88 lines
2.7 KiB
JavaScript
88 lines
2.7 KiB
JavaScript
"use strict";
|
|
|
|
const fs = require("fs");
|
|
const os = require("os");
|
|
const resolve = require("path").resolve;
|
|
|
|
const AES = require("aes-js");
|
|
const scrypt = require("scrypt-js");
|
|
|
|
const prompt = require("../packages/cli/prompt");
|
|
const randomBytes = require("../packages/random").randomBytes;
|
|
const computeHmac = require("../packages/sha2").computeHmac;
|
|
|
|
const colorify = require("./log").colorify;
|
|
|
|
function getConfigFilename() {
|
|
return resolve(os.homedir(), ".ethers-dist");
|
|
}
|
|
|
|
function getScrypt(message, password, salt) {
|
|
let progressBar = prompt.getProgressBar(message);
|
|
return new Promise((resolve, reject) => {
|
|
scrypt(Buffer.from(password), Buffer.from(salt), (1 << 17), 8, 1, 64, (error, progress, key) => {
|
|
if (error) { return reject(error); }
|
|
progressBar(progress);
|
|
if (key) { resolve(key); }
|
|
});
|
|
});
|
|
}
|
|
|
|
async function loadConfig(dkey) {
|
|
let config = { };
|
|
|
|
let filename = getConfigFilename();
|
|
if (fs.existsSync(filename)) {
|
|
let data = JSON.parse(fs.readFileSync(filename));
|
|
let ciphertext = Buffer.from(data.ciphertext, "base64");
|
|
let iv = Buffer.from(data.iv, "base64");
|
|
let aes = new AES.ModeOfOperation.ctr(dkey.slice(0, 32), new AES.Counter(iv));
|
|
let plaintext = aes.decrypt(ciphertext);
|
|
let hmac = computeHmac("sha512", dkey.slice(32, 64), plaintext);
|
|
if (hmac !== data.hmac) {
|
|
throw new Error("wrong password");
|
|
}
|
|
config = JSON.parse(Buffer.from(plaintext).toString());
|
|
}
|
|
|
|
return config;
|
|
}
|
|
|
|
async function getConfig(key) {
|
|
let password = await prompt.getPassword(colorify("Password (seesion-store): ", "bold"));
|
|
let dkey = await getScrypt(colorify("Decrypting", "bold"), password, key);
|
|
|
|
let config = await loadConfig(dkey);
|
|
return config[key];
|
|
}
|
|
|
|
async function setConfig(key, value) {
|
|
let password = await prompt.getPassword(colorify("Password (seesion-store): ", "bold"));
|
|
let dkey = await getScrypt("Encrypting", password, key);
|
|
|
|
let config = await loadConfig(dkey);
|
|
config[key] = value;
|
|
config._junk = Buffer.from(randomBytes(16 + parseInt(Math.random() * 48))).toString("base64")
|
|
|
|
let plaintext = Buffer.from(JSON.stringify(config));
|
|
|
|
let iv = Buffer.from(randomBytes(16));
|
|
let hmac = computeHmac("sha512", dkey.slice(32, 64), plaintext);
|
|
|
|
let aes = new AES.ModeOfOperation.ctr(dkey.slice(0, 32), new AES.Counter(iv));
|
|
let ciphertext = Buffer.from(aes.encrypt(plaintext));
|
|
|
|
let data = {
|
|
ciphertext: ciphertext.toString("base64"),
|
|
iv: iv.toString("base64"),
|
|
hmac: hmac
|
|
};
|
|
|
|
fs.writeFileSync(getConfigFilename(), JSON.stringify(data, null, 2));
|
|
}
|
|
|
|
module.exports = {
|
|
get: getConfig,
|
|
set: setConfig
|
|
}
|