fix singletone

This commit is contained in:
monoid 2023-01-06 23:22:00 +09:00
parent 687c1ac5e8
commit b552553edb
6 changed files with 50 additions and 20 deletions

View File

@ -43,7 +43,6 @@ const CSSPlugin: Plugin = {
}; };
}, },
}; };
await prepareSecretKey();
async function startServer(manifest: Manifest, options: StartOptions = {}) { async function startServer(manifest: Manifest, options: StartOptions = {}) {
const ctx = await ServerContext.fromManifest(manifest, options); const ctx = await ServerContext.fromManifest(manifest, options);
@ -86,7 +85,10 @@ if (import.meta.main) {
.option("--db-path <path:string>", "The path to the database file.", { .option("--db-path <path:string>", "The path to the database file.", {
default: ":memory:", default: ":memory:",
}) })
.option("--id-password <idpassword:string>", "The password to use. (Not recommended). id:password format.") .option(
"--id-password <idpassword:string>",
"The password to use. (Not recommended). id:password format.",
)
.arguments("[hostname:string]") .arguments("[hostname:string]")
.action(async ({ debug, port, auth, dbPath, idPassword }, hostname) => { .action(async ({ debug, port, auth, dbPath, idPassword }, hostname) => {
hostname ??= "localhost"; hostname ??= "localhost";
@ -98,7 +100,7 @@ if (import.meta.main) {
} }
if (idPassword) { if (idPassword) {
Deno.env.set("AUTH_REQUIRED", "true"); Deno.env.set("AUTH_REQUIRED", "true");
const db = connectDB(); const db = await connectDB();
const [username, password] = idPassword.split(":"); const [username, password] = idPassword.split(":");
const new_user = await users.createUser(username, password); const new_user = await users.createUser(username, password);
await users.addUser(db, new_user); await users.addUser(db, new_user);
@ -106,6 +108,7 @@ if (import.meta.main) {
if (debug) { if (debug) {
console.log("Debug mode enabled."); console.log("Debug mode enabled.");
} }
await prepareSecretKey();
await prepareDocs(); await prepareDocs();
await start({ await start({
port: port, port: port,

View File

@ -3,12 +3,11 @@ import { getCookies } from "http/cookie.ts";
import { verify } from "djwt"; import { verify } from "djwt";
import { prepareSecretKey } from "../util/secret.ts"; import { prepareSecretKey } from "../util/secret.ts";
const secret_key = await prepareSecretKey();
export const handler = async ( export const handler = async (
req: Request, req: Request,
ctx: MiddlewareHandlerContext<Record<string, unknown>>, ctx: MiddlewareHandlerContext<Record<string, unknown>>,
) => { ) => {
const secret_key = await prepareSecretKey();
const cookies = getCookies(req.headers); const cookies = getCookies(req.headers);
const jwt = cookies["auth"]; const jwt = cookies["auth"];
try { try {

View File

@ -6,17 +6,16 @@ import { getUser, verifyUser } from "../../src/user/user.ts";
import { create as createJWT } from "djwt"; import { create as createJWT } from "djwt";
import { prepareSecretKey } from "../../util/secret.ts"; import { prepareSecretKey } from "../../util/secret.ts";
const SECRET_KEY = await prepareSecretKey(); async function POST(req: Request, _ctx: HandlerContext): Promise<Response> {
async function POST(req: Request, ctx: HandlerContext): Promise<Response> {
const url = new URL(req.url); const url = new URL(req.url);
const form = await req.formData(); const form = await req.formData();
const username = form.get("username"); const username = form.get("username");
const password = form.get("password"); const password = form.get("password");
if (username && password) { if (username && password) {
const DB = connectDB(); const DB = await connectDB();
const user = await getUser(DB, username.toString()); const user = await getUser(DB, username.toString());
if (user) { if (user) {
const SECRET_KEY = await prepareSecretKey();
if (await verifyUser(user, password.toString())) { if (await verifyUser(user, password.toString())) {
const headers = new Headers(); const headers = new Headers();
const jwt = await createJWT({ alg: "HS512", typ: "JWT" }, { const jwt = await createJWT({ alg: "HS512", typ: "JWT" }, {

View File

@ -1,13 +1,31 @@
import { DB } from "sqlite"; import { DB } from "sqlite";
import { createSchema } from "./user.ts"; import { createSchema } from "./user.ts";
export function connectDB(): DB { let inmemoryDB: DB | undefined;
let previousPath = "";
let dbCache: DB | undefined;
export async function connectDB(): Promise<DB> {
let DB_path = Deno.env.get("DB_PATH"); let DB_path = Deno.env.get("DB_PATH");
if (DB_path === undefined) { if (DB_path === ":memory:") {
Deno.env.set("DB_PATH", "./db.sqlite"); if (inmemoryDB === undefined) {
DB_path = "./db.sqlite"; inmemoryDB = new DB(":memory:");
await createSchema(inmemoryDB);
} }
let db = new DB(DB_path); return inmemoryDB;
createSchema(db); } else if (DB_path === undefined) {
Deno.env.set("DB_PATH", "db.sqlite");
DB_path = "db.sqlite";
}
if (dbCache !== undefined && DB_path === previousPath) {
return dbCache;
} else {
dbCache?.close();
dbCache = undefined;
}
const db = new DB(DB_path);
previousPath = DB_path;
dbCache = db;
await createSchema(db);
return db; return db;
} }

View File

@ -24,7 +24,7 @@ export const user_command = new Command()
Deno.exit(1); Deno.exit(1);
} }
} }
const db = connectDB(); const db = await connectDB();
const new_user = await users.createUser(username, password); const new_user = await users.createUser(username, password);
await users.addUser(db, new_user); await users.addUser(db, new_user);
if (!quiet) { if (!quiet) {
@ -35,7 +35,7 @@ export const user_command = new Command()
.arguments("<username:string>") .arguments("<username:string>")
.option("-q, --quiet", "Quiet output.") .option("-q, --quiet", "Quiet output.")
.action(async ({ quiet }, username) => { .action(async ({ quiet }, username) => {
const db = connectDB(); const db = await connectDB();
await users.deleteUser(db, username); await users.deleteUser(db, username);
if (!quiet) { if (!quiet) {
console.log(`Deleting user ${username}`); console.log(`Deleting user ${username}`);
@ -43,7 +43,7 @@ export const user_command = new Command()
}) })
.command("list", "list all users") .command("list", "list all users")
.action(async () => { .action(async () => {
const db = connectDB(); const db = await connectDB();
const all_users = await users.getAllUsers(db); const all_users = await users.getAllUsers(db);
for (const user of all_users) { for (const user of all_users) {
console.log(`${user.name}`); console.log(`${user.name}`);
@ -53,7 +53,7 @@ export const user_command = new Command()
.arguments("<username:string> <password:string>") .arguments("<username:string> <password:string>")
.option("-q, --quiet", "quiet output.") .option("-q, --quiet", "quiet output.")
.action(async ({ quiet }, [username, password]) => { .action(async ({ quiet }, [username, password]) => {
const db = connectDB(); const db = await connectDB();
const new_user = await users.createUser(username, password); const new_user = await users.createUser(username, password);
await users.updateUser(db, new_user); await users.updateUser(db, new_user);
if (!quiet) { if (!quiet) {

View File

@ -8,10 +8,17 @@ export async function generateSecretKey() {
return key; return key;
} }
let cacheKey: CryptoKey | undefined;
let previousKey = "invalid";
export async function prepareSecretKey() { export async function prepareSecretKey() {
const key = Deno.env.get("SECRET_KEY"); const key = Deno.env.get("SECRET_KEY");
if (key === previousKey) {
return cacheKey!;
}
if (key) { if (key) {
const jwk = JSON.parse(key) as JsonWebKey; const jwk = JSON.parse(key) as JsonWebKey;
previousKey = key;
{ {
const key = await crypto.subtle.importKey( const key = await crypto.subtle.importKey(
"jwk", "jwk",
@ -20,12 +27,16 @@ export async function prepareSecretKey() {
true, true,
["sign", "verify"], ["sign", "verify"],
); );
cacheKey = key;
return key; return key;
} }
} else { } else {
const key = await generateSecretKey(); const key = await generateSecretKey();
const out = await crypto.subtle.exportKey("jwk", key); const out = await crypto.subtle.exportKey("jwk", key);
Deno.env.set("SECRET_KEY", JSON.stringify(out)); const outStr = JSON.stringify(out);
Deno.env.set("SECRET_KEY", outStr);
cacheKey = key;
previousKey = outStr;
return key; return key;
} }
} }