actual-server/app-account.js
2022-05-20 09:24:19 -04:00

116 lines
3.1 KiB
JavaScript

let express = require('express');
let bcrypt = require('bcrypt');
let uuid = require('uuid');
let errorMiddleware = require('./util/error-middleware');
let { validateUser } = require('./util/validate-user');
let { getAccountDb } = require('./account-db');
let app = express();
app.use(errorMiddleware);
function init() {
// eslint-disable-previous-line @typescript-eslint/no-empty-function
}
function hashPassword(password) {
return bcrypt.hashSync(password, 12);
}
// Non-authenticated endpoints:
//
// /boostrap (special endpoint for setting up the instance, cant call again)
// /login
app.get('/needs-bootstrap', (req, res) => {
let accountDb = getAccountDb();
let rows = accountDb.all('SELECT * FROM auth');
res.send({
status: 'ok',
data: { bootstrapped: rows.length > 0 }
});
});
app.post('/bootstrap', (req, res) => {
let { password } = req.body;
let accountDb = getAccountDb();
let rows = accountDb.all('SELECT * FROM auth');
if (rows.length !== 0) {
res.status(400).send({
status: 'error',
reason: 'already-bootstrapped'
});
return;
}
if (password == null || password === '') {
res.status(400).send({ status: 'error', reason: 'invalid-password' });
return;
}
// Hash the password. There's really not a strong need for this
// since this is a self-hosted instance owned by the user.
// However, just in case we do it.
let hashed = hashPassword(password);
accountDb.mutate('INSERT INTO auth (password) VALUES (?)', [hashed]);
let token = uuid.v4();
accountDb.mutate('INSERT INTO sessions (token) VALUES (?)', [token]);
res.send({ status: 'ok', data: { token } });
});
app.post('/login', (req, res) => {
let { password } = req.body;
let accountDb = getAccountDb();
let row = accountDb.first('SELECT * FROM auth');
let confirmed = row && bcrypt.compareSync(password, row.password);
let token = null;
if (confirmed) {
// Right now, tokens are permanent and there's just one in the
// system. In the future this should probably evolve to be a
// "session" that times out after a long time or something, and
// maybe each device has a different token
let row = accountDb.first('SELECT * FROM sessions');
token = row.token;
}
res.send({ status: 'ok', data: { token } });
});
app.post('/change-password', (req, res) => {
let user = validateUser(req, res);
if (!user) return;
let accountDb = getAccountDb();
let { password } = req.body;
if (password == null || password === '') {
res.send({ status: 'error', reason: 'invalid-password' });
return;
}
let hashed = hashPassword(password);
// Note that this doesn't have a WHERE. This table only ever has 1
// row (maybe that will change in the future? if this this will not work)
accountDb.mutate('UPDATE auth SET password = ?', [hashed]);
res.send({ status: 'ok', data: {} });
});
app.get('/validate', (req, res) => {
let user = validateUser(req, res);
if (user) {
res.send({ status: 'ok', data: { validated: true } });
}
});
app.use(errorMiddleware);
module.exports.handlers = app;
module.exports.init = init;