From 15790e85ad43a895b823a9784aae054872938ba3 Mon Sep 17 00:00:00 2001 From: Arca Ege Cengiz Date: Thu, 18 Dec 2025 22:54:00 +0000 Subject: [PATCH 1/5] Add two devlog requirement --- src/routes/dashboard/projects/[id]/ship/+page.server.ts | 5 +++++ src/routes/dashboard/projects/[id]/ship/+page.svelte | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/routes/dashboard/projects/[id]/ship/+page.server.ts b/src/routes/dashboard/projects/[id]/ship/+page.server.ts index 6d61441..b217bd6 100644 --- a/src/routes/dashboard/projects/[id]/ship/+page.server.ts +++ b/src/routes/dashboard/projects/[id]/ship/+page.server.ts @@ -234,6 +234,11 @@ export const actions = { return error(400, { message: 'minimum 2h needed to ship' }); } + // Make sure it has at least 2 devlogs + if (queriedProject.devlogCount < 2) { + return error(400, { message: 'minimum 2 journal logs required to ship' }); + } + if (queriedProject.description == '') { return error(400, { message: 'project must have a description' }); } diff --git a/src/routes/dashboard/projects/[id]/ship/+page.svelte b/src/routes/dashboard/projects/[id]/ship/+page.svelte index 61d3fa6..71c1e30 100644 --- a/src/routes/dashboard/projects/[id]/ship/+page.svelte +++ b/src/routes/dashboard/projects/[id]/ship/+page.svelte @@ -156,6 +156,9 @@ = 120} >At least 120 minutes spent + = 2} + >At least 2 journal logs Project has a description @@ -191,6 +194,7 @@ class="button sm orange" disabled={formPending || data.project.timeSpent < 120 || + data.project.devlogCount < 2 || data.project.description == '' || !printablesUrl || !hasEditorFile || From 778482a240c9d37911a9cb9af9f29835d1f894d1 Mon Sep 17 00:00:00 2001 From: Arca Ege Cengiz Date: Thu, 18 Dec 2025 22:58:39 +0000 Subject: [PATCH 2/5] Hide model section if it doesn't exist (on review pages) --- .../dashboard/admin/review/[id]/+page.svelte | 36 ++++++++++--------- .../admin/ysws-review/[id]/+page.svelte | 36 ++++++++++--------- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/routes/dashboard/admin/review/[id]/+page.svelte b/src/routes/dashboard/admin/review/[id]/+page.svelte index f4b6fbb..065311e 100644 --- a/src/routes/dashboard/admin/review/[id]/+page.svelte +++ b/src/routes/dashboard/admin/review/[id]/+page.svelte @@ -85,24 +85,26 @@ -
-

3D model

- - - -
+ {#if data.project.project.modelFile} +
+

3D model

+ + + +
-
- -
+
+ +
+ {/if}

Review

diff --git a/src/routes/dashboard/admin/ysws-review/[id]/+page.svelte b/src/routes/dashboard/admin/ysws-review/[id]/+page.svelte index 17edfe1..d489fc4 100644 --- a/src/routes/dashboard/admin/ysws-review/[id]/+page.svelte +++ b/src/routes/dashboard/admin/ysws-review/[id]/+page.svelte @@ -85,24 +85,26 @@
-
-

3D model

- - - -
+ {#if data.project.project.modelFile} +
+

3D model

+ + + +
-
- -
+
+ +
+ {/if}

YSWS Review (don't use yet if you're not Arca)

From 2fe78e273f30ccd7665622778fa393dc31c3b554 Mon Sep 17 00:00:00 2001 From: Arca Ege Cengiz Date: Thu, 18 Dec 2025 23:15:48 +0000 Subject: [PATCH 3/5] Fix possible javascript injection --- package-lock.json | 7 +++++++ package.json | 1 + src/routes/dashboard/projects/[id]/ship/+page.server.ts | 9 +++++---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 77e53fb..f6c020c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.1", "dependencies": { "@aws-sdk/client-s3": "^3.940.0", + "@braintree/sanitize-url": "^7.1.1", "@lucide/svelte": "^0.547.0", "@prgm/sveltekit-progress-bar": "^3.0.2", "@sentry/sveltekit": "^10.29.0", @@ -1258,6 +1259,12 @@ "node": ">=6.9.0" } }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.1.tgz", + "integrity": "sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==", + "license": "MIT" + }, "node_modules/@cloudflare/kv-asset-handler": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.0.tgz", diff --git a/package.json b/package.json index 8b008d1..7b7a994 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.940.0", + "@braintree/sanitize-url": "^7.1.1", "@lucide/svelte": "^0.547.0", "@prgm/sveltekit-progress-bar": "^3.0.2", "@sentry/sveltekit": "^10.29.0", diff --git a/src/routes/dashboard/projects/[id]/ship/+page.server.ts b/src/routes/dashboard/projects/[id]/ship/+page.server.ts index b217bd6..5e7d6db 100644 --- a/src/routes/dashboard/projects/[id]/ship/+page.server.ts +++ b/src/routes/dashboard/projects/[id]/ship/+page.server.ts @@ -11,6 +11,7 @@ import { env } from '$env/dynamic/private'; import { PutObjectCommand } from '@aws-sdk/client-s3'; import { S3 } from '$lib/server/s3'; import { ship } from '$lib/server/db/schema.js'; +import { sanitizeUrl } from '@braintree/sanitize-url'; export async function load({ params, locals }) { const id: number = parseInt(params.id); @@ -269,9 +270,9 @@ export const actions = { .update(project) .set({ status: 'submitted', - url: printablesUrl.toString(), + url: sanitizeUrl(printablesUrl.toString()), editorFileType: editorUrlExists ? 'url' : 'upload', - editorUrl: editorUrlExists ? editorUrl.toString() : undefined, + editorUrl: editorUrlExists ? sanitizeUrl(editorUrl.toString()) : undefined, uploadedFileUrl: editorFileExists ? editorFilePath : undefined, modelFile: modelPath @@ -287,10 +288,10 @@ export const actions = { await db.insert(ship).values({ userId: locals.user.id, projectId: queriedProject.id, - url: printablesUrl.toString(), + url: sanitizeUrl(printablesUrl.toString()), editorFileType: editorUrlExists ? 'url' : 'upload', - editorUrl: editorUrlExists ? editorUrl.toString() : undefined, + editorUrl: editorUrlExists ? sanitizeUrl(editorUrl.toString()) : undefined, uploadedFileUrl: editorFileExists ? editorFilePath : undefined, modelFile: modelPath From 4d77027c64500e452b3c1a4743608b5180cb094d Mon Sep 17 00:00:00 2001 From: Arca Ege Cengiz Date: Thu, 18 Dec 2025 23:28:50 +0000 Subject: [PATCH 4/5] Update to url sanitisation --- .../projects/[id]/ship/+page.server.ts | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/routes/dashboard/projects/[id]/ship/+page.server.ts b/src/routes/dashboard/projects/[id]/ship/+page.server.ts index 5e7d6db..8acd5e7 100644 --- a/src/routes/dashboard/projects/[id]/ship/+page.server.ts +++ b/src/routes/dashboard/projects/[id]/ship/+page.server.ts @@ -80,11 +80,14 @@ export const actions = { const editorFile = data.get('editor_file') as File; const modelFile = data.get('model_file') as File; + const printablesUrlString = + printablesUrl && printablesUrl.toString() ? sanitizeUrl(printablesUrl.toString()) : null; + const printablesUrlValid = - printablesUrl && - printablesUrl.toString() && - printablesUrl.toString().trim().length < 8000 && - isValidUrl(printablesUrl.toString().trim()); + printablesUrlString && + printablesUrlString.trim().length < 8000 && + isValidUrl(printablesUrlString.trim()) && + printablesUrlString !== 'about:blank'; if (!printablesUrlValid) { return fail(400, { @@ -92,7 +95,7 @@ export const actions = { }); } - const printablesUrlObj = new URL(printablesUrl.toString().trim()); + const printablesUrlObj = new URL(printablesUrlString.trim()); const pathMatch = printablesUrlObj.pathname.match(/\/model\/(\d+)/); const modelId = pathMatch ? pathMatch[1] : ''; @@ -155,12 +158,13 @@ export const actions = { // Editor URL const editorUrlExists = editorUrl && editorUrl.toString(); + + const editorUrlString = editorUrlExists ? sanitizeUrl(editorUrl.toString()) : null; + const editorUrlValid = - editorUrlExists && - editorUrl.toString().trim().length < 8000 && - isValidUrl(editorUrl.toString().trim()); + editorUrlString && editorUrlString.trim().length < 8000 && isValidUrl(editorUrlString.trim()); - if (editorUrlExists && !editorUrlValid) { + if (editorUrlExists && (!editorUrlValid || editorUrlString === 'about:blank')) { return fail(400, { invalid_editor_url: true }); @@ -270,9 +274,9 @@ export const actions = { .update(project) .set({ status: 'submitted', - url: sanitizeUrl(printablesUrl.toString()), + url: printablesUrlString, editorFileType: editorUrlExists ? 'url' : 'upload', - editorUrl: editorUrlExists ? sanitizeUrl(editorUrl.toString()) : undefined, + editorUrl: editorUrlExists ? editorUrlString : undefined, uploadedFileUrl: editorFileExists ? editorFilePath : undefined, modelFile: modelPath @@ -288,10 +292,10 @@ export const actions = { await db.insert(ship).values({ userId: locals.user.id, projectId: queriedProject.id, - url: sanitizeUrl(printablesUrl.toString()), + url: printablesUrlString, editorFileType: editorUrlExists ? 'url' : 'upload', - editorUrl: editorUrlExists ? sanitizeUrl(editorUrl.toString()) : undefined, + editorUrl: editorUrlExists ? editorUrlString : undefined, uploadedFileUrl: editorFileExists ? editorFilePath : undefined, modelFile: modelPath From 99ac9c90a540cfeee7ace2f687a8e35889584113 Mon Sep 17 00:00:00 2001 From: Arca Ege Cengiz Date: Thu, 18 Dec 2025 23:41:46 +0000 Subject: [PATCH 5/5] Shut up sentrybot --- src/routes/dashboard/projects/[id]/ship/+page.server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/dashboard/projects/[id]/ship/+page.server.ts b/src/routes/dashboard/projects/[id]/ship/+page.server.ts index 8acd5e7..3119c86 100644 --- a/src/routes/dashboard/projects/[id]/ship/+page.server.ts +++ b/src/routes/dashboard/projects/[id]/ship/+page.server.ts @@ -227,7 +227,7 @@ export const actions = { or(eq(project.status, 'building'), eq(project.status, 'rejected')) ) ) - .groupBy(project.id, project.description, project.url) + .groupBy(project.id, project.name, project.description, project.url) .limit(1); if (!queriedProject) {