add initial user Management API

This commit is contained in:
Alexander Bocken 2023-07-18 09:14:33 +02:00
parent 0816cbe9e5
commit ffa4496c16
Signed by: Alexander
GPG Key ID: 1D237BE83F9B05E8
4 changed files with 193 additions and 0 deletions

12
src/models/User.ts Normal file
View File

@ -0,0 +1,12 @@
import mongoose from 'mongoose';
const UserSchema = new mongoose.Schema(
{
username: {type: String, required: true, unique: true},
pass_hash: {type: String, required: true},
salt : {type: String, required: true},
access: [String], //rezepte, flims, abrechnung, ...
}, {timestamps: true}
);
export const User = mongoose.model("User", UserSchema);

View File

@ -0,0 +1,54 @@
import type { RequestHandler } from '@sveltejs/kit';
import { error } from '@sveltejs/kit';
import { sign } from 'jsonwebtoken';
import { hash, verify} from 'argon2';
import { COOKIE_SECRET } from '$env/static/private'
import { dbConnect, dbDisconnect } from '../../../utils/db';
import { User } from '../../../models/User';
// header: use for bearer token for now
// recipe json in body
export const POST: RequestHandler = async ({request}) => {
const {username, password} = await request.json()
// TODO: get salt from user in DB
await dbConnect()
let res = await User.findOne({username: username}, 'pass_hash salt').lean()
await dbDisconnect()
if(!res){
throw error(401, {message: "wrong password or user does not exist"})
}
const stored_pw = res.pass_hash
const salt = res.salt
const isMatch = await verify(stored_pw, password, {salt})
if(!isMatch){
throw error(401, {message: "wrong password or user does not exist"})
}
res = await createJWT(username)
return new Response(JSON.stringify(res))
};
async function hashPassword(password) {
try {
const salt = await generateSalt(); // Generate a random salt
const hashedPassword = await hash(password, salt); // Hash the password with the salt
return { hashedPassword, salt };
} catch (error) {
console.error('Error hashing password:', error);
}
}
async function createJWT(username) {
const payload = {
username: username,
};
const masterSecret = COOKIE_SECRET;
const secretKey = masterSecret;
const jwt = sign(payload, secretKey);
return jwt
}

View File

@ -0,0 +1,64 @@
import type { RequestHandler } from '@sveltejs/kit';
import { error } from '@sveltejs/kit';
import { sign } from 'jsonwebtoken';
import { hash, verify } from 'argon2';
import { randomBytes } from 'crypto';
import { COOKIE_SECRET } from '$env/static/private'
import { ALLOW_REGISTRATION } from '$env/static/private'
import { User } from '../../../models/User';
import { dbConnect, dbDisconnect } from '../../../utils/db';
// header: use for bearer token for now
// recipe json in body
export const POST: RequestHandler = async ({request}) => {
if(ALLOW_REGISTRATION){
const {username, password, access} = await request.json()
const salt = randomBytes(32).toString('hex'); // Generate a random salt
const pass_hash = await hashPassword(password, salt)
await dbConnect();
try{
await User.create({
username: username,
pass_hash: pass_hash,
salt: salt,
access: access,
})
}catch(e){
await dbDisconnect();
throw error(400, e);
}
await dbDisconnect();
return new Response(JSON.stringify({message: "User added successfully"}),
{status: 200}
);
}
else{
throw error(401, "user registration currently closed")
}
};
async function hashPassword(password, salt) {
try {
const hashedPassword = await hash(password, salt); // Hash the password with the salt
return hashedPassword;
} catch (error) {
console.error('Error hashing password:', error);
}
}
async function createJWT(username, userSalt) {
const payload = {
username: username,
};
const masterSecret = COOKIE_SECRET;
const secretKey = masterSecret + userSalt;
const jwt = sign(payload, secretKey);
return jwt
}

View File

@ -0,0 +1,63 @@
import type { RequestHandler } from '@sveltejs/kit';
import { error } from '@sveltejs/kit';
import { verify } from 'jsonwebtoken';
import { hash} from 'argon2';
import { randomBytes } from 'crypto';
import { COOKIE_SECRET } from '$env/static/private'
import { ALLOW_REGISTRATION } from '$env/static/private'
import { User } from '../../../models/User';
import { dbConnect, dbDisconnect } from '../../../utils/db';
import { getJWTFromRequest } from '../../../utils/cookie';
// header: use for bearer token for now
// recipe json in body
export const GET: RequestHandler = async ({request}) => {
const jwt = getJWTFromRequest(request)
console.log(jwt)
// Set your master secret key (replace with your own secret)
const masterSecret = COOKIE_SECRET;
const secretKey = masterSecret
let decoded
try{
decoded = await verify(jwt, secretKey);
}
catch(e){
throw error(401, "Cookies have changed, please log in again")
}
await dbConnect()
let res = await User.findOne({username: decoded.username}, 'access').lean();
await dbDisconnect()
if(!res){
throw error(404, "User for this Cookie does no longer exist")
}
return new Response(JSON.stringify({
username: decoded.username,
access: res.access
}), {status: 200})
};
async function hashPassword(password, salt) {
try {
const hashedPassword = await hash(password, salt); // Hash the password with the salt
return hashedPassword;
} catch (error) {
console.error('Error hashing password:', error);
}
}
async function createJWT(username, userSalt) {
const payload = {
username: username,
};
const masterSecret = COOKIE_SECRET;
const secretKey = masterSecret + userSalt;
const jwt = sign(payload, secretKey);
return jwt
}