basic sharex stuff, api key auth

This commit is contained in:
cirroskais 2024-08-02 10:34:38 -04:00
parent 7745b07418
commit 4c3f4d719f
No known key found for this signature in database
GPG key ID: 5FC73EBF2678E33D
7 changed files with 107 additions and 36 deletions

View file

@ -1,40 +1,48 @@
import { error, redirect } from '@sveltejs/kit'; import { redirect } from '@sveltejs/kit';
import { getSession } from '$lib/server/database'; import { getSession, getUserApiKey } from '$lib/server/database';
import { COOKIE } from '$lib/config'; import { COOKIE } from '$lib/config';
const PUBLIC_RESOURCES = [
'/',
'/api',
'/api/auth/register',
'/api/auth/login',
'/terms',
'/privacy'
];
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) { export async function handle({ event, resolve }) {
const { cookies, locals } = event; const { cookies, locals, request } = event;
const session = await getSession(cookies.get(COOKIE) || '');
if (session && session.user) { let cookie = cookies.get(COOKIE);
locals.user = { let bearer = request.headers.get('Authorization');
id: session.user.id, if (bearer) bearer = bearer.replace('Bearer ', '');
username: session.user.username,
email: session.user.email, if (cookie) {
maxUploadMB: session.user.maxUploadMB, const session = await getSession(cookie);
role: session.user.role if (session && session.user) {
}; locals.user = {
} else { id: session.user.id,
if (event.route.id) { username: session.user.username,
if (event.route.id.includes('(app)')) return redirect(303, '/'); email: session.user.email,
maxUploadMB: session.user.maxUploadMB,
role: session.user.role
};
} }
} }
if (bearer && !locals.user) {
const apiKey = await getUserApiKey(bearer);
if (apiKey && apiKey.user) {
locals.user = {
id: apiKey.user.id,
username: apiKey.user.username,
email: apiKey.user.email,
maxUploadMB: apiKey.user.maxUploadMB,
role: apiKey.user.role
};
}
}
if (!locals.user && event.route.id) {
if (event.route.id.includes('(app)')) return redirect(303, '/');
}
return await resolve(event); return await resolve(event);
} }
/** @type {import('@sveltejs/kit').HandleServerError} */ export async function handleError({ error, status, message }) {
export async function handleError({ error, event, status, message }) {
console.log(error); console.log(error);
return { return {

View file

@ -60,7 +60,7 @@
type={'email'} type={'email'}
name={'email'} name={'email'}
id={'email'} id={'email'}
placeholder={'user@example.com'} placeholder={'john@doefamily.com'}
bind:value={email} bind:value={email}
required={true} required={true}
> >

View file

@ -80,7 +80,7 @@
type={'email'} type={'email'}
name={'email'} name={'email'}
id={'email'} id={'email'}
placeholder={'user@example.com'} placeholder={'jane@doefamily.com'}
bind:value={email} bind:value={email}
required={true} required={true}
> >

View file

@ -11,8 +11,8 @@
--> -->
{#if type === 'username'} {#if type === 'username'}
<div class="flex p-2 space-x-1 rounded-lg shadow-md bg-crust"> <div class="flex p-2 space-x-2 rounded-lg shadow-md bg-crust">
<div class="py-0.5 pr-1 border-r-2 border-overlay2"> <div class="py-0.5 pr-2 border-r-2 border-overlay0">
<slot /> <slot />
</div> </div>
<input <input
@ -26,8 +26,8 @@
/> />
</div> </div>
{:else if type === 'email'} {:else if type === 'email'}
<div class="flex p-2 space-x-1 rounded-lg shadow-md bg-crust"> <div class="flex p-2 space-x-2 rounded-lg shadow-md bg-crust">
<div class="py-0.5 pr-1 border-r-2 border-overlay2"> <div class="py-0.5 pr-2 border-r-2 border-overlay0">
<slot /> <slot />
</div> </div>
<input <input
@ -41,8 +41,8 @@
/> />
</div> </div>
{:else if type === 'password'} {:else if type === 'password'}
<div class="flex p-2 space-x-1 rounded-lg shadow-md bg-crust"> <div class="flex p-2 space-x-2 rounded-lg shadow-md bg-crust">
<div class="py-0.5 pr-1 border-r-2 border-overlay2"> <div class="py-0.5 pr-2 border-r-2 border-overlay0">
<slot /> <slot />
</div> </div>
<input <input

View file

@ -172,3 +172,28 @@ export async function deleteUserApiKey(userId: number, id: string) {
} }
}); });
} }
export async function getUserApiKey(id: string) {
if (!id) return false;
return await prisma.aPIKey.findFirst({
where: {
id
},
include: {
user: {
select: {
id: true,
username: true,
email: true,
password: true,
role: true,
createdAt: true,
lastSeen: true,
maxUploadMB: true,
settings: true
}
}
}
});
}

View file

@ -16,7 +16,7 @@ const ApiKeyLimits = {
setInterval(function resetMinute() {}, 1000 * 60); setInterval(function resetMinute() {}, 1000 * 60);
setInterval(function resetHour() {}, 1000 * 60 * 60); setInterval(function resetHour() {}, 1000 * 60 * 60);
function hash(input) { function hash(input: string) {
createHash('sha256').update(input).digest('hex'); createHash('sha256').update(input).digest('hex');
} }

View file

@ -0,0 +1,38 @@
<script lang="ts">
import { page } from '$app/stores';
import Button from '$lib/components/Inputs/Button.svelte';
import { API_KEY_PERMISSIONS } from '$lib/config';
import { get } from 'svelte/store';
let awesome = '';
async function click() {
const response = await fetch('/api/v1/keys');
const body = (await response.json()) as { id: string; permissions: number }[];
const key = body.find((key) => key.permissions & API_KEY_PERMISSIONS.CREATE_UPLOADS);
if (!key) return (awesome = 'What the fuck did i tell you');
awesome = `{
"Version": "14.0.0",
"Name": "cirros file uploader",
"DestinationType": "ImageUploader, FileUploader",
"RequestMethod": "POST",
"RequestURL": "${get(page).url.origin}/api/v1/upload",
"Headers": {
"Authorization": "Bearer ${key.id}",
},
"Body": "MultipartFormData",
"FileFormName": "file",
"URL": "${get(page).url.origin}{response}",
}`;
}
</script>
<p>I'll make real documentation later but for now have this ShareX button</p>
<p class="mb-2">
MAKE SURE TO HAVE A VALID API KEY WITH THE CREATE_UPLOADS PERMISSION ( 1 &lt;&lt; 0 )
</p>
<Button {click}>The sharex button in question</Button>
<tt class="block mt-3 whitespace-pre-wrap">{awesome}</tt>