✨ Cleand authentication-code up
This commit is contained in:
@@ -12,6 +12,9 @@ from fastapi.background import BackgroundTasks
|
|||||||
from fastapi.responses import JSONResponse, RedirectResponse, PlainTextResponse
|
from fastapi.responses import JSONResponse, RedirectResponse, PlainTextResponse
|
||||||
from fastapi.security import OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordRequestForm
|
||||||
import html
|
import html
|
||||||
|
|
||||||
|
from jose import jwt, JWTError
|
||||||
|
|
||||||
from classquiz import oauth
|
from classquiz import oauth
|
||||||
from classquiz.helpers.avatar import gzipped_user_avatar
|
from classquiz.helpers.avatar import gzipped_user_avatar
|
||||||
import base64
|
import base64
|
||||||
@@ -266,3 +269,46 @@ async def get_other_avatar(respo: Response, user_id: uuid.UUID):
|
|||||||
raise HTTPException(status_code=404, detail="User not found")
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
respo.headers.append("Content-Type", "image/svg+xml")
|
respo.headers.append("Content-Type", "image/svg+xml")
|
||||||
return gzip.decompress(base64.b64decode(user.avatar))
|
return gzip.decompress(base64.b64decode(user.avatar))
|
||||||
|
|
||||||
|
|
||||||
|
class InternalAuthData(BaseModel):
|
||||||
|
rememberme: str
|
||||||
|
jwt: str | None
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/auth/internal")
|
||||||
|
async def internal_auth(data: InternalAuthData, resp: Response):
|
||||||
|
try:
|
||||||
|
data.jwt = data.jwt.replace("Bearer ", "")
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
if data.jwt is not None:
|
||||||
|
try:
|
||||||
|
payload = jwt.decode(data.jwt, settings.secret_key, algorithms=["HS256"])
|
||||||
|
email: str = payload.get("sub")
|
||||||
|
if email is None:
|
||||||
|
resp.status_code = 401
|
||||||
|
return resp
|
||||||
|
except JWTError:
|
||||||
|
resp.status_code = 401
|
||||||
|
return resp
|
||||||
|
else:
|
||||||
|
return await rememberme_check(data.rememberme, resp)
|
||||||
|
|
||||||
|
|
||||||
|
class GetEmailFromJWT(BaseModel):
|
||||||
|
jwt: str
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/auth/internal/email")
|
||||||
|
async def get_email_from_jwt(data: GetEmailFromJWT):
|
||||||
|
try:
|
||||||
|
data.jwt = data.jwt.replace("Bearer ", "")
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
payload = jwt.decode(data.jwt, settings.secret_key, algorithms=["HS256"])
|
||||||
|
return payload.get("sub")
|
||||||
|
except JWTError as e:
|
||||||
|
print(e)
|
||||||
|
raise HTTPException(status_code=401)
|
||||||
|
|||||||
+1
-4
@@ -25,11 +25,8 @@ RUN corepack enable && corepack prepare pnpm@7.5.0 --activate && pnpm i
|
|||||||
# copy the generated modules and all other files to the container
|
# copy the generated modules and all other files to the container
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN apt update && \
|
|
||||||
apt install -y redis-server
|
|
||||||
|
|
||||||
# build the application
|
# build the application
|
||||||
RUN nohup bash -c "redis-server &" && sleep 4 && pnpm run build
|
RUN pnpm run build
|
||||||
|
|
||||||
### Serve Step
|
### Serve Step
|
||||||
# pull the Node.js Docker image
|
# pull the Node.js Docker image
|
||||||
|
|||||||
@@ -48,7 +48,6 @@
|
|||||||
"felte": "^1.2.2",
|
"felte": "^1.2.2",
|
||||||
"highlight.js": "^11.5.1",
|
"highlight.js": "^11.5.1",
|
||||||
"i18next-browser-languagedetector": "^6.1.4",
|
"i18next-browser-languagedetector": "^6.1.4",
|
||||||
"ioredis": "^5.1.0",
|
|
||||||
"js-cookie": "^3.0.1",
|
"js-cookie": "^3.0.1",
|
||||||
"luxon": "^2.4.0",
|
"luxon": "^2.4.0",
|
||||||
"mapbox-gl": "^2.9.1",
|
"mapbox-gl": "^2.9.1",
|
||||||
|
|||||||
Generated
-84
@@ -36,7 +36,6 @@ specifiers:
|
|||||||
highlight.js: ^11.5.1
|
highlight.js: ^11.5.1
|
||||||
i18next: ^21.8.13
|
i18next: ^21.8.13
|
||||||
i18next-browser-languagedetector: ^6.1.4
|
i18next-browser-languagedetector: ^6.1.4
|
||||||
ioredis: ^5.1.0
|
|
||||||
js-cookie: ^3.0.1
|
js-cookie: ^3.0.1
|
||||||
luxon: ^2.4.0
|
luxon: ^2.4.0
|
||||||
mapbox-gl: ^2.9.1
|
mapbox-gl: ^2.9.1
|
||||||
@@ -101,7 +100,6 @@ devDependencies:
|
|||||||
felte: 1.2.2_svelte@3.49.0
|
felte: 1.2.2_svelte@3.49.0
|
||||||
highlight.js: 11.6.0
|
highlight.js: 11.6.0
|
||||||
i18next-browser-languagedetector: 6.1.4
|
i18next-browser-languagedetector: 6.1.4
|
||||||
ioredis: 5.2.1
|
|
||||||
js-cookie: 3.0.1
|
js-cookie: 3.0.1
|
||||||
luxon: 2.5.0
|
luxon: 2.5.0
|
||||||
mapbox-gl: 2.9.2
|
mapbox-gl: 2.9.2
|
||||||
@@ -251,13 +249,6 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@ioredis/commands/1.2.0:
|
|
||||||
resolution:
|
|
||||||
{
|
|
||||||
integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==
|
|
||||||
}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@jridgewell/resolve-uri/3.1.0:
|
/@jridgewell/resolve-uri/3.1.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -1439,14 +1430,6 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/cluster-key-slot/1.1.0:
|
|
||||||
resolution:
|
|
||||||
{
|
|
||||||
integrity: sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==
|
|
||||||
}
|
|
||||||
engines: { node: '>=0.10.0' }
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/color-convert/2.0.1:
|
/color-convert/2.0.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -1724,14 +1707,6 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/denque/2.1.0:
|
|
||||||
resolution:
|
|
||||||
{
|
|
||||||
integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==
|
|
||||||
}
|
|
||||||
engines: { node: '>=0.10' }
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/detect-indent/6.1.0:
|
/detect-indent/6.1.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -2797,26 +2772,6 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/ioredis/5.2.1:
|
|
||||||
resolution:
|
|
||||||
{
|
|
||||||
integrity: sha512-+rgPUIawiT+L3am9FbUcwjI7R7KtLDUSJNYWF82NZmlUXCZELws7iJkVDuECQoNUHqZTf/EGn3uw9IA+PlBiyg==
|
|
||||||
}
|
|
||||||
engines: { node: '>=12.22.0' }
|
|
||||||
dependencies:
|
|
||||||
'@ioredis/commands': 1.2.0
|
|
||||||
cluster-key-slot: 1.1.0
|
|
||||||
debug: 4.3.4
|
|
||||||
denque: 2.1.0
|
|
||||||
lodash.defaults: 4.2.0
|
|
||||||
lodash.isarguments: 3.1.0
|
|
||||||
redis-errors: 1.2.0
|
|
||||||
redis-parser: 3.0.0
|
|
||||||
standard-as-callback: 2.1.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/is-binary-path/2.1.0:
|
/is-binary-path/2.1.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -2979,20 +2934,6 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/lodash.defaults/4.2.0:
|
|
||||||
resolution:
|
|
||||||
{
|
|
||||||
integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==
|
|
||||||
}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/lodash.isarguments/3.1.0:
|
|
||||||
resolution:
|
|
||||||
{
|
|
||||||
integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==
|
|
||||||
}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/lodash.isplainobject/4.0.6:
|
/lodash.isplainobject/4.0.6:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -4088,24 +4029,6 @@ packages:
|
|||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/redis-errors/1.2.0:
|
|
||||||
resolution:
|
|
||||||
{
|
|
||||||
integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==
|
|
||||||
}
|
|
||||||
engines: { node: '>=4' }
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/redis-parser/3.0.0:
|
|
||||||
resolution:
|
|
||||||
{
|
|
||||||
integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==
|
|
||||||
}
|
|
||||||
engines: { node: '>=4' }
|
|
||||||
dependencies:
|
|
||||||
redis-errors: 1.2.0
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/regenerator-runtime/0.13.9:
|
/regenerator-runtime/0.13.9:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -4418,13 +4341,6 @@ packages:
|
|||||||
deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility'
|
deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility'
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/standard-as-callback/2.1.0:
|
|
||||||
resolution:
|
|
||||||
{
|
|
||||||
integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==
|
|
||||||
}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/string-width/4.2.3:
|
/string-width/4.2.3:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+18
@@ -3,3 +3,21 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
/// <reference types="@sveltejs/kit" />
|
||||||
|
|
||||||
|
// See https://kit.svelte.dev/docs/types#app
|
||||||
|
// for information about these interfaces
|
||||||
|
// and what to do when importing types
|
||||||
|
declare namespace App {
|
||||||
|
interface Locals {
|
||||||
|
email: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// interface Platform {}
|
||||||
|
interface Session {
|
||||||
|
authenticated: boolean;
|
||||||
|
email: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// interface Stuff {}
|
||||||
|
}
|
||||||
|
|||||||
+41
-44
@@ -5,56 +5,53 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as cookie from 'cookie';
|
import * as cookie from 'cookie';
|
||||||
import Redis from 'ioredis';
|
import type { Handle, GetSession } from '@sveltejs/kit';
|
||||||
|
|
||||||
const redis = new Redis(process.env.REDIS_URL);
|
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Handle} */
|
/** @type {import('@sveltejs/kit').Handle} */
|
||||||
export async function handle({ event, resolve }) {
|
export const handle: Handle = async ({ event, resolve }) => {
|
||||||
const cookies = cookie.parse(event.request.headers.get('cookie') || '');
|
const cookies = cookie.parse(event.request.headers.get('cookie') || '');
|
||||||
const regex_token = /^Bearer (.*)$/gm.exec(cookies.access_token);
|
const jwt = /^Bearer (.*)$/gm.exec(cookies.access_token);
|
||||||
if (regex_token === null) {
|
const rememberme_token = cookies.rememberme_token;
|
||||||
event.locals.token = null;
|
if (rememberme_token) {
|
||||||
} else {
|
const res = await fetch(`${process.env.API_URL}/api/v1/users/auth/internal`, {
|
||||||
event.locals.token = regex_token[1];
|
method: 'POST',
|
||||||
}
|
|
||||||
event.locals.rememberme = cookies.rememberme_token;
|
|
||||||
|
|
||||||
return await resolve(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').GetSession} */
|
|
||||||
export async function getSession(event) {
|
|
||||||
const redis_res = await redis.get(event.locals.token);
|
|
||||||
let user_email: string;
|
|
||||||
if (redis_res === null) {
|
|
||||||
const res = await fetch(`${process.env.API_URL}/api/v1/users/check`, {
|
|
||||||
headers: {
|
headers: {
|
||||||
Cookie: `access_token=Bearer ${event.locals.token}` // skipcq: JS-0378
|
'Content-Type': 'application/json'
|
||||||
}
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
rememberme: rememberme_token,
|
||||||
|
jwt: jwt === null ? undefined : jwt[0]
|
||||||
|
})
|
||||||
});
|
});
|
||||||
if (res.ok) {
|
let new_jwt;
|
||||||
const json = await res.json();
|
if (jwt) {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
new_jwt = jwt[0];
|
||||||
//@ts-ignore // skipcq: JS-0295
|
|
||||||
user_email = json.email;
|
|
||||||
} else {
|
} else {
|
||||||
user_email = null;
|
new_jwt = cookie.parse(res.headers.get('set-cookie')).access_token;
|
||||||
}
|
}
|
||||||
|
event.locals.email = await (
|
||||||
|
await fetch(`${process.env.API_URL}/api/v1/users/auth/internal/email`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
jwt: new_jwt
|
||||||
|
})
|
||||||
|
})
|
||||||
|
).text();
|
||||||
|
const resp = await resolve(event);
|
||||||
|
resp.headers.set('Set-Cookie', res.headers.get('set-cookie'));
|
||||||
|
return resp;
|
||||||
} else {
|
} else {
|
||||||
user_email = redis_res;
|
event.locals.email = null;
|
||||||
|
return resolve(event);
|
||||||
}
|
}
|
||||||
if (user_email === null) {
|
};
|
||||||
return {
|
|
||||||
authenticated: false,
|
export const getSession: GetSession = async (event) => {
|
||||||
token: event.locals.token,
|
return {
|
||||||
email: null
|
email: event.locals.email,
|
||||||
};
|
authenticated: Boolean(event.locals.email)
|
||||||
} else {
|
};
|
||||||
return {
|
};
|
||||||
authenticated: true,
|
|
||||||
token: event.locals.token,
|
|
||||||
email: user_email
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<footer class="text-center text-white border-black w-screen">
|
<footer class="text-center text-white border-black w-screen">
|
||||||
<div class="grid grid-cols-12 w-full pt-4 bg-gray-700 pb-2">
|
<div class="grid grid-cols-12 w-full pt-4 bg-gray-700 pb-2">
|
||||||
<p class="col-start-2 col-end-12 text-center w-full">
|
<p class="col-start-3 col-end-11 text-center w-full">
|
||||||
Made with ❤️ by
|
Made with ❤️ by
|
||||||
<a
|
<a
|
||||||
href="https://mawoka.eu?utm_source=ClassQuiz&utm_medium=footer"
|
href="https://mawoka.eu?utm_source=ClassQuiz&utm_medium=footer"
|
||||||
@@ -36,14 +36,16 @@
|
|||||||
>More details are here.</a
|
>More details are here.</a
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col items-center min-h-full h-full md:block hidden">
|
<div
|
||||||
|
class="flex flex-col items-center min-h-full h-full md:block hidden col-start-11 col-end-12"
|
||||||
|
>
|
||||||
<div class="my-auto mr-16">
|
<div class="my-auto mr-16">
|
||||||
<LanguageToggle />
|
<LanguageToggle />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="md:hidden block">
|
<div class="md:hidden block">
|
||||||
<div class="self-end flex justify-center min-h-full h-full bg-gray-700 md:pb-2">
|
<div class="self-end flex justify-center min-h-full h-full bg-gray-700 pb-2 md:pb-0">
|
||||||
<div class="m-auto md:invisible visible">
|
<div class="m-auto md:invisible visible">
|
||||||
<LanguageToggle />
|
<LanguageToggle />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user