smc-hub
Version:
CoCalc: Backend webserver component
160 lines (148 loc) • 4.76 kB
JavaScript
// Generated by CoffeeScript 2.5.1
(function() {
//########################################################################
// This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
// License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
//########################################################################
/*
Temporary authentication token for user.
*/
var BAN_TIME_MS, async, auth, ban, defaults, misc, random_key, required, types;
async = require('async');
random_key = require("random-key");
misc = require('smc-util/misc');
({defaults, types, required} = misc);
auth = require('./auth');
// map {account_id:{user_account_id:timestamp}}
ban = {};
BAN_TIME_MS = 1000 * 60;
exports.get_user_auth_token = function(opts) {
var auth_token, b, is_admin, is_lti, ref;
opts = defaults(opts, { // temporary until types is more than just a WARNING
database: required,
account_id: required,
user_account_id: required,
password: required, // admin can get token by using password = ''.
lti: false, // LTI auth mode
cb: required
});
types(opts, {
database: types.object.isRequired,
account_id: types.string.isRequired,
user_account_id: types.string.isRequired,
password: types.string.isRequired,
lti: types.bool, // LTI auth mode
cb: types.func.isRequired // cb(err, auth_token)
});
auth_token = void 0;
b = (ref = ban[opts.account_id]) != null ? ref[opts.user_account_id] : void 0;
if ((b != null) && (new Date() - b < BAN_TIME_MS)) {
opts.cb(`banned -- please wait at least ${BAN_TIME_MS / 1000}s before trying again`);
return;
}
is_admin = false;
is_lti = false;
return async.series([
function(cb) {
if (opts.password !== '') {
is_admin = false;
cb();
return;
}
if (!opts.lti) {
// must be an admin or NOPE.
return opts.database.is_admin({
account_id: opts.account_id,
cb: (err,
_is_admin) => {
is_admin = _is_admin;
return cb(err);
}
});
} else {
// must have an lti_id
return opts.database.get_account({
account_id: opts.account_id,
columns: ["lti_id"],
cb: (err,
lti_id) => {
is_lti = !!lti_id;
return cb(err);
}
});
}
},
function(cb) {
if ((is_admin || is_lti) && opts.password === '') {
// no need to do anything further
cb();
return;
}
// confirm auth
return auth.is_password_correct({
database: opts.database,
account_id: opts.user_account_id,
password: opts.password,
allow_empty_password: false, // user must have a password
cb: function(err,
is_correct) {
var name;
if (err) {
return cb(err);
} else if (!is_correct) {
// ban opts.account_id from attempting again for 1 minute (say)
b = ban[name = opts.account_id] != null ? ban[name] : ban[name] = {};
b[opts.user_account_id] = new Date();
return cb("incorrect password");
} else {
return cb();
}
}
});
},
function(cb) {
// generate token
auth_token = random_key.generate(24);
// save in db
return opts.database.save_auth_token({
account_id: opts.user_account_id,
auth_token: auth_token,
ttl: 12 * 3600, // ttl in seconds (12 hours)
cb: cb
});
},
function(cb) {
// log that we created an auth_token for an account...
// just in case (this is entirely a security thing)
return opts.database.log({
event: 'get_user_auth_token',
value: {
account_id: opts.account_id,
user_account_id: opts.user_account_id,
is_admin: is_admin
},
cb: cb
});
}
], function(err) {
return opts.cb(err, auth_token);
});
};
exports.revoke_user_auth_token = function(opts) {
opts = defaults(opts, {
database: required,
auth_token: required,
cb: required
});
types(opts, {
database: types.object.isRequired,
auth_token: types.string.isRequired,
cb: types.func.isRequired // cb(err, auth_token)
});
return opts.database.delete_auth_token({
auth_token: opts.auth_token,
cb: cb
});
};
}).call(this);
//# sourceMappingURL=auth-token.js.map