Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
bcf7802
feat: nginx + torrential basics & services system
DecDuck Dec 1, 2025
0bd0a4a
fix: lint + i18n
DecDuck Dec 1, 2025
fe6aff0
fix: update torrential to remove openssl
DecDuck Dec 1, 2025
45f3216
feat: add torrential to Docker build
DecDuck Dec 1, 2025
11a00fb
feat: move to self hosted runner
DecDuck Dec 1, 2025
85e3e66
fix: move off self-hosted runner
DecDuck Dec 1, 2025
b83d6f6
fix: update nginx.conf
DecDuck Dec 2, 2025
b76d60d
feat: torrential cache invalidation
DecDuck Dec 3, 2025
f1e04e4
fix: update torrential for cache invalidation
DecDuck Dec 4, 2025
71af776
feat: integrity check task
DecDuck Dec 5, 2025
ee889a7
fix: lint
DecDuck Dec 5, 2025
fc2f9a6
feat: move to version ids
DecDuck Dec 14, 2025
bfdbc7f
fix: client fixes and client-side checks
DecDuck Dec 18, 2025
ebd26bc
feat: new depot apis and version id fixes
DecDuck Dec 19, 2025
71990f6
feat: update torrential
DecDuck Dec 19, 2025
52da9c3
feat: droplet bump and remove unsafe update functions
DecDuck Dec 20, 2025
54dde50
fix: lint
DecDuck Dec 20, 2025
1c06081
feat: v4 featureset: emulators, multi-launch commands
DecDuck Dec 20, 2025
5d2ea28
fix: lint
DecDuck Dec 20, 2025
72a5226
fix: mobile ui for game editor
DecDuck Dec 20, 2025
2a8386e
feat: launch options
DecDuck Dec 21, 2025
7762665
fix: lint
DecDuck Dec 21, 2025
e31250c
fix: remove axios, use $fetch
DecDuck Dec 30, 2025
794d1f4
feat: metadata and task api improvements
DecDuck Dec 30, 2025
13cce1f
feat: task actions
DecDuck Dec 30, 2025
a8e44e6
fix: slight styling issue
DecDuck Dec 30, 2025
a94c399
feat: fix style and lints
DecDuck Dec 30, 2025
4dbf707
feat: totp backend routes
DecDuck Dec 30, 2025
e198c8a
feat: oidc groups
DecDuck Dec 30, 2025
066e689
fix: update drop-base
DecDuck Dec 31, 2025
902d63c
feat: creation of passkeys & totp
DecDuck Dec 31, 2025
0671611
feat: totp signin
DecDuck Dec 31, 2025
a7ddd5b
feat: webauthn mfa/signin
DecDuck Jan 4, 2026
2b34f26
feat: launch selecting ui
DecDuck Jan 4, 2026
31e545f
fix: manually running tasks
DecDuck Jan 4, 2026
ea33465
feat: update add company game modal to use new SelectorGame
DecDuck Jan 4, 2026
b670b2f
feat: executor selector
DecDuck Jan 4, 2026
ae11db1
fix(docker): update rust to rust nightly for torrential build (#305)
AdenMGB Jan 5, 2026
0fefad9
feat: new version ui
DecDuck Jan 5, 2026
a3b408e
feat: move package lookup to build time to allow for deno dev
DecDuck Jan 5, 2026
c9e2108
fix: lint
DecDuck Jan 5, 2026
dce5196
feat: localisation cleanup
DecDuck Jan 6, 2026
007d3f8
feat: apply localisation cleanup
DecDuck Jan 6, 2026
6e33515
feat: potential i18n refactor logic
DecDuck Jan 6, 2026
03b1e39
Merge branch 'develop' into torrential
DecDuck Jan 12, 2026
72c1a02
feat: remove args from commands
DecDuck Jan 12, 2026
df94ec0
fix: lint
DecDuck Jan 13, 2026
e11d1c6
fix: lockfile
DecDuck Jan 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:

jobs:
web:
name: Push website Docker image to registry
name: Build Docker image
runs-on: ubuntu-latest
permissions:
packages: write
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "drop-base"]
path = drop-base
url = https://github.com/Drop-OSS/drop-base.git
[submodule "torrential"]
path = torrential
url = https://github.com/Drop-OSS/torrential.git
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
drop-base/
# file is fully managed by pnpm, no reason to break it
pnpm-lock.yaml

torrential/
5 changes: 5 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"jsonRecursiveSort": true,
"jsonSortOrder": "{\"/.*/\": \"lexical\"}",
"plugins": ["prettier-plugin-sort-json"]
}
46 changes: 24 additions & 22 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
{
"spellchecker.ignoreWordsList": ["mTLS", "Wireguard"],
"sqltools.connections": [
{
"previewLimit": 50,
"server": "localhost",
"port": 5432,
"driver": "PostgreSQL",
"name": "drop",
"database": "drop",
"username": "drop",
"password": "drop"
}
],
// allow autocomplete for ArkType expressions like "string | num"
"editor.quickSuggestions": {
"strings": "on"
},
// prioritize ArkType's "type" for autoimports
"typescript.preferences.autoImportSpecifierExcludeRegexes": ["^(node:)?os$"],
// i18n Ally settings
"i18n-ally.sortKeys": true,
"i18n-ally.keepFulfilled": true,
"i18n-ally.extract.autoDetect": true,
"i18n-ally.localesPaths": ["i18n", "i18n/locales"],
"i18n-ally.keystyle": "nested",
"i18n-ally.extract.ignored": [
"string >= 14",
"string.alphanumeric >= 5",
"/api/v1/admin/import/version/preload?id=${encodeURIComponent(\n gameId,\n )}&version=${encodeURIComponent(version)}"
],
"i18n-ally.extract.ignoredByFiles": {
"pages/admin/library/sources/index.vue": ["Filesystem"],
"components/NewsArticleCreateButton.vue": ["[", "`", "Enter"],
"pages/admin/library/sources/index.vue": ["Filesystem"],
"server/api/v1/auth/signin/simple.post.ts": ["boolean | undefined"]
}
},
"i18n-ally.keepFulfilled": true,
"i18n-ally.keystyle": "nested",
"i18n-ally.localesPaths": ["i18n", "i18n/locales"],
// i18n Ally settings
"i18n-ally.sortKeys": true,
"prisma.pinToPrisma6": true,
"spellchecker.ignoreWordsList": ["mTLS", "Wireguard"],
"sqltools.connections": [
{
"database": "drop",
"driver": "PostgreSQL",
"name": "drop",
"password": "drop",
"port": 5432,
"previewLimit": 50,
"server": "localhost",
"username": "drop"
}
],
"typescript.experimental.useTsgo": true,
// prioritize ArkType's "type" for autoimports
"typescript.preferences.autoImportSpecifierExcludeRegexes": ["^(node:)?os$"]
}
33 changes: 22 additions & 11 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,54 @@ ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
WORKDIR /app

# so corepack knows pnpm's version
## so corepack knows pnpm's version
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
# prevent prompt to download
## prevent prompt to download
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0
# setup for offline
## setup for offline
RUN corepack pack
# don't call out to network anymore
## don't call out to network anymore
ENV COREPACK_ENABLE_NETWORK=0

### Unified deps builder
### INSTALL DEPS ONCE
FROM base AS deps
RUN pnpm install --frozen-lockfile --ignore-scripts

### Build for app
### BUILD TORRENTIAL
FROM rustlang/rust:nightly-alpine AS torrential-build
RUN apk add musl-dev
WORKDIR /build
COPY torrential .
RUN cargo build --release

### BUILD APP
FROM base AS build-system

ENV NODE_ENV=production
ENV NUXT_TELEMETRY_DISABLED=1

# add git so drop can determine its git ref at build
## add git so drop can determine its git ref at build
RUN apk add --no-cache git

# copy deps and rest of project files
## copy deps and rest of project files
COPY --from=deps /app/node_modules ./node_modules
COPY . .

ARG BUILD_DROP_VERSION
ARG BUILD_GIT_REF

# build
## build
RUN pnpm run postinstall && pnpm run build

### create run environment for Drop

# create run environment for Drop
FROM base AS run-system

ENV NODE_ENV=production
ENV NUXT_TELEMETRY_DISABLED=1

# RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn add --network-timeout 1000000 --no-lockfile --ignore-scripts prisma@6.11.1
RUN apk add --no-cache pnpm 7zip
RUN apk add --no-cache pnpm 7zip nginx
RUN pnpm install prisma@6.11.1
# init prisma to download all required files
RUN pnpm prisma init
Expand All @@ -54,8 +62,11 @@ COPY --from=build-system /app/prisma.config.ts ./
COPY --from=build-system /app/.output ./app
COPY --from=build-system /app/prisma ./prisma
COPY --from=build-system /app/build ./startup
COPY --from=build-system /app/build/nginx.conf /nginx.conf
COPY --from=torrential-build /build/target/release/torrential /usr/bin/

ENV LIBRARY="/library"
ENV DATA="/data"
ENV NGINX_CONFIG="/nginx.conf"

CMD ["sh", "/app/startup/launch.sh"]
15 changes: 2 additions & 13 deletions app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ await updateUser();

const user = useUser();
const apiDetails = await $dropFetch("/api/v1");
const clientMode = isClientRequest();

const showExternalUrlWarning = ref(false);
function checkExternalUrl() {
if (!import.meta.client) return;
if (!import.meta.client || clientMode) return;
const realOrigin = window.location.origin.trim();
const chosenOrigin = apiDetails.external.trim();
const ignore = window.localStorage.getItem("ignoreExternalUrl");
Expand All @@ -51,15 +52,3 @@ if (user.value?.admin) {
});
}
</script>

<style scoped>
/* You can customise the default animation here. */

::view-transition-old(root) {
animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out;
}

::view-transition-new(root) {
animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in;
}
</style>
41 changes: 41 additions & 0 deletions build/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
worker_processes 1;

events {
worker_connections 1024;
}

pid nginx.pid;
error_log stderr;
daemon off;

http {
default_type application/octet-stream;

sendfile on;
server_tokens off;

access_log nginx_host.access.log;
client_body_temp_path client_body;
fastcgi_temp_path fastcgi_temp;
proxy_temp_path proxy_temp;
scgi_temp_path scgi_temp;
uwsgi_temp_path uwsgi_temp;

server {
listen 8080;
server_name localhost;

location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

location /api/v1/depot/ {
proxy_pass http://localhost:5000;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
}
}
29 changes: 18 additions & 11 deletions components/AccountSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,17 @@ import type { Component } from "vue";
const notifications = useNotifications();
const { t } = useI18n();

const navigation: (NavigationItem & { icon: Component; count?: number })[] = [
{ label: t("home"), route: "/account", icon: HomeIcon, prefix: "/account" },
const navigation: Ref<
(NavigationItem & { icon: Component; count?: number })[]
> = computed(() => [
{
label: t("security"),
label: t("account.home.title"),
route: "/account",
icon: HomeIcon,
prefix: "/account",
},
{
label: t("account.security.title"),
route: "/account/security",
prefix: "/account/security",
icon: LockClosedIcon,
Expand All @@ -67,26 +74,26 @@ const navigation: (NavigationItem & { icon: Component; count?: number })[] = [
prefix: "/account/devices",
icon: DevicePhoneMobileIcon,
},
{
label: t("account.token.title"),
route: "/account/tokens",
prefix: "/account/tokens",
icon: CodeBracketIcon,
},
{
label: t("account.notifications.notifications"),
route: "/account/notifications",
prefix: "/account/notifications",
icon: BellIcon,
count: notifications.value.length,
},
{
label: t("account.token.title"),
route: "/account/tokens",
prefix: "/account/tokens",
icon: CodeBracketIcon,
},
{
label: t("account.settings"),
route: "/account/settings",
prefix: "/account/settings",
icon: WrenchScrewdriverIcon,
},
];
]);

const currentPageIndex = useCurrentNavigationIndex(navigation);
const currentPageIndex = useCurrentNavigationIndex(navigation.value);
</script>
57 changes: 48 additions & 9 deletions components/Auth/Simple.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
v-model="username"
name="username"
type="username"
autocomplete="username"
autocomplete="username webauthn"
required
class="block w-full rounded-md border-0 py-1.5 px-3 shadow-sm bg-zinc-950/20 text-zinc-300 ring-1 ring-inset ring-zinc-800 placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
/>
Expand Down Expand Up @@ -86,25 +86,60 @@

<script setup lang="ts">
import { XCircleIcon } from "@heroicons/vue/20/solid";
import type { UserModel } from "~/prisma/client/models";
import {
startAuthentication,
browserSupportsWebAuthn,
} from "@simplewebauthn/browser";
import type { FetchError } from "ofetch";

const username = ref("");
const password = ref("");
const rememberMe = ref(false);
const loading = ref(false);

async function passkeyAutofill() {
const silentWebauthnOptions = await $dropFetch("/api/v1/auth/passkey/start", {
method: "POST",
});

const result = await startAuthentication({
optionsJSON: silentWebauthnOptions,
useBrowserAutofill: true,
});

loading.value = true;

await $dropFetch("/api/v1/auth/passkey/finish", {
method: "POST",
body: result,
});

await completeSignin();
}

onMounted(async () => {
if (browserSupportsWebAuthn()) {
try {
await passkeyAutofill();
} catch (response) {
const message =
(response as FetchError).statusMessage || t("errors.unknown");
error.value = message;
} finally {
loading.value = false;
}
}
});

const error = ref<string | undefined>();

const route = useRoute();
const router = useRouter();
const route = useRoute();
const { t } = useI18n();

function signin_wrapper() {
loading.value = true;
signin()
.then(() => {
router.push(route.query.redirect?.toString() ?? "/");
})
.catch((response) => {
const message = response.statusMessage || t("errors.unknown");
error.value = message;
Expand All @@ -115,15 +150,19 @@ function signin_wrapper() {
}

async function signin() {
await $dropFetch("/api/v1/auth/signin/simple", {
const { result } = await $dropFetch("/api/v1/auth/signin/simple", {
method: "POST",
body: {
username: username.value,
password: password.value,
rememberMe: rememberMe.value,
},
});
const user = useUser();
user.value = await $dropFetch<UserModel | null>("/api/v1/user");
if (result == "2fa") {
router.push({ query: route.query, path: "/auth/mfa" });
return;
}

await completeSignin();
}
</script>
Loading
Loading