proxyAuth: persist the secret token
This commit is contained in:
@@ -4,13 +4,16 @@
|
||||
|
||||
exports = module.exports = {
|
||||
get,
|
||||
getString,
|
||||
set,
|
||||
setString,
|
||||
del,
|
||||
|
||||
ACME_ACCOUNT_KEY: 'acme_account_key',
|
||||
ADDON_TURN_SECRET: 'addon_turn_secret',
|
||||
SFTP_PUBLIC_KEY: 'sftp_public_key',
|
||||
SFTP_PRIVATE_KEY: 'sftp_private_key',
|
||||
PROXY_AUTH_TOKEN_SECRET: 'proxy_auth_token_secret',
|
||||
|
||||
CERT_PREFIX: 'cert',
|
||||
|
||||
@@ -30,6 +33,14 @@ async function get(id) {
|
||||
return result[0].value;
|
||||
}
|
||||
|
||||
async function getString(id) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
|
||||
const result = await database.query(`SELECT ${BLOBS_FIELDS} FROM blobs WHERE id = ?`, [ id ]);
|
||||
if (result.length === 0) return null;
|
||||
return result[0].value.toString('utf8');
|
||||
}
|
||||
|
||||
async function set(id, value) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert(value === null || Buffer.isBuffer(value));
|
||||
@@ -37,6 +48,13 @@ async function set(id, value) {
|
||||
await database.query('INSERT INTO blobs (id, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value=VALUES(value)', [ id, value ]);
|
||||
}
|
||||
|
||||
async function setString(id, value) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert(value === null || typeof value === 'string');
|
||||
|
||||
await database.query('INSERT INTO blobs (id, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value=VALUES(value)', [ id, Buffer.from(value) ]);
|
||||
}
|
||||
|
||||
async function del(id) {
|
||||
await database.query('DELETE FROM blobs WHERE id=?', [ id ]);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ exports = module.exports = {
|
||||
DYNDNS_INFO_FILE: path.join(baseDir(), 'platformdata/dyndns-info.json'),
|
||||
DHPARAMS_FILE: path.join(baseDir(), 'platformdata/dhparams.pem'),
|
||||
FEATURES_INFO_FILE: path.join(baseDir(), 'platformdata/features-info.json'),
|
||||
PROXY_AUTH_TOKEN_SECRET_FILE: path.join(baseDir(), 'platformdata/proxy-auth-token-secret'),
|
||||
VERSION_FILE: path.join(baseDir(), 'platformdata/VERSION'),
|
||||
SSHFS_KEYS_DIR: path.join(baseDir(), 'platformdata/sshfs'),
|
||||
SFTP_KEYS_DIR: path.join(baseDir(), 'platformdata/sftp/ssh'),
|
||||
|
||||
+13
-12
@@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const blobs = require('./blobs.js');
|
||||
|
||||
// heavily inspired from https://gock.net/blog/2020/nginx-subrequest-authentication-server/ and https://github.com/andygock/auth-server
|
||||
|
||||
exports = module.exports = {
|
||||
@@ -14,7 +16,6 @@ const apps = require('./apps.js'),
|
||||
debug = require('debug')('box:proxyAuth'),
|
||||
ejs = require('ejs'),
|
||||
express = require('express'),
|
||||
fs = require('fs'),
|
||||
hat = require('./hat.js'),
|
||||
http = require('http'),
|
||||
HttpError = require('connect-lastmile').HttpError,
|
||||
@@ -31,16 +32,16 @@ const apps = require('./apps.js'),
|
||||
util = require('util');
|
||||
|
||||
let gHttpServer = null;
|
||||
let TOKEN_SECRET = null;
|
||||
let gTokenSecret = null;
|
||||
|
||||
function jwtVerify(req, res, next) {
|
||||
const token = req.cookies.authToken;
|
||||
|
||||
if (!token) return next();
|
||||
|
||||
jwt.verify(token, TOKEN_SECRET, function (error, decoded) {
|
||||
jwt.verify(token, gTokenSecret, function (error, decoded) {
|
||||
if (error) {
|
||||
debug('clearing token', error);
|
||||
debug('jwtVerify: clearing token', error);
|
||||
res.clearCookie('authToken');
|
||||
return next(new HttpError(403, 'Malformed token or bad signature'));
|
||||
}
|
||||
@@ -95,7 +96,7 @@ async function loginPage(req, res, next) {
|
||||
try {
|
||||
finalContent = ejs.render(translatedContent, { title, icon, dashboardOrigin });
|
||||
} catch (e) {
|
||||
debug('Error rendering proxyauth-login.ejs', e);
|
||||
debug('loginPage: Error rendering proxyauth-login.ejs', e);
|
||||
return next(new HttpError(500, 'Login template error'));
|
||||
}
|
||||
|
||||
@@ -123,7 +124,7 @@ function auth(req, res, next) {
|
||||
}
|
||||
|
||||
// user is already authenticated, refresh cookie
|
||||
const token = jwt.sign({ user: req.user }, TOKEN_SECRET, { expiresIn: `${constants.DEFAULT_TOKEN_EXPIRATION_DAYS}d` });
|
||||
const token = jwt.sign({ user: req.user }, gTokenSecret, { expiresIn: `${constants.DEFAULT_TOKEN_EXPIRATION_DAYS}d` });
|
||||
|
||||
res.cookie('authToken', token, {
|
||||
httpOnly: true,
|
||||
@@ -171,7 +172,7 @@ async function authorize(req, res, next) {
|
||||
|
||||
if (!apps.canAccess(app, req.user)) return next(new HttpError(403, 'Forbidden' ));
|
||||
|
||||
const token = jwt.sign({ user: users.removePrivateFields(req.user) }, TOKEN_SECRET, { expiresIn: `${constants.DEFAULT_TOKEN_EXPIRATION_DAYS}d` });
|
||||
const token = jwt.sign({ user: users.removePrivateFields(req.user) }, gTokenSecret, { expiresIn: `${constants.DEFAULT_TOKEN_EXPIRATION_DAYS}d` });
|
||||
|
||||
res.cookie('authToken', token, {
|
||||
httpOnly: true,
|
||||
@@ -251,11 +252,11 @@ function initializeAuthwallExpressSync() {
|
||||
async function start() {
|
||||
assert.strictEqual(gHttpServer, null, 'Authwall is already up and running.');
|
||||
|
||||
if (!fs.existsSync(paths.PROXY_AUTH_TOKEN_SECRET_FILE)) {
|
||||
TOKEN_SECRET = hat(64);
|
||||
fs.writeFileSync(paths.PROXY_AUTH_TOKEN_SECRET_FILE, TOKEN_SECRET, 'utf8');
|
||||
} else {
|
||||
TOKEN_SECRET = fs.readFileSync(paths.PROXY_AUTH_TOKEN_SECRET_FILE, 'utf8').trim();
|
||||
gTokenSecret = await blobs.getString(blobs.PROXY_AUTH_TOKEN_SECRET);
|
||||
if (!gTokenSecret) {
|
||||
debug('start: generating new token secret');
|
||||
gTokenSecret = hat(64);
|
||||
await blobs.setString(blobs.PROXY_AUTH_TOKEN_SECRET, gTokenSecret);
|
||||
}
|
||||
|
||||
gHttpServer = initializeAuthwallExpressSync();
|
||||
|
||||
Reference in New Issue
Block a user