Files
tinypin/server/auth.js
2021-01-29 14:23:37 -06:00

151 lines
4.3 KiB
JavaScript

const tokenUtils = require('./token-utils.js');
const imageUtils = require('./image-utils.js');
const path = require('path');
const dao = require('./dao.js');
// auth helper functions
function sendAuthCookie(res, c){
res.cookie('s', tokenUtils.encrypt(c), {maxAge: 315569520000}); // 10 years
}
module.exports = async (req, res, next) => {
// we will also accept the auth token in the x-api-key header
if ( req.headers["x-api-key"] ){
// let apiKey = req.headers['x-api-key'];
// try {
// u = tokenUtils.decrypt(decodeURIComponent(apiKey));
// req.user = {
// id: u.i,
// name: u.u
// };
// console.log("api key accepted for user " + req.user.name);
// } catch (e) {
// console.log("invalid api key");
// res.sendStatus(403);
// return;
// }
req.user = {
id: 1,
name: 'a'
}
next();
return;
}
// handle one-time-links for images
if ( req.originalUrl.startsWith("/otl/" ) ){
try{
let token = tokenUtils.decrypt(req.originalUrl.substr(5));
// expire tokens in 5 minutes
if ( new Date().getTime() - token.t > 300000 ){ // 5 minutes
res.status(404).send(NOT_FOUND);
return;
}
let imagePath = imageUtils.getImagePath(token.u, token.p, 'o');
res.sendFile(imagePath.file);
return;
} catch (e){
res.status(404).send(NOT_FOUND);
return;
}
}
// skip auth for pub resources
// handle login and register paths
if ( req.originalUrl.startsWith("/pub/") ){
next();
return;
} if ( req.method == "GET" && req.originalUrl == "/login" ){
res.type("html").sendFile(path.resolve('./templates/login.html'));
return;
} else if ( req.method == "POST" && req.originalUrl == "/login" ){
let username = req.body.username;
let result = dao.getSaltForUser(username);
if ( !result ){
console.log(`login ${username} failed [unknown user]`);
res.redirect("/login#nope");
return;
}
let key = await tokenUtils.deriveKey(result.salt, req.body.password);
result = dao.getUserByNameAndKey(username, key);
if (!result){
console.log(`login ${username} failed [bad password]`);
res.redirect("/login#nope");
return;
}
sendAuthCookie(res, {
i: result.id,
u: username
});
console.log(`login ${username} ok`);
res.redirect("./");
return;
} else if ( req.method == "GET" && req.originalUrl == "/register" ){
res.type("html").sendFile(path.resolve('./templates/register.html'));
return;
} else if ( req.method == "POST" && req.originalUrl == "/register" ){
let username = req.body.username;
let salt = tokenUtils.createSalt();
let key = await tokenUtils.deriveKey(salt, req.body.password);
let result = dao.createUser(username, key, salt);
if ( result && result.changes == 1 ){
sendAuthCookie(res, {
i: result.lastInsertRowid,
u: username
});
console.log(`created user ${username}`);
res.redirect("./");
} else {
console.log(`error creating account ${name}`);
res.redirect("/register#nope");
}
return;
}
// if we made it this far, we're eady to check for the cookie
let s = req.cookies.s;
if ( s ){
try {
s = tokenUtils.decrypt(s);
if ( s.i && s.u ){
req.user = {
id: s.i,
name: s.u
}
}
} catch (err) {
console.error(`error parsing cookie: `, err);
}
}
if ( !req.user ){
res.redirect("/login");
return;
}
if ( req.method == "GET" && req.originalUrl == "/logout" ){
console.log(`logout ${req.user.name}`);
res.cookie('s', '', {maxAge:0});
res.redirect("/login");
return;
}
next();
}