Login System + API
This commit is contained in:
38
src/lib/APIResponse.ts
Normal file
38
src/lib/APIResponse.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { ZodError } from "zod";
|
||||
|
||||
export function success(data: any = {}) {
|
||||
return new Response(JSON.stringify({
|
||||
success: true,
|
||||
data
|
||||
}))
|
||||
}
|
||||
|
||||
export function error(errors: any[]) {
|
||||
return new Response(JSON.stringify({
|
||||
success: false,
|
||||
errors
|
||||
}))
|
||||
}
|
||||
|
||||
export function MissingPropertyError(properties: string[]) {
|
||||
return error(properties.map(property => {
|
||||
return `Missing property '${property}' in request body.`
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Signalisiert ein fehlendes Objekt und gibt den Fehler als HTTP Response zurück.
|
||||
* @param name Der Name der Entität, die nicht gefunden werden konnte.
|
||||
* @returns {Response} HTTP Response Objekt
|
||||
*/
|
||||
export function MissingEntityError(name: string): Response {
|
||||
return error([`Missing entity, ${name} does not exist.`])
|
||||
}
|
||||
|
||||
export function ActionFailedError(): Response {
|
||||
return error(["Failed executing action, error encountered."]);
|
||||
}
|
||||
|
||||
export function InvalidDataError(err: ZodError): Response {
|
||||
return error(err.issues);
|
||||
}
|
||||
9
src/lib/Ausweis/index.ts
Normal file
9
src/lib/Ausweis/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export class Ausweis {
|
||||
public static fromPublicId(public_id: string) {
|
||||
|
||||
}
|
||||
|
||||
public static fromPrivateId(id: number) {
|
||||
|
||||
}
|
||||
}
|
||||
0
src/lib/Ausweis/type.ts
Normal file
0
src/lib/Ausweis/type.ts
Normal file
10
src/lib/JsonWebToken.ts
Normal file
10
src/lib/JsonWebToken.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import * as jwt from "jwt-simple";
|
||||
|
||||
export function encodeToken(data: Record<string, any>) {
|
||||
const token = jwt.encode(data, "yIvbgS$k7Bfc+mpV%TWDZAhje9#uJad4", "HS256");
|
||||
return token;
|
||||
}
|
||||
|
||||
export function decodeToken(token: string) {
|
||||
return jwt.decode(token, "yIvbgS$k7Bfc+mpV%TWDZAhje9#uJad4");
|
||||
}
|
||||
22
src/lib/Password.ts
Normal file
22
src/lib/Password.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import * as bcrypt from "bcrypt";
|
||||
|
||||
export async function hashPassword(password: string): Promise<string | null> {
|
||||
const saltRounds = 4;
|
||||
|
||||
try {
|
||||
const salt = await bcrypt.genSalt(saltRounds);
|
||||
const hash = await bcrypt.hash(password, salt);
|
||||
return hash;
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function validatePassword(known: string, unknown: string): Promise<boolean> {
|
||||
try {
|
||||
const compare = await bcrypt.compare(unknown, known)
|
||||
return compare
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
88
src/lib/User/index.ts
Normal file
88
src/lib/User/index.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { db } from "../shared";
|
||||
import { UserRegisterValidator, UserType, UserTypeValidator } from "./type";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import { hashPassword } from "../Password";
|
||||
|
||||
|
||||
export class User {
|
||||
/**
|
||||
* Sucht einen Nutzer in der Datenbank anhand seiner Public/Unique id und gibt ihn zurück.
|
||||
* @param uid Die unique/public id des gesuchten Benutzers.
|
||||
* @returns {UserType | null} Die Daten des Nutzers oder null falls dieser nicht gefunden werden kann.
|
||||
*/
|
||||
public static async fromPublicId(uid: string): Promise<UserType | null> {
|
||||
if (!uid || typeof uid !== "string") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const user = await db<UserType>("users").select("*").where("uid", uid).first();
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async fromUsername(username: string): Promise<UserType | null> {
|
||||
if (!username || typeof username !== "string") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const user = await db<UserType>("users").select("*").where("username", username).first();
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht einen Nutzer in der Datenbank anhand seiner Private id und gibt ihn zurück.
|
||||
* @param uid Die private id des gesuchten Benutzers.
|
||||
* @returns {UserType | null} Die Daten des Nutzers oder null falls dieser nicht gefunden werden kann.
|
||||
*/
|
||||
public static async fromPrivateId(id: number): Promise<UserType | null> {
|
||||
if (!id || typeof id !== "number") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const user = await db<UserType>("users").select("*").where("id", id).first();
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async create(user: UserType): Promise<{uid: string, id: number} | null> {
|
||||
if (!user || UserRegisterValidator.safeParse(user).success == false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const uid = uuid();
|
||||
const hashedPassword = await hashPassword(user.password);
|
||||
|
||||
if (!hashedPassword) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const result = await db<UserType>("users").insert({
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
password: hashedPassword,
|
||||
uid: uid
|
||||
}, ["id"])
|
||||
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
uid,
|
||||
id: result[0].id
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/lib/User/type.ts
Normal file
17
src/lib/User/type.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { z } from "zod"
|
||||
|
||||
export const UserTypeValidator = z.object({
|
||||
username: z.string().min(4).max(64),
|
||||
id: z.number(),
|
||||
uid: z.string().length(36),
|
||||
email: z.string().max(255),
|
||||
password: z.string().min(6),
|
||||
})
|
||||
|
||||
export const UserRegisterValidator = z.object({
|
||||
username: z.string().min(4).max(64),
|
||||
email: z.string().max(255),
|
||||
password: z.string().min(6),
|
||||
})
|
||||
|
||||
export type UserType = z.infer<typeof UserTypeValidator>
|
||||
19
src/lib/shared.ts
Normal file
19
src/lib/shared.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import knex, { Knex } from "knex";
|
||||
|
||||
export function dbOpen(): Knex {
|
||||
const db = knex({
|
||||
client: 'pg',
|
||||
connection: {
|
||||
host : '127.0.0.1',
|
||||
port : 5436,
|
||||
user : 'main',
|
||||
password : 'hHMP8cd^N3SnzGRR',
|
||||
database : 'main'
|
||||
}
|
||||
})
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
export const db = dbOpen();
|
||||
Reference in New Issue
Block a user