bifurcation / rocket-skates

A light, fast ACME implementation
Mozilla Public License 2.0
1 stars 1 forks source link

rocket-skates

Reference implementation of ACME.

Build Status Coverage Status

Wile E. Coyote on rocket skates

Goals

This implementation is intended more as a tool for learning about ACME and working on its development than something to be used in production.

Coverage

Test coverage can be measured with npm run coverage, and should be tracked by coveralls. There is currently no automated tracking of documentation coverage.

Spec coverage should be reflected in SPEC_COVERAGE.md. This file is built from comments of the following form:

  // {{request-uri-integrity}}
  _checkURL(req, url) {
    // implement the corresponding section of the spec
  }

The tag inside the curly braces is a reference to a section of the specification, using the de-facto standard mapping of section headings to anchors in Markdown. Of course, these are only claims of coverage, so there may be some inaccuracy.

Architecture

Internally, this module has a layered structure reflecting the layering of ACME.

The idea is that you can when you instantiate a server, you provide it with the challenge modules that you want it to offer, and likewise with the client and the validation modules you want it to support.

 acme-server             acme-client           |   http-validation
      |                       |                |   dns-validation
      |                       +------------+   |   tls-sni-validation
      |                       |            |   |
transport-server        transport-client  pki  |   http-challenge
      |   |                   |                |   dns-challenge
      |   +--------+----------+                |   tls-sni-challenge
      |            |
 nonce-source     jose

You can also define your own challenge / validation modules by following the interface used by the current set (in pseudo-JS):

interface Validation {
  // key        = A 'node-jose' key object
  // challenge  = An ACME challenge (not a challenge as below)
  // return     - Promise that resolves to an ACME response
  static makeResponse(key, challenge);

  // name       = The domain name being validated
  // challenge  = An ACME challenge
  // response   = The corresponding ACME response
  // onready    = A callback called with no arguments when the validation
  //              server is ready for the ACME server (mainly for testing)
  // return     - Promise that resolves when the validation request has been
  //              received and the server shut down.
  static respond(name, challenge, response, readyCallback);
}

interface Challenge {
  // name       = The domain name being validated
  // thumbprint = The thumbprint of the client's account key
  // return     - A new challenge object
  constructor(name, thumbprint);

  // response   = An ACME response
  // return     - A promise that resolves if the challenge was successful and
  //              rejects if it failed for any reason
  update(response);

  // return     - The JSON (ACME) form of the challenge
  toJSON();
}

Out-of-band requirements are specified by providing a handler function that takes express request and response objects and returns a promise that resolves to a boolean reflecting whether the requirement has been satisfied or not. So if you want an out-of-band requirement that simply requires someone to load a URL, you could do the following:

oobHandler = (req, res) => {
  res.end();
  return Promise.resolve(true);
};

Note that the promises returned by OOB handlers must be bluebird promises, because the OOB code takes advantage of .finally().