mostly because code is being autogenerated by all the AI stuff using this prefix. it's also used in the stack trace.
88 lines
3.0 KiB
JavaScript
88 lines
3.0 KiB
JavaScript
'use strict';
|
|
|
|
exports = module.exports = {
|
|
get,
|
|
add,
|
|
list,
|
|
del,
|
|
|
|
removePrivateFields
|
|
};
|
|
|
|
const assert = require('node:assert'),
|
|
BoxError = require('./boxerror.js'),
|
|
crypto = require('node:crypto'),
|
|
database = require('./database.js'),
|
|
hat = require('./hat.js'),
|
|
safe = require('safetydance'),
|
|
_ = require('./underscore.js');
|
|
|
|
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-' + crypto.randomUUID(),
|
|
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');
|
|
}
|