start dev
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import type { User } from '$lib/types';
|
||||
import bcrypt from 'bcrypt';
|
||||
import sql from '$lib/db/db.server';
|
||||
import type { Cookies } from '@sveltejs/kit';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
export function setJWT(cookies: Cookies, user: User) {
|
||||
const payload = {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name
|
||||
};
|
||||
|
||||
if (process.env.JWT_SECRET === undefined) {
|
||||
throw new Error('JWT_SECRET not defined');
|
||||
}
|
||||
if (process.env.BASE_URL === undefined) {
|
||||
throw new Error('BASE_URL not defined');
|
||||
}
|
||||
|
||||
const secure: boolean = process.env.BASE_URL?.includes('https://');
|
||||
|
||||
const maxAge = 60 * 60 * 24 * 30; // 30 days
|
||||
const JWT = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '30d' });
|
||||
cookies.set('jwt', JWT, { maxAge, path: '/', httpOnly: false, secure });
|
||||
}
|
||||
|
||||
// export function checkPerms(cookies: Cookies, perms: number): void {
|
||||
// const JWT = cookies.get('jwt');
|
||||
// if (!JWT) throw error(403, 'Unauthorized');
|
||||
// if (process.env.JWT_SECRET === undefined) {
|
||||
// throw new Error('JWT_SECRET not defined');
|
||||
// }
|
||||
// const user = jwt.verify(JWT, process.env.JWT_SECRET) as User;
|
||||
// if ((user.perms & perms) !== perms) {
|
||||
// throw error(403, 'Unauthorized');
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// export function hasPerms(cookies: Cookies, perms: number): boolean {
|
||||
// const JWT = cookies.get('jwt');
|
||||
// if (!JWT) return false;
|
||||
// if (process.env.JWT_SECRET === undefined) {
|
||||
// throw new Error('JWT_SECRET not defined');
|
||||
// }
|
||||
// const user = jwt.verify(JWT, process.env.JWT_SECRET) as User;
|
||||
// return (user.perms & perms) === perms;
|
||||
// }
|
||||
|
||||
export async function login(email: string, password: string): Promise<User> {
|
||||
try {
|
||||
const [user] = await sql`
|
||||
SELECT id, email, password_hash, perms, name
|
||||
WHERE email = ${email};
|
||||
`;
|
||||
|
||||
if (await bcrypt.compare(password, user.password_hash)) {
|
||||
delete user.password_hash;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
sql`
|
||||
UPDATE users
|
||||
SET last_signin = NOW()
|
||||
WHERE id = ${user.id};
|
||||
`;
|
||||
|
||||
return <User>user;
|
||||
}
|
||||
} catch {
|
||||
throw Error('Error signing in ');
|
||||
}
|
||||
throw Error('Invalid email or password');
|
||||
}
|
||||
|
||||
// await createUser(<User>{
|
||||
// email: 'drake@marinodev.com',
|
||||
// password: 'password',
|
||||
// perms: 255,
|
||||
// name: 'Drake'
|
||||
// });
|
||||
@@ -0,0 +1,9 @@
|
||||
export const PERMISSIONS = {
|
||||
VIEW: 0b00000001,
|
||||
DO_TASKS: 0b00000010,
|
||||
MANAGE_USERS: 0b00000100,
|
||||
MANAGE_ITEMS: 0b00001000,
|
||||
MANAGE_TASKS: 0b00010000
|
||||
};
|
||||
|
||||
export const EXPIRE_REMINDER_DAYS = 30;
|
||||
@@ -0,0 +1,14 @@
|
||||
import postgres from 'postgres';
|
||||
import * as dotenv from 'dotenv';
|
||||
|
||||
dotenv.config({ path: '.env' });
|
||||
|
||||
const sql = postgres({
|
||||
host: process.env.POSTGRES_HOST,
|
||||
port: parseInt(process.env.POSTGRES_PORT!),
|
||||
database: process.env.POSTGRES_DB,
|
||||
username: process.env.POSTGRES_USER,
|
||||
password: process.env.POSTGRES_PASSWORD
|
||||
});
|
||||
|
||||
export default sql;
|
||||
@@ -0,0 +1,67 @@
|
||||
import type { User } from '$lib/types';
|
||||
import sql from '$lib/db/db.server';
|
||||
import bcrypt from 'bcrypt';
|
||||
|
||||
// should require MANAGE_USERS permission
|
||||
|
||||
export async function getUsers(searchQuery: string | null = null): Promise<User[]> {
|
||||
return sql`
|
||||
SELECT id,
|
||||
email,
|
||||
perms,
|
||||
name,
|
||||
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
||||
last_signin AT TIME ZONE 'UTC' AS "lastSignIn"
|
||||
FROM users
|
||||
WHERE (${!searchQuery ? sql`TRUE` : sql`email ILIKE ${'%' + searchQuery + '%'} OR name ILIKE ${'%' + searchQuery + '%'}`});
|
||||
`;
|
||||
}
|
||||
|
||||
export async function getUser(id: number): Promise<User> {
|
||||
return <User>(
|
||||
await sql`
|
||||
SELECT id,
|
||||
email,
|
||||
perms,
|
||||
name,
|
||||
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
||||
last_signin AT TIME ZONE 'UTC' AS "lastSignIn"
|
||||
FROM users
|
||||
WHERE (id = ${id}) LIMIT 1;
|
||||
`
|
||||
)[0];
|
||||
}
|
||||
|
||||
export async function createUser(user: User) {
|
||||
const passwordHash = await bcrypt.hash(user.password!, 12);
|
||||
await sql`
|
||||
INSERT INTO users (email, password_hash, perms, name, created_at, last_signin)
|
||||
VALUES (${user.email}, ${passwordHash}, ${user.perms}, ${user.name}, NOW(), NOW())
|
||||
RETURNING id;
|
||||
`;
|
||||
}
|
||||
|
||||
export async function editUser(user: User) {
|
||||
let passwordHash: string | undefined;
|
||||
if (user.password) {
|
||||
passwordHash = await bcrypt.hash(user.password, 12);
|
||||
}
|
||||
|
||||
await sql`
|
||||
UPDATE users
|
||||
SET
|
||||
email = ${user.email},
|
||||
${passwordHash ? sql`password_hash = ${passwordHash},` : sql``}
|
||||
perms = ${user.perms},
|
||||
name = ${user.name}
|
||||
WHERE id = ${user.id!}
|
||||
RETURNING id;
|
||||
`;
|
||||
}
|
||||
|
||||
export async function deleteUser(id: number) {
|
||||
await sql`
|
||||
DELETE FROM users
|
||||
WHERE id = ${id}
|
||||
`;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
export interface User {
|
||||
id: number;
|
||||
email: string;
|
||||
phone: string;
|
||||
password?: string;
|
||||
name: string;
|
||||
createdAt: Date;
|
||||
lastSignIn: Date;
|
||||
}
|
||||
|
||||
export interface Item {
|
||||
id: number;
|
||||
ownerEmail: string;
|
||||
ownerPhone: string;
|
||||
foundDate: Date;
|
||||
approvedDate?: Date;
|
||||
claimedDate?: Date;
|
||||
title: string;
|
||||
description: string;
|
||||
transferred: boolean; // to L&F location
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import type { User } from '$lib/types';
|
||||
|
||||
export const getCookieValue = (name: string): string =>
|
||||
document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)')?.pop() || '';
|
||||
|
||||
export const getUserFromJWT = (jwt: string): User => JSON.parse(atob(jwt.split('.')[1]));
|
||||
|
||||
// export const userData = () => {
|
||||
// let userData: User | null = null;
|
||||
// const cookieValue = getCookieValue('jwt');
|
||||
// if (cookieValue) {
|
||||
// userData = getUserFromJWT(cookieValue);
|
||||
// }
|
||||
// return userData;
|
||||
// };
|
||||
|
||||
export function getFormString(data: FormData, key: string): string | undefined {
|
||||
const value = data.get(key);
|
||||
if (value === null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
throw Error(`Incorrect input in field ${key}.`);
|
||||
}
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
export function getRequiredFormString(data: FormData, key: string) {
|
||||
const value = data.get(key);
|
||||
if (typeof value !== 'string') {
|
||||
throw Error(`Missing required field ${key}.`);
|
||||
}
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
export const dateFormatOptions: Intl.DateTimeFormatOptions = {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
};
|
||||
Reference in New Issue
Block a user