89 lines
3.0 KiB
JavaScript
89 lines
3.0 KiB
JavaScript
'use strict';
|
|
|
|
exports = module.exports = {
|
|
get,
|
|
add,
|
|
list,
|
|
del,
|
|
|
|
removePrivateFields
|
|
};
|
|
|
|
const assert = require('assert'),
|
|
BoxError = require('./boxerror.js'),
|
|
crypto = require('crypto'),
|
|
database = require('./database.js'),
|
|
hat = require('./hat.js'),
|
|
safe = require('safetydance'),
|
|
uuid = require('uuid'),
|
|
_ = require('underscore');
|
|
|
|
const APP_PASSWORD_FIELDS = [ 'id', 'name', 'userId', 'identifier', 'hashedPassword', 'creationTime' ].join(',');
|
|
|
|
function validateAppPasswordName(name) {
|
|
assert.strictEqual(typeof name, 'string');
|
|
|
|
if (name.length < 1) return new BoxError(BoxError.BAD_FIELD, 'name must be atleast 1 char');
|
|
if (name.length >= 200) return new BoxError(BoxError.BAD_FIELD, 'name too long');
|
|
|
|
return null;
|
|
}
|
|
|
|
function removePrivateFields(appPassword) {
|
|
return _.pick(appPassword, 'id', 'name', 'userId', 'identifier', 'creationTime');
|
|
}
|
|
|
|
async function get(id) {
|
|
assert.strictEqual(typeof id, 'string');
|
|
|
|
const result = await database.query('SELECT ' + APP_PASSWORD_FIELDS + ' FROM appPasswords WHERE id = ?', [ id ]);
|
|
if (result.length === 0) return null;
|
|
return result[0];
|
|
}
|
|
|
|
async function add(userId, identifier, name) {
|
|
assert.strictEqual(typeof userId, 'string');
|
|
assert.strictEqual(typeof identifier, 'string');
|
|
assert.strictEqual(typeof name, 'string');
|
|
|
|
let error = validateAppPasswordName(name);
|
|
if (error) throw error;
|
|
|
|
if (identifier.length < 1) throw new BoxError(BoxError.BAD_FIELD, 'identifier must be atleast 1 char');
|
|
|
|
const password = hat(16 * 4);
|
|
const hashedPassword = crypto.createHash('sha256').update(password).digest('base64');
|
|
|
|
const appPassword = {
|
|
id: 'uid-' + uuid.v4(),
|
|
name,
|
|
userId,
|
|
identifier,
|
|
password,
|
|
hashedPassword
|
|
};
|
|
|
|
const query = 'INSERT INTO appPasswords (id, userId, identifier, name, hashedPassword) VALUES (?, ?, ?, ?, ?)';
|
|
const args = [ appPassword.id, appPassword.userId, appPassword.identifier, appPassword.name, appPassword.hashedPassword ];
|
|
|
|
[error] = await safe(database.query(query, args));
|
|
if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('appPasswords_name_userId_identifier') !== -1) throw new BoxError(BoxError.ALREADY_EXISTS, 'name/app combination already exists');
|
|
if (error && error.code === 'ER_NO_REFERENCED_ROW_2' && error.sqlMessage.indexOf('userId')) throw new BoxError(BoxError.NOT_FOUND, 'user not found');
|
|
if (error) throw error;
|
|
|
|
return { id: appPassword.id, password: appPassword.password };
|
|
}
|
|
|
|
async function list(userId) {
|
|
assert.strictEqual(typeof userId, 'string');
|
|
|
|
return await database.query('SELECT ' + APP_PASSWORD_FIELDS + ' FROM appPasswords WHERE userId = ?', [ userId ]);
|
|
}
|
|
|
|
async function del(id) {
|
|
assert.strictEqual(typeof id, 'string');
|
|
|
|
const result = await database.query('DELETE FROM appPasswords WHERE id = ?', [ id ]);
|
|
if (result.affectedRows !== 1) throw new BoxError(BoxError.NOT_FOUND, 'password not found');
|
|
}
|