Compare commits

..

No commits in common. "1d8220d92c27802bc0b5ef858cef4ca786b9276b" and "500a9ad59505c7b9d005b36e5f0c4b59d390332c" have entirely different histories.

8 changed files with 19 additions and 75 deletions

View file

@ -7,13 +7,14 @@ type optionalMap<Optional> = Optional extends true ? undefined : string | number
export type fieldDefinition<Optional extends boolean = boolean> = {
key: string,
label?: string,
type: "text" | "password" | "number",
type: "text" | "number",
optional?: Optional,
value?: optionalMap<Optional>,
}
const props = defineProps<{
fields: Array<fieldDefinition>,
modelValue?: any,
}>();
// eslint-disable-next-line func-call-spacing

View file

@ -9,7 +9,7 @@ import Alerts, { type AlertData } from '~/components/alerts.vue';
const editorFields: Array<fieldDefinition> = [
{ key: "username", type: "text", label: "Username", optional: false },
{ key: "password", type: "password", label: "Password", optional: false },
{ key: "password", type: "text", label: "Password", optional: false },
{ key: "email", type: "text", label: "email", optional: false },
];

View file

@ -20,14 +20,12 @@ model User {
}
model Session {
id BigInt @id @default(dbgenerated("(((unix_timestamp() * 1000) * pow(2,22)) + floor((rand() * pow(2,12))))")) @db.UnsignedBigInt
userId BigInt @map("user") @db.UnsignedBigInt
sessionToken Bytes @db.Binary(64)
expiry_date DateTime? @default(dbgenerated("(now() + interval 30 day)")) @db.Timestamp(0)
user User @relation(fields: [userId], references: [id])
id BigInt @id @default(dbgenerated("(((unix_timestamp() * 1000) * pow(2,22)) + floor((rand() * pow(2,12))))")) @db.UnsignedBigInt
userId BigInt @map("user") @db.UnsignedBigInt
expiry_date DateTime? @default(dbgenerated("(now() + interval 30 day)")) @db.Timestamp(0)
user User @relation(fields: [userId], references: [id])
@@index([userId], map: "user_idx")
@@index([sessionToken])
@@map("sessions")
}

View file

@ -24,7 +24,7 @@ export default defineEventHandler(async (e) => {
if (typeof email !== "string") throw createError({ message: "email is not string", statusCode: 400 });
execSync("npx prisma db push --force-reset");
await database.user.create({
database.user.create({
data: {
id: new Snowflake().state,
username,

View file

@ -4,7 +4,7 @@ import { defineEventHandler, getCookie, setCookie, readBody } from "h3";
import { database } from "../utils/database";
import { isString } from "../utils/isString";
import { cookieSettings } from "../utils/rootUtils";
import SessionToken from "../utils/SessionToken";
import Snowflake from "~/utils/snowflake";
import { createError } from "#imports";
@ -40,11 +40,14 @@ export default defineEventHandler(async (e) => {
if (account === null) throw createError({ statusCode: 400, message: "Invalid username or password." });
const session = new SessionToken(account.id);
const sessionId = new Snowflake();
await database.session.create({
data: session.toPrisma(),
data: {
id: sessionId.state,
userId: account.id,
},
});
setCookie(e, "token", session.toString(), cookieSettings);
return { message: "Login successful", token: session.toString() };
setCookie(e, "token", sessionId.toString(), cookieSettings);
return { message: "Login successful", token: sessionId.toString() };
});

View file

@ -1,11 +1,9 @@
import { defineEventHandler, getCookie } from "h3";
import SessionToken from "../utils/SessionToken";
import { createError } from "#imports";
import { database } from "~/server/utils/database";
import getRequestingUser from "~/server/utils/getRequestingUser";
import { createError } from "#imports";
const endpointsWithoutAuth: string[] = [
"/dbtest",
"/echo",
@ -39,10 +37,7 @@ export async function isAuthorised(token: string | undefined): Promise<boolean>
try {
await database.session.findUniqueOrThrow({
where: {
...SessionToken.fromString(token).toPrisma(),
expiry_date: {
gte: new Date(),
},
id: BigInt(token),
},
});

View file

@ -1,49 +0,0 @@
import crypto from "node:crypto";
import { type Session } from "@prisma/client";
import Snowflake from "~/utils/snowflake";
/** Represents a Session token, without expiry data. */
export default class SessionToken {
userId: bigint;
sessionId: bigint;
sessionToken: Buffer;
constructor(userId: bigint, sessionId?: bigint, sessionToken?: Buffer) {
this.userId = userId;
this.sessionId = sessionId ?? new Snowflake().state;
this.sessionToken = sessionToken ?? crypto.randomBytes(64);
}
/** Creates SessionToken from a string.
* @param string The strinct to create from.
* @returns The SessionToken object.
*/
static fromString(string: string): SessionToken {
const parameters = string.split(".");
return new SessionToken(
Buffer.from(parameters[0], "base64").readBigUInt64LE(),
Buffer.from(parameters[1], "base64").readBigUInt64LE(),
Buffer.from(parameters[2], "base64"),
);
}
toString(): string {
const stringUserId = Buffer.copyBytesFrom(new BigUint64Array([this.userId])).toString("base64");
const stringSessionId = Buffer.copyBytesFrom(new BigUint64Array([this.sessionId])).toString("base64");
const stringSessionToken = this.sessionToken.toString("base64");
return `${stringUserId}.${stringSessionId}.${stringSessionToken}`;
}
/** Returns this SessionToken as Prisma object.
* For use in where parameter.
* @returns this as prisma object.
*/
toPrisma(): Omit<Session, "expiry_date"> {
return {
id: this.sessionId,
userId: this.userId,
sessionToken: this.sessionToken,
};
}
}

View file

@ -1,7 +1,6 @@
import { getCookie, H3Event } from "h3";
import { database } from "./database";
import SessionToken from "./SessionToken";
import { createError } from "#imports";
@ -10,10 +9,7 @@ export default async function getRequestingUser(e: H3Event) {
if (!cookie) throw createError("User not found");
const { user } = await database.session.findUnique({
where: {
...SessionToken.fromString(cookie).toPrisma(),
expiry_date: {
gte: new Date(),
},
id: BigInt(cookie),
},
select: {
user: {