Added auto database creation based on sql scripts and jwt key cache
This commit is contained in:
@@ -9,3 +9,5 @@
|
|||||||
_fresh/
|
_fresh/
|
||||||
# npm dependencies
|
# npm dependencies
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
|
databases/data/
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { Database } from "@db/sqlite";
|
||||||
|
|
||||||
|
export default async function ensureDatabases() {
|
||||||
|
for await (const file of Deno.readDir("databases/init")) {
|
||||||
|
if (!file.isFile) {
|
||||||
|
console.warn(`[WARN] Path ${file.name} is not a file.`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const databaseName = file.name.substring(0, file.name.length - 4);
|
||||||
|
const databasePath = `databases/data/${databaseName}.db`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Deno.stat(databasePath);
|
||||||
|
} catch (error) {
|
||||||
|
if (!(error instanceof Deno.errors.NotFound)) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sqlInitCode = await Deno.readTextFile(
|
||||||
|
`databases/init/${file.name}`,
|
||||||
|
);
|
||||||
|
const database = new Database(databasePath);
|
||||||
|
database.run(sqlInitCode);
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,9 @@
|
|||||||
"check": "deno fmt --check && deno lint && deno check **/*.ts && deno check **/*.tsx",
|
"check": "deno fmt --check && deno lint && deno check **/*.ts && deno check **/*.tsx",
|
||||||
"cli": "echo \"import '\\$fresh/src/dev/cli.ts'\" | deno run --unstable -A -",
|
"cli": "echo \"import '\\$fresh/src/dev/cli.ts'\" | deno run --unstable -A -",
|
||||||
"manifest": "deno task cli manifest $(pwd)",
|
"manifest": "deno task cli manifest $(pwd)",
|
||||||
"start": "deno run -A --watch=static/,routes/ dev.ts",
|
"start": "deno run -A --unstable-ffi --watch=static/,routes/ dev.ts",
|
||||||
"build": "deno run -A dev.ts build",
|
"build": "deno run -A --unstable-ffi dev.ts build",
|
||||||
"preview": "deno run -A main.ts",
|
"preview": "deno run -A --unstable-ffi main.ts",
|
||||||
"update": "deno run -A -r https://fresh.deno.dev/update ."
|
"update": "deno run -A -r https://fresh.deno.dev/update ."
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
],
|
],
|
||||||
"imports": {
|
"imports": {
|
||||||
"$fresh/": "https://deno.land/x/fresh@1.7.3/",
|
"$fresh/": "https://deno.land/x/fresh@1.7.3/",
|
||||||
|
"@db/sqlite": "jsr:@db/sqlite@^0.12.0",
|
||||||
"@melvdouc/xml-parser": "jsr:@melvdouc/xml-parser@^0.1.1",
|
"@melvdouc/xml-parser": "jsr:@melvdouc/xml-parser@^0.1.1",
|
||||||
"@popov/jwt": "jsr:@popov/jwt@^1.0.1",
|
"@popov/jwt": "jsr:@popov/jwt@^1.0.1",
|
||||||
"preact": "https://esm.sh/preact@10.22.0",
|
"preact": "https://esm.sh/preact@10.22.0",
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { defineConfig } from "$fresh/server.ts";
|
import { defineConfig } from "$fresh/server.ts";
|
||||||
|
import ensureDatabases from "$root/databases/ensure.ts";
|
||||||
|
|
||||||
|
await ensureDatabases();
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
cert: await Deno.readTextFile("certs/cert.pem"),
|
cert: await Deno.readTextFile("certs/cert.pem"),
|
||||||
|
|||||||
+24
-3
@@ -1,6 +1,7 @@
|
|||||||
import { FreshContext } from "$fresh/server.ts";
|
import { FreshContext } from "$fresh/server.ts";
|
||||||
import { getCookies } from "$std/http/cookie.ts";
|
import { getCookies } from "$std/http/cookie.ts";
|
||||||
import { isJwtValid } from "@popov/jwt";
|
import { getJwtPayload, isJwtValid } from "@popov/jwt";
|
||||||
|
import { LoginJWT } from "$root/routes/login.tsx";
|
||||||
|
|
||||||
const PUBLIC_ROUTES = [
|
const PUBLIC_ROUTES = [
|
||||||
"/",
|
"/",
|
||||||
@@ -11,6 +12,8 @@ const PUBLIC_ROUTES = [
|
|||||||
"/contact",
|
"/contact",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const jwtKeyCache: Record<string, string> = {};
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
isAuthenticated: boolean;
|
isAuthenticated: boolean;
|
||||||
}
|
}
|
||||||
@@ -19,15 +22,33 @@ function isRoutePublic(route: string) {
|
|||||||
return PUBLIC_ROUTES.includes(route) || route.match(/\..+$/);
|
return PUBLIC_ROUTES.includes(route) || route.match(/\..+$/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getKey(user: string): string {
|
||||||
|
if (!jwtKeyCache[user]) {
|
||||||
|
const keyBuffer = new Uint8Array(32);
|
||||||
|
crypto.getRandomValues(keyBuffer);
|
||||||
|
jwtKeyCache[user] = new TextDecoder().decode(keyBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jwtKeyCache[user];
|
||||||
|
}
|
||||||
|
|
||||||
export const handler = [
|
export const handler = [
|
||||||
async function checkAuthentication(
|
async function checkAuthentication(
|
||||||
request: Request,
|
request: Request,
|
||||||
context: FreshContext<State>,
|
context: FreshContext<State>,
|
||||||
) {
|
) {
|
||||||
const cookies = getCookies(request.headers);
|
const cookies = getCookies(request.headers);
|
||||||
|
if (!cookies["sessionToken"]) {
|
||||||
|
context.state.isAuthenticated = false;
|
||||||
|
return await context.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = getJwtPayload(cookies["sessionToken"]) as LoginJWT;
|
||||||
|
const key = getKey(content.user.uid as string);
|
||||||
|
|
||||||
context.state.isAuthenticated = await isJwtValid(
|
context.state.isAuthenticated = await isJwtValid(
|
||||||
cookies["sessionToken"] ?? "",
|
cookies["sessionToken"],
|
||||||
"NEED TO CHANGE THIS KEY FURTHER IN DEV",
|
key,
|
||||||
);
|
);
|
||||||
|
|
||||||
return await context.next();
|
return await context.next();
|
||||||
|
|||||||
+10
-1
@@ -7,6 +7,7 @@ import {
|
|||||||
} from "@melvdouc/xml-parser";
|
} from "@melvdouc/xml-parser";
|
||||||
import { createJwt } from "@popov/jwt";
|
import { createJwt } from "@popov/jwt";
|
||||||
import { setCookie } from "$std/http/cookie.ts";
|
import { setCookie } from "$std/http/cookie.ts";
|
||||||
|
import { getKey } from "$root/routes/_middleware.ts";
|
||||||
|
|
||||||
const SERVICE = "https://localhost/login";
|
const SERVICE = "https://localhost/login";
|
||||||
const CAS = "https://ident.univ-amu.fr/cas";
|
const CAS = "https://ident.univ-amu.fr/cas";
|
||||||
@@ -23,6 +24,14 @@ interface CasResponse extends RegularTagNode {
|
|||||||
children: [TextNode, CasGroupNode];
|
children: [TextNode, CasGroupNode];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LoginJWT {
|
||||||
|
iss: "PolyMPR";
|
||||||
|
iat: number;
|
||||||
|
exp: number;
|
||||||
|
aud: "PolyMPR";
|
||||||
|
user: Record<string, string | string[]>;
|
||||||
|
}
|
||||||
|
|
||||||
function getTag(tag: CasTagNode): [string, string] {
|
function getTag(tag: CasTagNode): [string, string] {
|
||||||
return [
|
return [
|
||||||
tag.tagName.replace("cas:", ""),
|
tag.tagName.replace("cas:", ""),
|
||||||
@@ -55,7 +64,7 @@ function createUserJWT(casResponse: CasResponse): Promise<string> {
|
|||||||
user: fullUserInfos,
|
user: fullUserInfos,
|
||||||
};
|
};
|
||||||
|
|
||||||
const key = "NEED TO CHANGE THIS KEY FURTHER IN DEV";
|
const key = getKey(fullUserInfos.uid as string);
|
||||||
return createJwt(payload, key);
|
return createJwt(payload, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user