Source: verificationHelper.js

const zeltrezjs = require('zeltrezjs');
const bitcoinMessage = require('bitcoinjs-message');
const { randomBytes } = require('crypto');

const log = require('../lib/log');

const verificationHelperUtils = require('./verificationHelperUtils');

/**
 * Verifies a specific privilege based on request headers.
 * @param {string} privilege - 'admin, 'fluxteam', 'adminandfluxteam', 'appownerabove', 'appowner', 'user'
 * @param {object} req
 * @param {string} appName
 *
 * @returns {Promise<boolean>} authorized
 */
async function verifyPrivilege(privilege, req, appName) {
  try {
    let authorized = false;
    switch (privilege) {
      case 'admin':
        authorized = await verificationHelperUtils.verifyAdminSession(req.headers);
        break;
      case 'fluxteam':
        authorized = await verificationHelperUtils.verifyFluxTeamSession(req.headers);
        break;
      case 'adminandfluxteam':
        authorized = await verificationHelperUtils.verifyAdminAndFluxTeamSession(req.headers);
        break;
      case 'appownerabove':
        authorized = await verificationHelperUtils.verifyAppOwnerOrHigherSession(req.headers, appName);
        break;
      case 'appowner':
        authorized = await verificationHelperUtils.verifyAppOwnerSession(req.headers, appName);
        break;
      case 'user':
        authorized = await verificationHelperUtils.verifyUserSession(req.headers);
        break;
      default:
        authorized = false;
        break;
    }
    return authorized;
  } catch (error) {
    log.error(error);
    return false;
  }
}

/**
 * Verifies ZelID, returns true if it's valid.
 *
 * @param {string} address
 * @returns {bool} isVaild
 */
function verifyZelID(address) {
  let isValid = false;
  try {
    if (!address) {
      throw new Error('Missing parameters for message verification');
    }

    if (!address.startsWith('1')) {
      throw new Error('Invalid zelID');
    }

    if (address.length > 36) {
      const btcPubKeyHash = '00';
      zeltrezjs.address.pubKeyToAddr(address, btcPubKeyHash);
    }
    isValid = true;
  } catch (e) {
    // log.error(e);  - the function is not used at the moment, commented out to clean up test logs
    isValid = e;
  }
  return isValid;
}

/**
 * Verifies if the message was properly signed.
 *
 * @param {object} message
 * @param {string} address
 * @param {string} signature
 * @param {string} strMessageMagic
 * @param {string} checkSegwitAlways
 *
 * @returns {bool} isValid
 */
function verifyMessage(message, address, signature, strMessageMagic, checkSegwitAlways) {
  let isValid = false;
  let signingAddress = address;
  try {
    if (!address || !message || !signature) {
      throw new Error('Missing parameters for message verification');
    }

    if (address.length > 36) {
      const btcPubKeyHash = '00';
      const sigAddress = zeltrezjs.address.pubKeyToAddr(address, btcPubKeyHash);
      signingAddress = sigAddress;
    }
    isValid = bitcoinMessage.verify(message, signingAddress, signature, strMessageMagic, checkSegwitAlways);
  } catch (e) {
    log.error(e);
    isValid = e;
  }
  return isValid;
}

/**
 * Signs the message with the private key.
 *
 * @param {object} message
 * @param {string} pk - private key
 *
 * @returns {string} signature
 */
function signMessage(message, pk) {
  let signature;
  try {
    const privateKey = zeltrezjs.address.WIFToPrivKey(pk);

    const isCompressed = !pk.startsWith('5');

    signature = bitcoinMessage.sign(message, Buffer.from(privateKey, 'hex'), isCompressed, { extraEntropy: randomBytes(32) });
    signature = signature.toString('base64');
    // => different (but valid) signature each time
  } catch (e) {
    log.error(e);
    signature = e;
  }
  return signature;
}

module.exports = {
  verifyPrivilege,
  verifyZelID,
  signMessage,
  verifyMessage,
};