accounts.js 3.57 KB
"use strict";

var accounts = module.exports;
var store = accounts;
var U = require("./utils.js");

var fs = require("fs");
var path = require("path");
var PromiseA = require("./promise.js");
var readFileAsync = PromiseA.promisify(fs.readFile);
var writeFileAsync = PromiseA.promisify(fs.writeFile);
var mkdirpAsync = PromiseA.promisify(require("@root/mkdirp"));

// Implement if you need the ACME account metadata elsewhere in the chain of events
//store.accounts.check = function (opts) {
//  console.log('accounts.check for', opts.account, opts.email);
//  return PromiseA.resolve(null);
//};

// Accounts.checkKeypair
//
// Use account.id, or email, if id hasn't been set, to find an account keypair.
// Return an object with string privateKeyPem and/or object privateKeyJwk (or null, not undefined)
accounts.checkKeypair = function(opts) {
    var id =
        (opts.account && opts.account.id) ||
        (opts.subscriberEmail || opts.email) ||
        "single-user";
    //console.log('accounts.checkKeypair for', id);

    var pathname = path.join(
        accountsDir(store, opts),
        sanitizeFilename(id) + ".json"
    );
    return readFileAsync(U._tameWild(pathname, opts.subject), "utf8")
        .then(function(blob) {
            // keypair can treated as an opaque object and just passed along,
            // but just to show you what it is...
            var keypair = JSON.parse(blob);
            return keypair;
            /*
      {
				privateKeyPem: keypair.privateKeyPem, // string PEM private key
				privateKeyJwk: keypair.privateKeyJwk, // object JWK private key
				private: keypair.private,
				public: keypair.public
			};
      */
        })
        .catch(function(err) {
            if ("ENOENT" === err.code) {
                return null;
            }
            throw err;
        });
};

// Accounts.setKeypair({ account, email, keypair, ... }):
//
// Use account.id (or email if no id is present) to save an account keypair
// Return null (not undefined) on success, or throw on error
accounts.setKeypair = function(opts) {
    //console.log('accounts.setKeypair for', opts.account, opts.email, opts.keypair);
    var id = opts.account.id || opts.email || "single-user";

    // you can just treat the keypair as opaque and save and retrieve it as JSON
    var keyblob = JSON.stringify(opts.keypair);
    /*
	var keyblob = JSON.stringify({
		privateKeyPem: opts.keypair.privateKeyPem, // string PEM
		privateKeyJwk: opts.keypair.privateKeyJwk, // object JWK
    private: opts.keypair.private
	});
  */

    // Ignore.
    // Just implementation specific details here.
    return mkdirpAsync(accountsDir(store, opts))
        .then(function() {
            var pathname = path.join(
                accountsDir(store, opts),
                sanitizeFilename(id) + ".json"
            );
            return writeFileAsync(
                U._tameWild(pathname, opts.subject),
                keyblob,
                "utf8"
            );
        })
        .then(function() {
            // This is your job: return null, not undefined
            return null;
        });
};

// Implement if you need the ACME account metadata elsewhere in the chain of events
//accounts.set = function (opts) {
//  console.log('account.set:', opts.account, opts.email, opts.receipt);
//  return PromiseA.resolve(null);
//};

function sanitizeFilename(id) {
    return id.replace(/(\.\.)|\\|\//g, "_").replace(/[^!-~]/g, "_");
}

function accountsDir(store, opts) {
    var dir = U._tpl(
        store,
        opts,
        opts.accountsDir || store.options.accountsDir
    );
    return U._tameWild(dir, opts.subject || "");
}