/* eslint require-jsdoc: off */

'use strict';

let crypto = require('crypto');
let crypt3 = require('./crypt3');
let md5 = require('apache-md5');
let locker = require('@verdaccio/file-locking');

// this function neither unlocks file nor closes it
// it'll have to be done manually later
function lock_and_read(name, cb) {
  locker.readFile(name, {lock: true}, function(err, res) {
    if (err) {
      return cb(err);
    }
    return cb(null, res);
  });
}

// close and unlock file
function unlock_file(name, cb) {
  locker.unlockFile(name, cb);
}

function parse_htpasswd(input) {
  let result = {};
  input.split('\n').forEach(function(line) {
    let args = line.split(':', 3);
    if (args.length > 1) result[args[0]] = args[1];
  });
  return result;
}

function verify_password(user, passwd, hash) {
  if (hash.indexOf('{PLAIN}') === 0) {
    return passwd === hash.substr(7);
  } else if (hash.indexOf('{SHA}') === 0) {
    return crypto.createHash('sha1').update(passwd, 'binary').digest('base64') === hash.substr(5);
  } else {
    return (
      // for backwards compatibility, first check md5 then check crypt3
      md5(passwd, hash) === hash ||
      crypt3(passwd, hash) === hash
    );
  }
}

function add_user_to_htpasswd(body, user, passwd) {
  if (user !== encodeURIComponent(user)) {
    let err = Error('username should not contain non-uri-safe characters');
    err.status = 409;
    throw err;
  }

  if (crypt3) {
    passwd = crypt3(passwd);
  } else {
    passwd = '{SHA}' + crypto.createHash('sha1').update(passwd, 'binary').digest('base64');
  }
  let comment = 'autocreated ' + (new Date()).toJSON();

  let newline = user + ':' + passwd + ':' + comment + '\n';
  if (body.length && body[body.length-1] !== '\n') newline = '\n' + newline;
  return body + newline;
}

module.exports.parse_htpasswd = parse_htpasswd;
module.exports.verify_password = verify_password;
module.exports.add_user_to_htpasswd = add_user_to_htpasswd;
module.exports.lock_and_read = lock_and_read;
module.exports.unlock_file = unlock_file;
