Add basic login/logout logic

This commit is contained in:
Johannes Zellner
2020-02-04 14:35:25 +01:00
parent 57e3180737
commit 0ae9be4de9
3 changed files with 69 additions and 0 deletions
+52
View File
@@ -1,6 +1,8 @@
'use strict';
exports = module.exports = {
login: login,
logout: logout,
reboot: reboot,
isRebootRequired: isRebootRequired,
getConfig: getConfig,
@@ -22,16 +24,66 @@ let assert = require('assert'),
async = require('async'),
auditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
clients = require('../clients.js'),
cloudron = require('../cloudron.js'),
custom = require('../custom.js'),
externalLdap = require('../externalldap.js'),
HttpError = require('connect-lastmile').HttpError,
HttpSuccess = require('connect-lastmile').HttpSuccess,
passport = require('passport'),
speakeasy = require('speakeasy'),
sysinfo = require('../sysinfo.js'),
system = require('../system.js'),
tokendb = require('../tokendb.js'),
updater = require('../updater.js'),
updateChecker = require('../updatechecker.js');
function login(req, res, next) {
passport.authenticate('local', function (error, user) {
if (error) return next(new HttpError(500, error));
if (!user) return next(new HttpError(401, 'Invalid credentials'));
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || null;
if (!user.ghost && !user.appPassword && user.twoFactorAuthenticationEnabled) {
if (!req.body.totpToken) return next(new HttpError(401, 'A totpToken must be provided'));
let verified = speakeasy.totp.verify({ secret: user.twoFactorAuthenticationSecret, encoding: 'base32', token: req.body.totpToken, window: 2 });
if (!verified) return next(new HttpError(401, 'Invalid totpToken'));
}
const auditSource = { authType: 'cli', ip: ip };
clients.issueDeveloperToken(user, auditSource, function (error, result) {
if (error) return next(new HttpError(500, error));
next(new HttpSuccess(200, result));
});
})(req, res, next);
}
function logout(req, res) {
var token;
// this determines the priority
if (req.body && req.body.access_token) token = req.body.access_token;
if (req.query && req.query.access_token) token = req.query.access_token;
if (req.headers && req.headers.authorization) {
var parts = req.headers.authorization.split(' ');
if (parts.length == 2) {
var scheme = parts[0];
var credentials = parts[1];
if (/^Bearer$/i.test(scheme)) token = credentials;
}
}
if (!token) return res.redirect('/login.html');
tokendb.delByAccessToken(token, function () {
res.redirect('/index.html');
});
}
function reboot(req, res, next) {
// Finish the request, to let the appstore know we triggered the reboot
next(new HttpSuccess(202, {}));
+4
View File
@@ -139,6 +139,10 @@ function initializeExpressSync() {
router.get ('/api/v1/cloudron/avatar', routes.settings.getCloudronAvatar); // this is a public alias for /api/v1/settings/cloudron_avatar
// login/logout routes
router.post('/api/v1/cloudron/login', routes.cloudron.login);
router.get ('/api/v1/cloudron/logout', routes.cloudron.logout); // this will invalidate the token if any and redirect to /login.html always
// developer routes
router.post('/api/v1/developer/login', routes.developer.login);
+13
View File
@@ -5,6 +5,7 @@
exports = module.exports = {
get: get,
getByAccessToken: getByAccessToken,
delByAccessToken: delByAccessToken,
add: add,
del: del,
delByClientId: delByClientId,
@@ -35,6 +36,18 @@ function getByAccessToken(accessToken, callback) {
});
}
function delByAccessToken(accessToken, callback) {
assert.strictEqual(typeof accessToken, 'string');
assert.strictEqual(typeof callback, 'function');
database.query('DELETE FROM tokens WHERE accessToken = ?', [ accessToken ], function (error, result) {
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (result.affectedRows !== 1) return callback(new BoxError(BoxError.NOT_FOUND, 'Token not found'));
return callback(null);
});
}
function get(id, callback) {
assert.strictEqual(typeof id, 'string');
assert.strictEqual(typeof callback, 'function');