Files
cloudron-box/src/tokens.js
T

130 lines
4.0 KiB
JavaScript
Raw Normal View History

2020-02-06 16:57:33 +01:00
'use strict';
exports = module.exports = {
2021-03-15 12:47:57 -07:00
add,
get,
update,
del,
2021-06-04 09:28:40 -07:00
delByAccessToken,
delExpired,
delByUserIdAndType,
2021-06-04 09:28:40 -07:00
listByUserId,
2021-03-15 12:47:57 -07:00
getByAccessToken,
2020-02-06 16:57:33 +01:00
2021-03-15 12:47:57 -07:00
validateTokenType,
2020-02-06 16:57:33 +01:00
// token client ids. we categorize them so we can have different restrictions based on the client
ID_WEBADMIN: 'cid-webadmin', // dashboard
2020-02-06 16:57:33 +01:00
ID_SDK: 'cid-sdk', // created by user via dashboard
};
2021-06-04 09:28:40 -07:00
const TOKENS_FIELDS = [ 'id', 'accessToken', 'identifier', 'clientId', 'scope', 'expires', 'name', 'lastUsedTime' ].join(',');
const assert = require('assert'),
2020-02-06 16:57:33 +01:00
BoxError = require('./boxerror.js'),
2021-06-04 09:28:40 -07:00
database = require('./database.js'),
2020-02-06 16:57:33 +01:00
hat = require('./hat.js'),
2021-06-04 09:28:40 -07:00
uuid = require('uuid');
2020-02-06 16:57:33 +01:00
function validateTokenName(name) {
assert.strictEqual(typeof name, 'string');
2022-02-07 13:19:59 -08:00
if (name.length > 64) return new BoxError(BoxError.BAD_FIELD, 'name too long');
2020-02-06 16:57:33 +01:00
return null;
}
function validateTokenType(type) {
2020-02-07 23:12:53 +01:00
assert.strictEqual(typeof type, 'string');
2021-09-17 15:21:56 -07:00
const types = [ exports.ID_WEBADMIN, exports.ID_SDK ];
if (types.indexOf(type) === -1) return BoxError(BoxError.BAD_FIELD, `type must be one of ${types.join(',')}`);
return null;
}
2021-06-04 09:28:40 -07:00
async function add(token) {
assert.strictEqual(typeof token, 'object');
const { clientId, identifier, expires } = token;
const name = token.name || '';
const error = validateTokenName(name);
if (error) throw error;
const id = 'tid-' + uuid.v4();
const accessToken = hat(8 * 32);
const scope = 'unused';
await database.query('INSERT INTO tokens (id, accessToken, identifier, clientId, expires, scope, name) VALUES (?, ?, ?, ?, ?, ?, ?)', [ id, accessToken, identifier, clientId, expires, scope, name ]);
return { id, accessToken, scope, clientId, identifier, expires, name };
2020-02-06 16:57:33 +01:00
}
2020-02-07 16:20:05 +01:00
2021-06-04 09:28:40 -07:00
async function get(id) {
2020-02-07 16:20:05 +01:00
assert.strictEqual(typeof id, 'string');
2021-06-04 09:28:40 -07:00
const result = await database.query(`SELECT ${TOKENS_FIELDS} FROM tokens WHERE id = ?`, [ id ]);
if (result.length === 0) return null;
2020-02-07 16:20:05 +01:00
2021-06-04 09:28:40 -07:00
return result[0];
2020-02-07 16:20:05 +01:00
}
2021-06-04 09:28:40 -07:00
async function del(id) {
2020-02-07 16:20:05 +01:00
assert.strictEqual(typeof id, 'string');
2021-06-04 09:28:40 -07:00
const result = await database.query('DELETE FROM tokens WHERE id = ?', [ id ]);
if (result.affectedRows !== 1) throw new BoxError(BoxError.NOT_FOUND, 'Token not found');
2020-02-07 16:20:05 +01:00
}
2021-06-04 09:28:40 -07:00
async function listByUserId(userId) {
2020-02-07 16:20:05 +01:00
assert.strictEqual(typeof userId, 'string');
2021-06-04 09:28:40 -07:00
return await database.query(`SELECT ${TOKENS_FIELDS} FROM tokens WHERE identifier = ?`, [ userId ]);
}
async function getByAccessToken(accessToken) {
assert.strictEqual(typeof accessToken, 'string');
2020-02-07 16:20:05 +01:00
2021-06-04 09:28:40 -07:00
const result = await database.query('SELECT ' + TOKENS_FIELDS + ' FROM tokens WHERE accessToken = ? AND expires > ?', [ accessToken, Date.now() ]);
if (result.length === 0) return null;
return result[0];
2020-02-07 16:20:05 +01:00
}
2021-03-15 12:47:57 -07:00
2021-06-04 09:28:40 -07:00
async function delByAccessToken(accessToken) {
assert.strictEqual(typeof accessToken, 'string');
2021-03-15 12:47:57 -07:00
2021-06-04 09:28:40 -07:00
const result = await database.query('DELETE FROM tokens WHERE accessToken = ?', [ accessToken ]);
if (result.affectedRows !== 1) throw new BoxError(BoxError.NOT_FOUND, 'Token not found');
}
2021-03-15 12:47:57 -07:00
2021-06-04 09:28:40 -07:00
async function delExpired() {
const result = await database.query('DELETE FROM tokens WHERE expires <= ?', [ Date.now() ]);
return result.affectedRows;
2021-03-15 12:47:57 -07:00
}
async function delByUserIdAndType(userId, type) {
assert.strictEqual(typeof userId, 'string');
assert.strictEqual(typeof type, 'string');
const result = await database.query('DELETE FROM tokens WHERE identifier=? AND clientId=?', [ userId, type ]);
return result.affectedRows;
}
2021-06-04 09:28:40 -07:00
async function update(id, values) {
2021-03-15 12:47:57 -07:00
assert.strictEqual(typeof id, 'string');
assert.strictEqual(typeof values, 'object');
2021-06-04 09:28:40 -07:00
let args = [ ];
let fields = [ ];
for (let k in values) {
fields.push(k + ' = ?');
args.push(values[k]);
}
args.push(id);
const result = await database.query('UPDATE tokens SET ' + fields.join(', ') + ' WHERE id = ?', args);
if (result.affectedRows !== 1) throw new BoxError(BoxError.NOT_FOUND, 'Token not found');
}