UNPKG

@windingtree/wt-write-api

Version:

API to write data to the Winding Tree platform

132 lines (118 loc) 3.22 kB
/* eslint-disable camelcase */ const crypto = require('crypto'); const { db } = require('../config'); const { validateWallet, validateUploaders } = require('../services/validators'); const TABLE = 'accounts'; module.exports.createTable = async function () { await db.schema.createTable(TABLE, (table) => { table.string('id').primary(); table.string('access_key').unique().notNullable(); // Hashed access key. table.string('wallet', 1023); table.string('uploaders', 1023); table.timestamps(true, true); }); }; module.exports.dropTable = async function () { await db.schema.dropTableIfExists(TABLE); }; async function _generateRandomString (bytesCnt, encoding) { return new Promise((resolve, reject) => { crypto.randomBytes(bytesCnt, (err, buffer) => { if (err) { return reject(err); } resolve(buffer.toString(encoding)); }); }); } /** * Generate a new secret key. */ async function _generateKey () { return _generateRandomString(32, 'base64'); } /** * Generate a random account ID. */ async function _generateID () { return _generateRandomString(8, 'hex'); } /** * Return a secure hash of the access key. * * Since access keys are long, randomly generated strings, we do * not need to use pbdkf2 nor salts. */ function _hashKey (accessKey) { const hash = crypto.createHash('sha256'); return hash.update(accessKey).digest('hex'); } const VALIDATED_FIELDS = [ { name: 'wallet', validator: validateWallet }, { name: 'uploaders', validator: validateUploaders }, ]; /** * Validate the given account data. */ function _validate (accountData) { for (const field of VALIDATED_FIELDS) { field.validator(accountData[field.name]); } } /** * Create a new account and return its ID and secret key. * * @param {Object} accountData * @return {Promise<Object>} */ module.exports.create = async function (accountData) { _validate(accountData); const accessKey = await _generateKey(), id = await _generateID(); await db(TABLE).insert({ id: id, wallet: JSON.stringify(accountData.wallet), uploaders: JSON.stringify(accountData.uploaders), access_key: _hashKey(accessKey), }); return { id, accessKey }; }; /** * Overwrite an existing account with new data. * * @param {Object} accountData * @return {Promise<void>} */ module.exports.update = async function (id, accountData) { _validate(accountData); await db(TABLE).where('id', id).update({ wallet: JSON.stringify(accountData.wallet), uploaders: JSON.stringify(accountData.uploaders), updated_at: db.fn.now(), }); }; /** * Get an account by access key. * * @param {String} accessKey * @return {Promise<Object>} */ module.exports.getByKey = async function (accessKey) { const account = (await db(TABLE).select('id', 'uploaders', 'wallet').where({ access_key: _hashKey(accessKey), }))[0]; return account && { id: account.id, wallet: JSON.parse(account.wallet), uploaders: JSON.parse(account.uploaders), }; }; /** * Delete an account by ID. * * @param {String} accessKey * @return {Promise<void>} */ module.exports.delete = async function (id) { await db(TABLE).where('id', id).delete(); };