From 303f1a232fe2092b88a8b4b54401f67eac747d77 Mon Sep 17 00:00:00 2001 From: cirroskais Date: Fri, 2 Aug 2024 05:05:10 -0400 Subject: [PATCH] labels for inputs, add api keys --- .../migration.sql | 16 ++++++++++ prisma/schema.prisma | 11 +++++++ src/lib/components/Header.svelte | 2 +- src/lib/components/ListedAPIKey.svelte | 16 ++++++++++ src/lib/config.ts | 11 +++++++ src/lib/server/database.ts | 23 ++++++++++++++ .../{links => documentation}/+page.svelte | 0 src/routes/(app)/settings/+page.server.ts | 7 +++++ src/routes/(app)/settings/+page.svelte | 30 ++++++++----------- src/routes/(app)/uploads/+page.server.ts | 2 -- src/routes/api/v1/keys/+server.ts | 17 +++++++++++ 11 files changed, 115 insertions(+), 20 deletions(-) create mode 100644 prisma/migrations/20240802082051_add_api_keys_to_schema/migration.sql create mode 100644 src/lib/components/ListedAPIKey.svelte rename src/routes/(app)/{links => documentation}/+page.svelte (100%) create mode 100644 src/routes/(app)/settings/+page.server.ts create mode 100644 src/routes/api/v1/keys/+server.ts diff --git a/prisma/migrations/20240802082051_add_api_keys_to_schema/migration.sql b/prisma/migrations/20240802082051_add_api_keys_to_schema/migration.sql new file mode 100644 index 0000000..d46c83e --- /dev/null +++ b/prisma/migrations/20240802082051_add_api_keys_to_schema/migration.sql @@ -0,0 +1,16 @@ +-- AlterTable +ALTER TABLE `User` ADD COLUMN `totp` VARCHAR(191) NULL; + +-- CreateTable +CREATE TABLE `APIKey` ( + `id` VARCHAR(191) NOT NULL, + `userId` INTEGER NOT NULL, + `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + `expiresAt` DATETIME(3) NOT NULL, + `permissions` INTEGER NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `APIKey` ADD CONSTRAINT `APIKey_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 19ef386..7775c27 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -12,6 +12,7 @@ model User { username String @unique email String @unique password String + totp String? role Role createdAt DateTime @default(now()) lastSeen DateTime @default(now()) @@ -20,6 +21,7 @@ model User { maxUploadMB Int @default(100) uploads Upload[] sessions Session[] + apiKeys APIKey[] } model Session { @@ -58,6 +60,15 @@ model Upload { uploaded DateTime @default(now()) } +model APIKey { + id String @id + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + expiresAt DateTime + permissions Int +} + enum Role { ADMINISTRATOR USER diff --git a/src/lib/components/Header.svelte b/src/lib/components/Header.svelte index 6e5bb15..6404869 100644 --- a/src/lib/components/Header.svelte +++ b/src/lib/components/Header.svelte @@ -20,7 +20,7 @@
Dashboard Uploads - Links + Documentation {#if $user?.role === 'ADMINISTRATOR'} Admin {/if} diff --git a/src/lib/components/ListedAPIKey.svelte b/src/lib/components/ListedAPIKey.svelte new file mode 100644 index 0000000..9d2b9fa --- /dev/null +++ b/src/lib/components/ListedAPIKey.svelte @@ -0,0 +1,16 @@ + + + + + {key.id} + + + + + diff --git a/src/lib/config.ts b/src/lib/config.ts index ae168ec..27c20c2 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -23,3 +23,14 @@ export const DOMAINS = [ ]; export const DEV_DOMAINS = ['cdn.dev.madhouselabs.net']; + +export const API_KEY_PERMISSIONS = { + CREATE_UPLOADS: 1 << 0, + READ_UPLOADS: 1 << 1, + UPDATE_UPLOADS: 1 << 2, + DELETE_UPLOADS: 1 << 3, + + READ_ACCOUNT: 1 << 4, + UPDATE_ACCOUNT_ACCOUNT_SETTINGS: 1 << 5, // allows for updating username & email. bad idea? probably. + UPDATE_ACCOUNT_EMBED_SETTINGS: 1 << 6 +}; diff --git a/src/lib/server/database.ts b/src/lib/server/database.ts index fdbdde6..063fa1e 100644 --- a/src/lib/server/database.ts +++ b/src/lib/server/database.ts @@ -138,3 +138,26 @@ export async function getSettings(id: number) { } }); } + +export async function getUserApiKeys(userId: number) { + if (!userId) return false; + + return await prisma.aPIKey.findMany({ + where: { + userId: userId + } + }); +} + +export async function createUserApiKey(userId: number, permissions: number, expiresAt: Date) { + if (!userId) return false; + + return await prisma.aPIKey.create({ + data: { + id: randomBytes(42).toString('base64url'), + userId, + permissions, + expiresAt + } + }); +} diff --git a/src/routes/(app)/links/+page.svelte b/src/routes/(app)/documentation/+page.svelte similarity index 100% rename from src/routes/(app)/links/+page.svelte rename to src/routes/(app)/documentation/+page.svelte diff --git a/src/routes/(app)/settings/+page.server.ts b/src/routes/(app)/settings/+page.server.ts new file mode 100644 index 0000000..f669c16 --- /dev/null +++ b/src/routes/(app)/settings/+page.server.ts @@ -0,0 +1,7 @@ +import { getUserApiKeys } from '$lib/server/database.js'; + +export async function load({ locals }) { + return { + keys: (await getUserApiKeys(locals.user.id)) || [] + }; +} diff --git a/src/routes/(app)/settings/+page.svelte b/src/routes/(app)/settings/+page.svelte index ba40b1e..7593b4a 100644 --- a/src/routes/(app)/settings/+page.svelte +++ b/src/routes/(app)/settings/+page.svelte @@ -1,6 +1,9 @@
@@ -26,7 +29,7 @@
- + - - - d8895a0c-daa5-4b6e-b66f-2494c039fe9e - - - - - + {#each data.keys as key} + + {/each}
@@ -165,8 +161,8 @@
-
- +
+

2FA

A One-Time Password will be required each time you login.

@@ -184,7 +180,7 @@
-
+
@@ -195,10 +191,10 @@
-
+
- - + +

Enable encryption for new uploads. (Client-side)

diff --git a/src/routes/(app)/uploads/+page.server.ts b/src/routes/(app)/uploads/+page.server.ts index 29d0e27..3883b88 100644 --- a/src/routes/(app)/uploads/+page.server.ts +++ b/src/routes/(app)/uploads/+page.server.ts @@ -3,13 +3,11 @@ import { error } from '@sveltejs/kit'; export async function load({ locals, url }) { if (!locals.user) return error(403, { status: 403, message: 'Forbidden' }); - if (+(url.searchParams.get('i') || 0) < 0) error(400, { status: 403, message: 'Invalid Index' }); const totalUploads = await prisma.upload.count({ where: { uploaderId: locals.user.id } }); if (!totalUploads) return { uploads: [], totalUploads: 0 }; - if (+(url.searchParams.get('i') || 0) >= Math.ceil(totalUploads / 15)) error(400, { status: 403, message: 'Invalid Index' }); diff --git a/src/routes/api/v1/keys/+server.ts b/src/routes/api/v1/keys/+server.ts new file mode 100644 index 0000000..94437c0 --- /dev/null +++ b/src/routes/api/v1/keys/+server.ts @@ -0,0 +1,17 @@ +import { API_KEY_PERMISSIONS } from '$lib/config.js'; +import { createUserApiKey, getUserApiKeys } from '$lib/server/database'; +import { json } from '@sveltejs/kit'; + +export async function GET({ locals }) { + return json(await getUserApiKeys(locals.user.id)); +} + +export async function POST({ locals }) { + return json( + await createUserApiKey( + locals.user.id, + API_KEY_PERMISSIONS.CREATE_UPLOADS | API_KEY_PERMISSIONS.READ_ACCOUNT, + new Date('2099') + ) + ); +}