7 Commits

Author SHA1 Message Date
66494c6760 Fix tests
All checks were successful
Publish / lints (push) Successful in 25s
/ Misc Linters (push) Successful in 28s
/ Build App (push) Successful in 1m3s
Publish / tests (push) Successful in 50s
Publish / Publishing (push) Successful in 1m7s
2024-08-16 16:39:44 +02:00
05320916b2 0.0.4
Some checks failed
/ Misc Linters (push) Successful in 24s
/ Build App (push) Failing after 29s
Publish / lints (push) Successful in 22s
Publish / tests (push) Failing after 27s
Publish / Publishing (push) Has been skipped
2024-08-16 16:37:24 +02:00
e6857f5b5d 0.0.2 2024-08-16 16:36:51 +02:00
5dba5471d1 Reject illegal names 2024-08-16 16:34:43 +02:00
f1ff9f1c38 Update flake.lock 2024-08-16 16:34:26 +02:00
7386a29ec5 flake.lock: Update
Some checks failed
/ Misc Linters (push) Successful in 25s
/ Build App (push) Failing after 24s
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/693bc46d169f5af9c992095736e82c3488bf7dbb' (2024-07-14)
  → 'github:nixos/nixpkgs/c3aa7b8938b17aebd2deecf7be0636000d62a2b9' (2024-08-14)
2024-08-16 15:53:10 +02:00
88b158b7b4 Lint before publish
All checks were successful
/ Misc Linters (push) Successful in 27s
/ Build App (push) Successful in 59s
2024-08-16 15:10:18 +02:00
7 changed files with 44 additions and 11 deletions

View File

@ -6,6 +6,9 @@ on:
- 'v*' - 'v*'
jobs: jobs:
lints:
uses: ./.gitea/workflows/lints.yml
tests: tests:
uses: ./.gitea/workflows/node.yml uses: ./.gitea/workflows/node.yml

6
flake.lock generated
View File

@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1720957393, "lastModified": 1723637854,
"narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=", "narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "693bc46d169f5af9c992095736e82c3488bf7dbb", "rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9",
"type": "github" "type": "github"
}, },
"original": { "original": {

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "fotochallenge", "name": "fotochallenge",
"version": "0.0.1", "version": "0.0.4",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "fotochallenge", "name": "fotochallenge",
"version": "0.0.1", "version": "0.0.4",
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/adapter-node": "^5.2.0", "@sveltejs/adapter-node": "^5.2.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "fotochallenge", "name": "fotochallenge",
"version": "0.0.1", "version": "0.0.4",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",

View File

@ -2,7 +2,19 @@ import safePath from '$lib';
import { describe, it, expect } from 'vitest'; import { describe, it, expect } from 'vitest';
describe('safe path', () => { describe('safe path', () => {
it('removes non alphanum from string', () => { it('reject names with ../', () => {
expect(safePath('../../!=-.,/abc123')).toBe('abc123'); expect(safePath('../foobar', './uploads')).toBe(false);
});
it('accept names with ./', () => {
expect(safePath('./foobar', './uploads')).toBe(true);
});
it('reject names with /', () => {
expect(safePath('foo/bar', './uploads')).toBe(false);
});
it('accept happy path', () => {
expect(safePath('foobar', './uploads')).toBe(true);
}); });
}); });

View File

@ -1,10 +1,23 @@
// place files you want to import through the `$lib` alias in this folder. // place files you want to import through the `$lib` alias in this folder.
import path from 'path';
const safePath = (input: string) => input.replace(/\W/g, ''); function safePath(name: string, basePath: string): boolean {
const fullPath = `${basePath}/${name}`;
const relative = path.relative(basePath, fullPath);
return (
!!relative &&
// does move out of `basePath`
!relative.startsWith('..') &&
// exactly one layer deep, e.g. no `./uplodas/foo/bar`
!relative.includes('/') &&
// result is not an absolute path
!path.isAbsolute(relative)
);
}
const defaultPath: string = './uploads'; const defaultPath: string = './uploads';
if (!('STORAGE_PATH' in process.env)) { if (!('STORAGE_PATH' in process.env)) {
console.log(`'STORAGE_PATH' environment variable is not set. Defaulting to ${defaultPath}`); console.warn(`'STORAGE_PATH' environment variable is not set. Defaulting to ${defaultPath}`);
} }
export const storagePath: string = process.env.STORAGE_PATH ?? defaultPath; export const storagePath: string = process.env.STORAGE_PATH ?? defaultPath;

View File

@ -34,7 +34,12 @@ export const actions = {
return fail(400, { field: 'name', name: formName, incorrect: true }); return fail(400, { field: 'name', name: formName, incorrect: true });
} }
const name = safePath(formName as string); const name = formName as string;
if (!safePath(name, storagePath)) {
return fail(400, { field: 'name', name: name, incorrect: true });
}
// const name = safePath(formName as string);
files.forEach(async (file) => { files.forEach(async (file) => {
const outPath = `${storagePath}/${name}`; const outPath = `${storagePath}/${name}`;