This commit is contained in:
Jesper 2024-10-04 11:49:39 +02:00
parent 349ad6356a
commit 25606bd438
9 changed files with 198 additions and 7 deletions

View File

@ -6,21 +6,39 @@ import { authenticator } from 'otplib';
const user = new User(); const user = new User();
const userController = new Elysia() const userController = new Elysia()
.get('/', ({user}) => {
return user
})
.post('/login', async ({ body }) => { .post('/login', async ({ body }) => {
const msg = db.query(`select id, password, otp from users WHERE username = ?;`) const msg = db.query(`select id, password, administrator, otp from users WHERE username = ?;`)
.get(body.username) .get(body.username)
console.log(msg) console.log(msg)
if(msg == null) return new Response("Invalid username or password", { status: 401 }) if(msg == null) return new Response("Invalid username or password", { status: 401 })
const validPassword = await Bun.password.verify(body.password, msg.password) const validPassword = await Bun.password.verify(body.password, msg.password)
if (!validPassword) return new Response("Invalid username or password", { status: 401 }) if (!validPassword) return new Response("Invalid username or password", { status: 401 })
// if(!authenticator.check(body.otp, msg.otp)) return new Response("Invalid OTP code", { status: 401 }) // if(!authenticator.check(body.otp, msg.otp)) return new Response("Invalid OTP code", { status: 401 })
if(msg.administrator == 1) {return new Response(await user.createToken(msg.id), {status: 418})}
return await user.createToken(msg.id) return await user.createToken(msg.id)
}) })
.post('/register', async({body}) => { // .post('/register', async({body}) => {
return await Bun.password.hash(body.password); // return await Bun.password.hash(body.password);
}) // })
.get('/otp', () => { .get('/otp', () => {
return authenticator.generateSecret(); return authenticator.generateSecret();
}) })
.put('/password', ({user}, body) => {
const oldPassword = body.oldPassword;
const newPassword = body.newPassword;
if (oldPassword == "" || newPassword == "") {
{return new Response("Bad password", {status: 400})}
}
const msg = db.query(`select password from users WHERE id = ?;`).get(user.id);
if(!Bun.password.verify(oldPassword, msg.password)) {
{return new Response("Bad old password", {status: 400})}
}
const newPasswordHash = Bun.password.hash(body.newPassword)
const msg = db.query(`update users set password = ? WHERE id = ?;`).run(newPassword. user.id);
})
export default userController export default userController

View File

@ -1,10 +1,48 @@
import { Elysia } from 'elysia' import { Elysia } from 'elysia'
import db from '../Database'
import { authenticator } from 'otplib';
const adminController = new Elysia() const adminController = new Elysia()
.get('/', () => "admin endpoint") .get('/', () => "admin endpoint")
.post('/register', async({body}) => { .get('/users', () => {
return await Bun.password.hash(body.password); const users = db.query(`SELECT id, username, name FROM users;`)
.all();
return users
})
.post('/user/group/:groupId', ({params: {groupId}, body}) => {
db.query(`INSERT INTO userGroups (UserID, GroupID) VALUES (?, ?);`).run(groupId, body.userId);
return "Added user to group"
})
.delete('/user/:userId', ({params: {userId}}) => {
db.query(`DELETE FROM users WHERE id = ?;`).run(userId);
"deleted user"
})
.post('/register', async({body}) => {
const password = await Bun.password.hash(body.password);
const otp = authenticator.generateSecret();
const res = db.query(`INSERT INTO users(username, password, name, otp) VALUES (?, ?, ?, ?);`).run(body.username, password, body.name, otp);
return {id: res.lastInsertRowid, username: body.username, name: body.name, otp: otp}
})
.get('/group', () => {
const groups = db.query(`SELECT GroupID, GroupName FROM groups;`)
.all();
return groups
})
.post('/group', ({body}) => {
const res = db.query(`INSERT INTO groups (GroupName) VALUES (?);`).run(body.name);
return {GroupID: res.lastInsertRowid, GroupName: body.name}
})
.delete('/group/:groupId', ({ params: { groupId }}) => {
db.query(`DELETE FROM groups WHERE GroupID = ?;`).run(groupId);
"deleted group"
})
.delete('/password/:passwordId', ({params: {passwordId}}) => {
db.query(`DELETE FROM passwords WHERE id = ?;`).run(passwordId);
"deleted password"
}) })
export default adminController export default adminController

Binary file not shown.

View File

@ -1,9 +1,41 @@
import {Elysia} from 'elysia' import {Elysia} from 'elysia'
import userController from './User/Controller' import userController from './User/Controller'
import adminController from './admin/Controller' import adminController from './admin/Controller'
import passwordController from './password/Controller'
import type { User } from './interfaces/user_interface'
import db from './Database'
import { cors } from '@elysiajs/cors'
const app = new Elysia() const app = new Elysia()
.get('/', () => "Hello") .derive(async ({ headers }) => {
const auth = headers['authorization']
if (!auth) {
return {}
}
const bearer = auth?.startsWith('Bearer ') ? auth.slice(7) : null
const msg = db.query(`select users.id, users.name, users.administrator from users JOIN tokens ON users.id = tokens.user_id WHERE tokens.token = ?;`)
.get(bearer)
console.log(msg)
if(msg == null) {
throw new Response("Invalid token", { status: 401 })
return {}
}
const user: User = {
id: msg.id,
username: msg.username,
name: msg.name,
admin: msg.administrator
}
return { user }
// return user here instead of bearer
})
.get('/', ({ user }) => user)
.group('/user', (app) => app.use(userController)) .group('/user', (app) => app.use(userController))
.group('/admin', (app) => app.use(adminController)) .group('/admin', (app) => app.use(adminController))
.group('/password', (app) => app.use(passwordController))
.use(cors())
.listen(3000) .listen(3000)

View File

@ -0,0 +1,7 @@
export type User = {
id: number,
name: string,
username: string,
password?: string,
admin: boolean,
}

View File

@ -9,6 +9,7 @@
"typescript": "^5.0.0" "typescript": "^5.0.0"
}, },
"dependencies": { "dependencies": {
"@elysiajs/cors": "^1.1.1",
"elysia": "^1.1.12", "elysia": "^1.1.12",
"kysely": "^0.27.4", "kysely": "^0.27.4",
"nanoid": "^5.0.7", "nanoid": "^5.0.7",

View File

@ -0,0 +1,44 @@
import { Elysia } from 'elysia'
import db from '../Database'
const passwordController = new Elysia()
.get('/', ({ user }) => {
const userGroup = db.query(`SELECT groups.GroupId, groups.GroupName FROM groups JOIN userGroups ON groups.GroupID = userGroups.GroupID JOIN users ON userGroups.UserID = users.id WHERE users.id = ?;`)
.all(user.id);
return userGroup
})
.get('/:groupId', ({params: {groupId}}) => {
// make sure user has access to group
const passwords = db.query(`SELECT id, name, password, created_by, created_at from passwords WHERE group_id = ?;`)
.all(groupId);
console.log(passwords)
return passwords
})
.post('/:groupId', async({params: {groupId}, body, user}) => {
const passName = body.name;
const password = body.password
if (!passName || passName.trim() === "") {
return new Response("Name must be defined", { status: 400 });
}
const userGroup = db.query(`SELECT 1 FROM userGroups WHERE userID = ? AND groupID = ?;`)
.get(user.id, groupId);
if (!userGroup) {
return new Response("Forbidden: You do not have access to this group", { status: 403 });
}
db.query(`INSERT INTO passwords (name, password, group_id, created_by) VALUES (?, ?, ?, ?);`).run(body.name, body.password, groupId, user.name);
return new Response("Password created successfully", { status: 201 });
})
.delete('/:passwordId', ({params: {passwordId}}) => {
db.query(`DELETE FROM users WHERE id = ?;`).run(userId);
"deleted password"
})
export default passwordController

View File

View File

@ -0,0 +1,51 @@
import { SmtpClient } from 'smtp'
import config from "../email_config.json" assert { type: "json" };
const client = new SmtpClient();
export async function SendVerificationMail(userEmail: string, name: string, companyName: string, verificationToken: string) {
try {
await client.connect({
hostname: config.smtp_server,
port: config.smtp_port,
username: config.smtp_username,
password: config.smtp_password,
});
await client.send({
from: "PasswordBox <no-reply@passwordbox.dk>",
to: userEmail,
subject: "=?utf-8?B?QmVrcsOmZnQgZGluIGUtbWFpbC1hZHJlc3Nl?=",
content: `Kære ${name},<br><br>Velkommen til vores interne password manager PasswordBox. For at fuldføre oprettelsesprocessen skal du bekræfte din e-mail-adresse ved at klikke på nedenstående link:<br><br><a href="https://passwordbox.dk/verify?token=${verificationToken}">https://passwordbox.dk/verify?token=${verificationToken}</a><br><br>Hvis du ikke vil tilmeldes vores tjeneste, kan du blot ignorere denne e-mail.<br><br>Med venlig hilsen,<br>PasswordBox<br><br><i>Denne e-mail kan ikke besvares</i>`,
});
} catch {
return error("Kunne ikke sende mail!");
} finally {
await client.close();
}
return ok(undefined)
}
export async function SendForgotPasswordMail(userEmail: string, name: string, verificationToken: string) {
try {
await client.connect({
hostname: config.smtp_server,
port: config.smtp_port,
username: config.smtp_username,
password: config.smtp_password,
});
await client.send({
from: "PasswordBox <no-reply@passwordbox.dk>",
to: userEmail,
subject: "PasswordBox - Glemt adgangskode",
content: `Hej ${name},<br><br><b>Der er blevet anmodet et password reset.</b><br> Klik på følgende link for at nulstille din adgangskode:<br><br><a href="https://passwordbox.dk/verify?token=${verificationToken}">https://passwordbox.dk/verify?token=${verificationToken}</a><br><br>Hvis du ikke har glemt din adgangskode, kan du blot ignorere denne e-mail.<br><br>Med venlig hilsen,<br>PasswordBox<br><br><i>Denne e-mail kan ikke besvares</i>`,
});
} catch {
return error("Kunne ikke sende mail!");
} finally {
await client.close();
}
return ok(undefined)
}