/* jslint node:true */ 'use strict'; exports = module.exports = { get, set, del, initSecrets, ACME_ACCOUNT_KEY: 'acme_account_key', ADDON_TURN_SECRET: 'addon_turn_secret', DHPARAMS: 'dhparams', SFTP_PUBLIC_KEY: 'sftp_public_key', SFTP_PRIVATE_KEY: 'sftp_private_key', CERT_PREFIX: 'cert', _clear: clear }; const assert = require('assert'), BoxError = require('./boxerror.js'), constants = require('./constants.js'), crypto = require('crypto'), database = require('./database.js'), debug = require('debug')('box:blobs'), paths = require('./paths.js'), safe = require('safetydance'); const BLOBS_FIELDS = [ 'id', 'value' ].join(','); async function get(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; } async function set(id, value) { assert.strictEqual(typeof id, 'string'); assert(value === null || Buffer.isBuffer(value)); await database.query('INSERT INTO blobs (id, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value=VALUES(value)', [ id, value ]); } async function del(id) { await database.query('DELETE FROM blobs WHERE id=?', [ id ]); } async function clear() { await database.query('DELETE FROM blobs'); } async function initSecrets() { let acmeAccountKey = await get(exports.ACME_ACCOUNT_KEY); if (!acmeAccountKey) { acmeAccountKey = safe.child_process.execSync('openssl genrsa 4096'); if (!acmeAccountKey) throw new BoxError(BoxError.OPENSSL_ERROR, `Could not generate acme account key: ${safe.error.message}`); await set(exports.ACME_ACCOUNT_KEY, acmeAccountKey); } let turnSecret = await get(exports.ADDON_TURN_SECRET); if (!turnSecret) { turnSecret = 'a' + crypto.randomBytes(15).toString('hex'); // prefix with a to ensure string starts with a letter await set(exports.ADDON_TURN_SECRET, Buffer.from(turnSecret)); } if (!constants.TEST) { let dhparams = await get(exports.DHPARAMS); if (!dhparams) { debug('initSecrets: generating dhparams.pem. this takes forever'); dhparams = safe.child_process.execSync('openssl dhparam 2048'); if (!dhparams) throw new BoxError(BoxError.OPENSSL_ERROR, safe.error); if (!safe.fs.writeFileSync(paths.DHPARAMS_FILE, dhparams)) throw new BoxError(BoxError.FS_ERROR, `Could not save dhparams.pem: ${safe.error.message}`); await set(exports.DHPARAMS, dhparams); } else if (!safe.fs.existsSync(paths.DHPARAMS_FILE)) { if (!safe.fs.writeFileSync(paths.DHPARAMS_FILE, dhparams)) throw new BoxError(BoxError.FS_ERROR, `Could not save dhparams.pem: ${safe.error.message}`); } } let sftpPrivateKey = await get(exports.SFTP_PRIVATE_KEY); let sftpPublicKey = await get(exports.SFTP_PUBLIC_KEY); if (!sftpPrivateKey || !sftpPublicKey) { debug('initSecrets: generate sftp keys'); if (constants.TEST) { safe.fs.unlinkSync(paths.SFTP_PUBLIC_KEY_FILE); safe.fs.unlinkSync(paths.SFTP_PRIVATE_KEY_FILE); } if (!safe.child_process.execSync(`ssh-keygen -m PEM -t rsa -f "${paths.SFTP_KEYS_DIR}/ssh_host_rsa_key" -q -N ""`)) throw new BoxError(BoxError.OPENSSL_ERROR, `Could not generate sftp ssh keys: ${safe.error.message}`); sftpPublicKey = safe.fs.readFileSync(paths.SFTP_PUBLIC_KEY_FILE); await set(exports.SFTP_PUBLIC_KEY, sftpPublicKey); sftpPrivateKey = safe.fs.readFileSync(paths.SFTP_PRIVATE_KEY_FILE); await set(exports.SFTP_PRIVATE_KEY, sftpPrivateKey); } else if (!safe.fs.existsSync(paths.SFTP_PUBLIC_KEY_FILE) || !safe.fs.existsSync(paths.SFTP_PRIVATE_KEY_FILE)) { if (!safe.fs.writeFileSync(paths.SFTP_PUBLIC_KEY_FILE, sftpPublicKey)) throw new BoxError(BoxError.FS_ERROR, `Could not save sftp public key: ${safe.error.message}`); if (!safe.fs.writeFileSync(paths.SFTP_PRIVATE_KEY_FILE, sftpPrivateKey)) throw new BoxError(BoxError.FS_ERROR, `Could not save sftp private key: ${safe.error.message}`); } }