update docs

This commit is contained in:
AJ ONeal 2019-11-02 13:26:08 -06:00
parent e0a9fff07d
commit 5490a194eb
3 changed files with 161 additions and 106 deletions

263
README.md
View File

@ -12,125 +12,180 @@ Works with all ACME (Let's Encrypt) SSL certificate sytles:
# Usage # Usage
**Global** config:
```js ```js
var greenlock = require('greenlock'); greenlock.manager.defaults({
var gl = greenlock.create({ store: {
configDir: '~/.config/acme' module: "greenlock-store-fs",
, store: require('greenlock-store-fs') basePath: "~/.config/greenlock"
, approveDomains: approveDomains }
, ... });
```
**Per-site** config:
```js
greenlock.add({
subject: "example.com",
altnames: ["example.com", "www.example.com"],
store: {
module: "greenlock-store-fs",
basePath: "~/.config/greenlock"
}
}); });
``` ```
# File System # File System
The default file system layout mirrors that of le-store-certbot in order to make transitioning effortless, The default file system layout mirrors that of certbot (python Let's Encrypt implementation) and
in most situations: the prior le-store-certbot in order to make transitioning effortless.
``` The default structure looks like this:
acme
├── accounts ```txt
│   └── acme-staging-v02.api.letsencrypt.org .config
│   └── directory └── greenlock
│   └── sites@example.com.json ├── accounts
└── live │   └── acme-staging-v02.api.letsencrypt.org
├── example.com │   └── directory
│   ├── bundle.pem │   └── sites@example.com.json
│   ├── cert.pem ├── staging
│   ├── chain.pem │ └── (same as live)
│   ├── fullchain.pem └── live
│   └── privkey.pem ├── example.com
└── www.example.com │   ├── bundle.pem
├── bundle.pem │   ├── cert.pem
├── cert.pem │   ├── chain.pem
├── chain.pem │   ├── fullchain.pem
├── fullchain.pem │   └── privkey.pem
└── privkey.pem └── www.example.com
├── bundle.pem
├── cert.pem
├── chain.pem
├── fullchain.pem
└── privkey.pem
``` ```
# Wildcards & AltNames # Internal Implementation Details
Working with wildcards and multiple altnames requires greenlock >= v2.7 (or v3). You **DO NOT NEED TO KNOW** these details.
To do so you must return `{ subject: '...', altnames: ['...', ...] }` within the `approveDomains()` callback. They're provided for the sake of understanding what happens "under the hood"
to help you make better choices "in the seat".
`subject` refers to "the subject of the ssl certificate" as opposed to `domain` which indicates "the domain servername # Parameters
used in the current request". For single-domain certificates they're always the same, but for multiple-domain
certificates `subject` must be the name no matter what `domain` is receiving a request. `subject` is used as
part of the name of the file storage path where the certificate will be saved (or retrieved).
`altnames` should be the list of SubjectAlternativeNames (SANs) on the certificate. | parameters | example | notes |
The subject and the first altname must be an exact match: `subject === altnames[0]`. | ----------------- | -------------------------------------------------------- | ---------------- |
| `env` | `staging` or `live` | - |
| `directoryUrl` | `https://acme-staging-v02.api.letsencrypt.org/directory` | - |
| `keypair` | `{ privateKeyPem, privateKeyJwk }` | |
| `account` | `{ id: "an-arbitrary-id" }` | account only |
| `subscriberEmail` | `webhost@example.com` | account only |
| `certificate` | `{ id: "an-arbitrary-id" }` | certificate only |
| `subject` | `example.com` | certificate only |
| `pems` | `{ privkey, cert, chain, issuedAt, expiresAt }` | certificate only |
## Simple Example ### Account Keypair
```js ```js
function approveDomains(opts) { accounts.setKeypair = async function({
// Allow only example.com and *.example.com (such as foo.example.com) env,
basePath,
// foo.example.com => *.example.com directoryUrl,
var wild = email,
"*." + account
opts.domain }) {
.split(".") var id = account.id || email;
.slice(1) var serverDir = directoryUrl.replace("https://", "");
.join("."); };
```
if ("example.com" !== opts.domain && "*.example.com" !== wild) {
cb(new Error(opts.domain + " is not allowed")); ```js
} accounts.checkKeypair = async function({
env,
var result = { basePath,
subject: "example.com", directoryUrl,
altnames: ["example.com", "*.example.com"] email,
}; account
return Promise.resolve(result); }) {
} var id = account.id || email;
``` var serverDir = directoryUrl.replace("https://", "");
## Realistic Example return {
privateKeyPem,
```js privateKeyJwk
function approveDomains(opts, certs, cb) { };
var related = getRelated(opts.domain); };
if (!related) { ```
cb(new Error(opts.domain + " is not allowed"));
} ### Certificate Keypair
opts.subject = related.subject; ```js
opts.domains = related.domains; certificate.setKeypair = async function({
env,
cb({ options: opts, certs: certs }); basePath,
} directoryUrl,
``` subject,
certificate
```js }) {
function getRelated(domain) { var id = account.id || email;
var related; env = env || directoryUrl.replace("https://", "");
var wild = };
"*." + ```
domain
.split(".") ```js
.slice(1) certificate.checkKeypair = async function({
.join("."); env,
if ( basePath,
Object.keys(allAllowedDomains).some(function(k) { directoryUrl,
return allAllowedDomains[k].some(function(name) { subject,
if (domain === name || wild === name) { certificate
related = { subject: k, altnames: allAllowedDomains[k] }; }) {
return true; var id = account.id || email;
} env = env || directoryUrl.replace("https://", "");
});
}) return {
) { privateKeyPem,
return related; privateKeyJwk
} };
} };
``` ```
```js ### Certificate PEMs
var allAllowedDomains = {
"example.com": ["example.com", "*.example.com"], ```js
"example.net": ["example.net", "*.example.net"] certificate.set = async function({
env,
basePath,
directoryUrl,
subject,
certificate,
pems
}) {
var id = account.id || email;
env = env || directoryUrl.replace("https://", "");
};
```
```js
certificate.check = async function({
env,
basePath,
directoryUrl,
subject,
certificate
}) {
var id = account.id || email;
env = env || directoryUrl.replace("https://", "");
return {
privkey,
cert,
chain,
issuedAt,
expiresAt
};
}; };
``` ```

View File

@ -17,7 +17,7 @@ var mkdirpAsync = PromiseA.promisify(require("@root/mkdirp"));
// Use certificate.id, or subject, if id hasn't been set, to find a certificate. // Use certificate.id, or subject, if id hasn't been set, to find a certificate.
// Return an object with string PEMs for cert and chain (or null, not undefined) // Return an object with string PEMs for cert and chain (or null, not undefined)
certificates.check = function(opts) { certificates.check = function(opts) {
// { certificate.id, subject, ... } // { directoryUrl, subject, certificate.id, ... }
var id = (opts.certificate && opts.certificate.id) || opts.subject; var id = (opts.certificate && opts.certificate.id) || opts.subject;
//console.log('certificates.check for', opts); //console.log('certificates.check for', opts);

View File

@ -1,6 +1,6 @@
{ {
"name": "greenlock-store-fs", "name": "greenlock-store-fs",
"version": "3.2.1", "version": "3.2.2",
"description": "A file-based certificate store for greenlock that supports wildcards.", "description": "A file-based certificate store for greenlock that supports wildcards.",
"homepage": "https://git.rootprojects.org/root/greenlock-store-fs.js", "homepage": "https://git.rootprojects.org/root/greenlock-store-fs.js",
"main": "index.js", "main": "index.js",