63 lines
2 KiB
TypeScript
63 lines
2 KiB
TypeScript
import type { Actions } from './$types';
|
|
import { COUCHDB_DB_NAME, S3_BUCKET_NAME } from '$env/static/private';
|
|
import { fail, redirect } from '@sveltejs/kit';
|
|
import { fileTreeSchema } from '$lib/types-zod';
|
|
import { get_blobs } from '$lib/utils';
|
|
import type { Modpack } from '$lib/types';
|
|
import { nanoid } from 'nanoid';
|
|
import { minioClient, nano } from '$lib/server/clients';
|
|
|
|
export const actions: Actions = {
|
|
default: async (event) => {
|
|
const session = await event.locals.getSession();
|
|
if (!session?.user) throw redirect(303, '/auth/signin');
|
|
const data = await event.request.formData();
|
|
const payload = data.get('payload');
|
|
const title = data.get('title');
|
|
if (typeof payload != 'string') throw fail(400);
|
|
if (typeof title != 'string') throw fail(400);
|
|
const payload_decoded = fileTreeSchema.safeParse(JSON.parse(payload));
|
|
if (!payload_decoded.success) {
|
|
throw fail(400);
|
|
}
|
|
const blobs = get_blobs(payload_decoded.data);
|
|
for (const blob of blobs) {
|
|
const file = data.get(blob.sha512);
|
|
if (typeof file != 'object' || !file) throw fail(400);
|
|
if (file.size > 8 * 1024 * 1024) throw fail(400);
|
|
const buf = await file.arrayBuffer();
|
|
const hashBuffer = await crypto.subtle.digest('SHA-512', buf);
|
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
const hash = hashArray
|
|
.map((b) => b.toString(16).padStart(2, '0'))
|
|
.join('')
|
|
.toLowerCase();
|
|
if (hash != blob.sha512) throw fail(400);
|
|
let exists = false;
|
|
try {
|
|
await minioClient.statObject(S3_BUCKET_NAME, blob.sha512);
|
|
exists = true;
|
|
} catch {
|
|
// failed to stat. file doesn't exist
|
|
}
|
|
if (!exists) {
|
|
await minioClient.putObject(S3_BUCKET_NAME, hash, Buffer.from(buf));
|
|
}
|
|
}
|
|
const document: Modpack = {
|
|
type: 'modpack',
|
|
_id: nanoid(),
|
|
name: title,
|
|
author: session.user.email ?? 'unknown@nodomain',
|
|
revisions: [
|
|
{
|
|
id: nanoid(),
|
|
type: 'base',
|
|
tree: payload_decoded.data,
|
|
message: 'initial revision'
|
|
}
|
|
]
|
|
};
|
|
await nano.use(COUCHDB_DB_NAME).insert(document);
|
|
}
|
|
};
|