basic sharex stuff, api key auth
This commit is contained in:
parent
7745b07418
commit
4c3f4d719f
7 changed files with 107 additions and 36 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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}
|
||||||
>
|
>
|
||||||
|
|
|
@ -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}
|
||||||
>
|
>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 << 0 )
|
||||||
|
</p>
|
||||||
|
<Button {click}>The sharex button in question</Button>
|
||||||
|
|
||||||
|
<tt class="block mt-3 whitespace-pre-wrap">{awesome}</tt>
|
Loading…
Reference in a new issue