@root/acme
Advanced tools
Comparing version 3.0.0 to 3.0.1
@@ -49,6 +49,6 @@ 'use strict'; | ||
function agree(tosUrl) { | ||
function agree(agreed) { | ||
var err; | ||
if (me._tos !== tosUrl) { | ||
err = new Error("must agree to '" + tosUrl + "'"); | ||
if (!agreed) { | ||
err = new Error("must agree to '" + me._tos + "'"); | ||
err.code = 'E_AGREE_TOS'; | ||
@@ -140,8 +140,26 @@ throw err; | ||
var agreeToTerms = options.agreeToTerms; | ||
if (true === agreeToTerms) { | ||
agreeToTerms = function(tos) { | ||
return tos; | ||
if (!agreeToTerms) { | ||
agreeToTerms = function(terms) { | ||
console.log( | ||
'By using this software you accept this Subscriber Agreement and Terms of Service:' | ||
); | ||
console.info( | ||
'ACME Subscriber Agreement:', | ||
terms.acmeSubscriberTermsUrl | ||
); | ||
console.info( | ||
'Greenlock/ACME.js Terms of Use:', | ||
terms.terms.acmeJsTermsUrl | ||
); | ||
return true; | ||
}; | ||
} else if (true === agreeToTerms) { | ||
agreeToTerms = function(terms) { | ||
return terms && true; | ||
}; | ||
} | ||
return agreeToTerms(me._tos); | ||
return agreeToTerms({ | ||
acmeSubscriberTosUrl: me._tos, | ||
acmeJsTosUrl: 'https://rootprojects.org/legal/#terms' | ||
}); | ||
}) | ||
@@ -148,0 +166,0 @@ .then(agree) |
31
acme.js
@@ -113,3 +113,3 @@ // Copyright 2018-present AJ ONeal. All rights reserved | ||
return A._getAccountKid(me, options).then(function(kid) { | ||
ACME._normalizePresenters(options, options.challenges); | ||
ACME._normalizePresenters(me, options, options.challenges); | ||
return ACME._orderCert(me, options, kid).then(function(order) { | ||
@@ -123,3 +123,3 @@ return order.claims; | ||
return A._getAccountKid(me, options).then(function(kid) { | ||
ACME._normalizePresenters(options, options.challenges); | ||
ACME._normalizePresenters(me, options, options.challenges); | ||
return ACME._finalizeOrder(me, options, kid, options.order); | ||
@@ -133,3 +133,3 @@ }); | ||
return A._getAccountKid(me, options).then(function(kid) { | ||
ACME._normalizePresenters(options, options.challenges); | ||
ACME._normalizePresenters(me, options, options.challenges); | ||
return ACME._getCertificate(me, options, kid); | ||
@@ -222,3 +222,3 @@ }); | ||
}; | ||
ACME._normalizePresenters = function(options, presenters) { | ||
ACME._normalizePresenters = function(me, options, presenters) { | ||
// Prefer this order for efficiency: | ||
@@ -235,2 +235,18 @@ // * http-01 is the fasest | ||
); | ||
if ( | ||
presenters['dns-01'] && | ||
'number' !== typeof presenters['dns-01'].propagationDelay | ||
) { | ||
if (!ACME._propagationDelayWarning) { | ||
var err = new Error( | ||
"dns-01 challenge's `propagationDelay` not set, defaulting to 5000ms" | ||
); | ||
err.code = 'E_NO_DNS_DELAY'; | ||
err.description = | ||
"Each dns-01 challenge should specify challenges['dns-01'].propagationDelay as an estimate of how long DNS propagation will take."; | ||
ACME._notify(me, options, 'warning', err); | ||
presenters['dns-01'].propagationDelay = 5000; | ||
ACME._propagationDelayWarning = true; | ||
} | ||
} | ||
Object.keys(presenters || {}).forEach(function(k) { | ||
@@ -916,9 +932,2 @@ var ch = presenters[k]; | ||
if (!DNS_DELAY || DNS_DELAY <= 0) { | ||
if (!ACME._propagationDelayWarning) { | ||
console.warn( | ||
'warn: the given dns-01 challenge did not specify `propagationDelay`' | ||
); | ||
console.warn('warn: the default of 5000ms will be used'); | ||
ACME._propagationDelayWarning = true; | ||
} | ||
DNS_DELAY = 5000; | ||
@@ -925,0 +934,0 @@ } |
@@ -58,2 +58,3 @@ 'use strict'; | ||
maintainer: me.maintainerEmail, | ||
package: me.packageAgent, | ||
tz: tz, | ||
@@ -60,0 +61,0 @@ locale: locale |
{ | ||
"name": "@root/acme", | ||
"version": "3.0.0", | ||
"version": "3.0.1", | ||
"description": "Free SSL certificates for Node.js and Browsers. Issued via Let's Encrypt", | ||
@@ -5,0 +5,0 @@ "homepage": "https://rootprojects.org/acme/", |
480
README.md
@@ -1,9 +0,23 @@ | ||
# [ACME.js](https://git.rootprojects.org/root/acme.js) (RFC 8555 / November 2019) | ||
# Let's Encrypt™ + JavaScript = [ACME.js](https://git.rootprojects.org/root/acme.js) | ||
| Built by [Root](https://therootcompany.com) for [Greenlock](https://greenlock.domains) | ||
| Built by [Root](https://therootcompany.com) for [Hub](https://rootprojects.org/hub) | ||
Free SSL Certificates from Let's Encrypt, for Node.js and Web Browsers | ||
ACME.js is a _low-level_ client for Let's Encrypt. | ||
Lightweight. Fast. Modern Crypto. Zero external dependecies. | ||
Looking for an **easy**, _high-level_ client? Check out [Greenlock.js](https://git.rootprojects.org/root/greenlock.js). | ||
# Online Demo | ||
See https://greenlock.domains | ||
<!-- | ||
We expect that our hosted versions will meet all of yours needs. | ||
If they don't, please open an issue to let us know why. | ||
We'd much rather improve the app than have a hundred different versions running in the wild. | ||
However, in keeping to our values we've made the source visible for others to inspect, improve, and modify. | ||
--> | ||
# Features | ||
@@ -13,46 +27,62 @@ | ||
The primary goal of this library is to make it easy to | ||
get Accounts and Certificates through Let's Encrypt. | ||
Supports the latest (Nov 2019) release of Let's Encrypt in a small, lightweight, Vanilla JS package. | ||
- [x] Let's Encrypt v2 / ACME RFC 8555 (November 2019) | ||
- [x] POST-as-GET support | ||
- [x] Secure support for EC and RSA for account and server keys | ||
- [x] Simple and lightweight PEM, DER, ASN1, X509, and CSR implementations | ||
- [ ] (in-progress) StartTLS Everywhere™ | ||
- [x] Supports International Domain Names (i.e. `.中国`) | ||
- [x] Works with any [generic ACME challenge handler](https://git.rootprojects.org/root/acme-challenge-test.js) | ||
- [x] **http-01** for single or multiple domains per certificate | ||
- [x] **dns-01** for wildcards, localhost, private networks, etc | ||
- [x] VanillaJS, Zero External Dependencies | ||
- [x] Let's Encrypt v2 | ||
- [x] ACME RFC 8555 | ||
- [x] November 2019 | ||
- [x] POST-as-GET | ||
- [ ] StartTLS Everywhere™ (in-progress) | ||
- [x] IDN (i.e. `.中国`) | ||
- [x] ECDSA and RSA keypairs | ||
- [x] JWK | ||
- [x] PEM | ||
- [x] DER | ||
- [x] Native Crypto in Node.js | ||
- [x] WebCrypto in Browsers | ||
- [x] Domain Validation Plugins | ||
- [x] tls-alpn-01 | ||
- [x] http-01 | ||
- [x] dns-01 | ||
- [x] **Wildcards** | ||
- [x] **Localhost** | ||
- [x] Private Networks | ||
- [x] [Create your own](https://git.rootprojects.org/root/acme-challenge-test.js) | ||
- [x] Vanilla JS\* | ||
- [x] No Transpiling Necessary! | ||
- [x] Node.js | ||
- [x] Browsers | ||
- [x] WebPack | ||
- [x] Zero External Dependencies | ||
- [x] Commercial Support | ||
- [x] Safe, Efficient, Maintained | ||
- [x] Node.js\* (v6+) | ||
- [x] WebPack | ||
- [x] Online Demo | ||
- See https://greenlock.domains | ||
\* Although we use `async/await` in the examples, the code is written in CommonJS, | ||
with Promises, so you can use it in Node.js and Browsers without transpiling. | ||
\* Although we use `async/await` in the examples, | ||
the codebase is written entirely in Common JS. | ||
# Want Quick and Easy? | ||
# Use Cases | ||
ACME.js is a low-level tool for building Let's Encrypt clients in Node and Browsers. | ||
- Home Servers | ||
- IoT | ||
- Enterprise On-Prem | ||
- Web Hosting | ||
- Cloud Services | ||
- Localhost Development | ||
If you're looking for maximum convenience, try | ||
[Greenlock.js](https://git.rootprojects.org/root/greenlock-express.js). | ||
# API | ||
- <https://git.rootprojects.org/root/greenlock-express.js> | ||
The public API encapsulates the three high-level steps of the ACME protocol: | ||
# Online Demos | ||
1. API Discovery | ||
2. Account Creation | ||
- Subscriber Agreement | ||
3. Certificate Issuance | ||
- Certificate Request | ||
- Authorization Challenges | ||
- Challenge Presentation | ||
- Certificate Redemption | ||
- Greenlock for the Web <https://greenlock.domains> | ||
- ACME.js Demo <https://rootprojects.org/acme/> | ||
## Overview | ||
We expect that our hosted versions will meet all of yours needs. | ||
If they don't, please open an issue to let us know why. | ||
The core API can be show in just four functions: | ||
We'd much rather improve the app than have a hundred different versions running in the wild. | ||
However, in keeping to our values we've made the source visible for others to inspect, improve, and modify. | ||
# API Overview | ||
```js | ||
@@ -72,17 +102,2 @@ ACME.create({ maintainerEmail, packageAgent, notify }); | ||
| Parameter | Description | | ||
| --------------- | ----------------------------------------------------------------------------------------------------------- | | ||
| account | an object containing the Let's Encrypt Account ID as "kid" (misnomer, not actually a key id/thumbprint) | | ||
| accountKey | an RSA or EC public/private keypair in JWK format | | ||
| agreeToTerms | set to `true` to agree to the Let's Encrypt Subscriber Agreement | | ||
| challenges | the 'http-01', 'alpn-01', and/or 'dns-01' challenge plugins (`get`, `set`, and `remove` callbacks) to use | | ||
| csr | a Certificate Signing Request (CSR), which may be generated with csr.js, openssl, or another | | ||
| customerEmail | Don't use this. Given as an example to differentiate between Maintainer, Subscriber, and End-User | | ||
| directoryUrl | should be the Let's Encrypt Directory URL<br>`https://acme-staging-v02.api.letsencrypt.org/directory` | | ||
| domains | the list of altnames (subject first) that are listed in the CSR and will be listed on the certificate | | ||
| notify | all callback for logging events and errors in the form `function (ev, args) { ... }` | | ||
| maintainerEmail | should be a contact for the author of the code to receive critical bug and security notices | | ||
| packageAgent | should be an RFC72321-style user-agent string to append to the ACME client (ex: mypackage/v1.1.1) | | ||
| subscriberEmail | should be a contact for the service provider to receive renewal failure notices and manage the ACME account | | ||
Helper Functions | ||
@@ -92,3 +107,3 @@ | ||
ACME.computeChallenge({ | ||
accountKey: jwk, | ||
accountKey, | ||
hostname: 'example.com', | ||
@@ -99,2 +114,77 @@ challenge: { type: 'dns-01', token: 'xxxx' } | ||
| Parameter | Description | | ||
| ------------------ | ----------------------------------------------------------------------------------------------------------- | | ||
| account | an object containing the Let's Encrypt Account ID as "kid" (misnomer, not actually a key id/thumbprint) | | ||
| accountKey | an RSA or EC public/private keypair in JWK format | | ||
| agreeToTerms | set to `true` to agree to the Let's Encrypt Subscriber Agreement | | ||
| challenges | the 'http-01', 'alpn-01', and/or 'dns-01' challenge plugins (`get`, `set`, and `remove` callbacks) to use | | ||
| csr | a Certificate Signing Request (CSR), which may be generated with `@root/csr`, openssl, or another | | ||
| customerEmail | Don't use this. Given as an example to differentiate between Maintainer, Subscriber, and End-User | | ||
| directoryUrl | should be the Let's Encrypt Directory URL<br>`https://acme-staging-v02.api.letsencrypt.org/directory` | | ||
| domains | the list of altnames (subject first) that are listed in the CSR and will be listed on the certificate | | ||
| maintainerEmail | should be a contact for the author of the code to receive critical bug and security notices | | ||
| notify | all callback for logging events and errors in the form `function (ev, args) { ... }` | | ||
| packageAgent | should be an RFC72321-style user-agent string to append to the ACME client (ex: mypackage/v1.1.1) | | ||
| skipChallengeTests | do not do a self-check that the ACME-issued challenges will pass (not recommended) | | ||
| skipDryRun: false | do not do a self-check with self-issued challenges (not recommended) | | ||
| subscriberEmail | should be a contact for the service provider to receive renewal failure notices and manage the ACME account | | ||
**Maintainer vs Subscriber vs Customer** | ||
- `maintainerEmail` should be the email address of the **author of the code**. | ||
This person will receive critical security and API change notifications. | ||
- `subscriberEmail` should be the email of the **admin of the hosting service**. | ||
This person agrees to the Let's Encrypt Terms of Service and will be notified | ||
when a certificate fails to renew. | ||
- `customerEmail` should be the email of individual who owns the domain. | ||
This is optional (not currently implemented). | ||
Generally speaking **YOU** are the _maintainer_ and you **or your employer** is the _subscriber_. | ||
If you (or your employer) is running any type of service | ||
you **SHOULD NOT** pass the _customer_ email as the subscriber email. | ||
If you are not running a service (you may be building a CLI, for example), | ||
then you should prompt the user for their email address, and they are the subscriber. | ||
## Events | ||
These `notify` events are intended for _logging_ and debugging, NOT as a data API. | ||
| Event Name | Example Message | | ||
| -------------------- | --------------------------------------------------------------------------------- | | ||
| `certificate_order` | `{ subject: 'example.com', altnames: ['...'], account: { key: { kid: '...' } } }` | | ||
| `challenge_select` | `{ altname: '*.example.com', type: 'dns-01' }` | | ||
| `challenge_status` | `{ altname: '*.example.com', type: 'dns-01', status: 'pending' }` | | ||
| `challenge_remove` | `{ altname: '*.example.com', type: 'dns-01' }` | | ||
| `certificate_status` | `{ subject: 'example.com', status: 'valid' }` | | ||
| `warning` | `{ message: 'what went wrong', description: 'what action to take about it' }` | | ||
| `error` | `{ message: 'a background process failed, and it may have side-effects' }` | | ||
Note: DO NOT rely on **undocumented properties**. They are experimental and **will break**. | ||
If you have a use case for a particular property **open an issue** - we can lock it down and document it. | ||
# Example | ||
A basic example includes the following: | ||
1. Initialization | ||
- maintainer contact | ||
- package user-agent | ||
- log events | ||
2. Discover API | ||
- retrieves Terms of Service and API endpoints | ||
3. Get Subscriber Account | ||
- create an ECDSA (or RSA) Account key in JWK format | ||
- agree to terms | ||
- register account by the key | ||
4. Prepare a Certificate Signing Request | ||
- create a RSA (or ECDSA) Server key in PEM format | ||
- select domains | ||
- choose challenges | ||
- sign CSR | ||
- order certificate | ||
See [examples/README.md](https://git.rootprojects.org/root/acme.js/src/branch/master/examples/README.md) | ||
# Install | ||
@@ -106,3 +196,4 @@ | ||
## Node.js | ||
<detail> | ||
<summary>Node.js</summary> | ||
@@ -117,4 +208,7 @@ ```js | ||
## WebPack | ||
</detail> | ||
<detail> | ||
<summary>WebPack</summary> | ||
```html | ||
@@ -130,4 +224,7 @@ <meta charset="UTF-8" /> | ||
## Vanilla JS | ||
</detail> | ||
<detail> | ||
<summary>Vanilla JS</summary> | ||
```html | ||
@@ -155,180 +252,38 @@ <meta charset="UTF-8" /> | ||
## Usage Examples | ||
</detail> | ||
You can see `tests/index.js`, `examples/index.html`, `examples/app.js` in the repo for full example usage. | ||
# Challenge Callbacks | ||
### Emails: Maintainer vs Subscriber vs Customer | ||
The challenge callbacks are documented in the [test suite](https://git.rootprojects.org/root/acme-dns-01-test.js), | ||
essentially: | ||
- `maintainerEmail` should be the email address of the **author of the code**. | ||
This person will receive critical security and API change notifications. | ||
- `subscriberEmail` should be the email of the **admin of the hosting service**. | ||
This person agrees to the Let's Encrypt Terms of Service and will be notified | ||
when a certificate fails to renew. | ||
- `customerEmail` should be the email of individual who owns the domain. | ||
This is optional (not currently implemented). | ||
Generally speaking **YOU** are the _maintainer_ and you **or your employer** is the _subscriber_. | ||
If you (or your employer) is running any type of service | ||
you **SHOULD NOT** pass the _customer_ email as the subscriber email. | ||
If you are not running a service (you may be building a CLI, for example), | ||
then you should prompt the user for their email address, and they are the subscriber. | ||
### Overview | ||
1. Create an instance of ACME.js | ||
2. Create and SAVE a Subscriber Account private key | ||
3. Retrieve the Let's Encrypt Subscriber account (with the key) | ||
- the account will be created if it doesn't exist | ||
4. Create a Server Key | ||
- this should be per-server, or perhaps per-end-user | ||
5. Create a Certificate Signing Request | ||
- International Domain Names must be converted with `punycode` | ||
6. Create an ACME Order | ||
- use a challenge plugin for HTTP-01 or DNS-01 challenges | ||
### Instantiate ACME.js | ||
Although built for Let's Encrypt, ACME.js will work with any server | ||
that supports draft-15 of the ACME spec (includes POST-as-GET support). | ||
The `init()` method takes a _directory url_ and initializes internal state according to its response. | ||
```js | ||
var acme = ACME.create({ | ||
maintainerEmail: 'jon@example.com' | ||
}); | ||
acme.init('https://acme-staging-v02.api.letsencrypt.org/directory').then( | ||
function() { | ||
// Ready to use, show page | ||
$('body').hidden = false; | ||
} | ||
); | ||
function create(options) { | ||
var plugin = { | ||
init: async function(deps) { | ||
// for http requests | ||
plugin.request = deps.request; | ||
}, | ||
zones: async function(args) { | ||
// list zones relevant to the altnames | ||
}, | ||
set: async function(args) { | ||
// set TXT record | ||
}, | ||
get: async function(args) { | ||
// get TXT records | ||
}, | ||
remove: async function(args) { | ||
// remove TXT record | ||
}, | ||
// how long to wait after *all* TXT records are set | ||
// before presenting them for validation | ||
propagationDelay: 5000 | ||
}; | ||
return plugin; | ||
} | ||
``` | ||
### Create ACME Account with Let's Encrypt | ||
The `http-01` plugin is similar, but without `zones` or `propagationDelay`. | ||
ACME Accounts are key and device based, with an email address as a backup identifier. | ||
A public account key must be registered before an SSL certificate can be requested. | ||
```js | ||
var accountPrivateJwk; | ||
var account; | ||
Keypairs.generate({ kty: 'EC' }).then(function(pair) { | ||
accountPrivateJwk = pair.private; | ||
return acme.accounts | ||
.create({ | ||
agreeToTerms: function(tos) { | ||
if ( | ||
window.confirm( | ||
"Do you agree to the ACME.js and Let's Encrypt Terms of Service?" | ||
) | ||
) { | ||
return Promise.resolve(tos); | ||
} | ||
}, | ||
accountKey: pair.private, | ||
subscriberEmail: $('.js-email-input').value | ||
}) | ||
.then(function(_account) { | ||
account = _account; | ||
}); | ||
}); | ||
``` | ||
### Generate a Certificate Private Key | ||
```js | ||
var certKeypair = await Keypairs.generate({ kty: 'RSA' }); | ||
var pem = await Keypairs.export({ | ||
jwk: certKeypair.private, | ||
encoding: 'pem' | ||
}); | ||
// This should be saved as `privkey.pem` | ||
console.log(pem); | ||
``` | ||
### Generate a CSR | ||
The easiest way to generate a Certificate Signing Request will be either with `openssl` or with `@root/CSR`. | ||
```js | ||
var CSR = require('@root/csr'); | ||
var Enc = require('@root/encoding'); | ||
// 'subject' should be first in list | ||
// the domains may be in any order, but it should be consistent | ||
var sortedDomains = ['example.com', 'www.example.com']; | ||
var csr = await CSR.csr({ | ||
jwk: certKeypair.private, | ||
domains: sortedDomains, | ||
encoding: 'der' | ||
}).then(function(der) { | ||
return Enc.bufToUrlBase64(der); | ||
}); | ||
``` | ||
### Get Free 90-day SSL Certificate | ||
Creating an ACME "order" for a 90-day SSL certificate requires use of the account private key, | ||
the names of domains to be secured, and a distinctly separate server private key. | ||
A domain ownership verification "challenge" (uploading a file to an unsecured HTTP url or setting a DNS record) | ||
is a required part of the process, which requires `set` and `remove` callbacks/promises. | ||
```js | ||
var certinfo = await acme.certificates.create({ | ||
account: account, | ||
accountKey: accountPrivateJwk, | ||
csr: csr, | ||
domains: sortedDomains, | ||
challenges: challenges, // must be implemented | ||
customerEmail: null, | ||
skipChallengeTests: false, | ||
skipDryRun: false | ||
}); | ||
console.log('Got SSL Certificate:'); | ||
console.log(results.expires); | ||
// This should be saved as `fullchain.pem` | ||
console.log([results.cert, results.chain].join('\n')); | ||
``` | ||
### Example "Challenge" Implementation | ||
Typically here you're just presenting some sort of dialog to the user to ask them to | ||
upload a file or set a DNS record. | ||
It may be possible to do something fancy like using OAuth2 to login to Google Domanis | ||
to set a DNS address, etc, but it seems like that sort of fanciness is probably best | ||
reserved for server-side plugins. | ||
```js | ||
var challenges = { | ||
'http-01': { | ||
set: function(opts) { | ||
console.info('http-01 set challenge:'); | ||
console.info(opts.challengeUrl); | ||
console.info(opts.keyAuthorization); | ||
while ( | ||
!window.confirm('Upload the challenge file before continuing.') | ||
) { | ||
// spin and wait for the user to upload the challenge file | ||
} | ||
return Promise.resolve(); | ||
}, | ||
remove: function(opts) { | ||
console.log('http-01 remove challenge:', opts.challengeUrl); | ||
return Promise.resolve(); | ||
} | ||
} | ||
}; | ||
``` | ||
Many challenge plugins are already available for popular platforms. | ||
@@ -338,40 +293,29 @@ | ||
- [x] DNS-01 Challenges | ||
- CloudFlare | ||
- [Digital Ocean](https://git.rootprojects.org/root/acme-dns-01-digitalocean.js) | ||
- [DNSimple](https://git.rootprojects.org/root/acme-dns-01-dnsimple.js) | ||
- [DuckDNS](https://git.rootprojects.org/root/acme-dns-01-duckdns.js) | ||
- [GoDaddy](https://git.rootprojects.org/root/acme-dns-01-godaddy.js) | ||
- [Gandi](https://git.rootprojects.org/root/acme-dns-01-gandi.js) | ||
- [NameCheap](https://git.rootprojects.org/root/acme-dns-01-namecheap.js) | ||
- [Name.com](https://git.rootprojects.org/root/acme-dns-01-namedotcom.js) | ||
- Route53 (AWS) | ||
- [Vultr](https://git.rootprojects.org/root/acme-dns-01-vultr.js) | ||
- Build your own | ||
- [x] HTTP-01 Challenges | ||
- [In-Memory](https://git.rootprojects.org/root/acme-http-01-standalone.js) (Standalone) | ||
- [FileSystem](https://git.rootprojects.org/root/acme-http-01-webroot.js) (WebRoot) | ||
- S3 (AWS, Digital Ocean, etc) | ||
- [x] TLS-ALPN-01 Challenges | ||
- Contact us to learn about Greenlock Pro | ||
| Type | Service | Plugin | | ||
| ----------- | ----------------------------------------------------------------------------------- | ------------------------ | | ||
| dns-01 | CloudFlare | acme-dns-01-cloudflare | | ||
| dns-01 | [Digital Ocean](https://git.rootprojects.org/root/acme-dns-01-digitalocean.js) | acme-dns-01-digitalocean | | ||
| dns-01 | [DNSimple](https://git.rootprojects.org/root/acme-dns-01-dnsimple.js) | acme-dns-01-dnsimple | | ||
| dns-01 | [DuckDNS](https://git.rootprojects.org/root/acme-dns-01-duckdns.js) | acme-dns-01-duckdns | | ||
| http-01 | File System / [Web Root](https://git.rootprojects.org/root/acme-http-01-webroot.js) | acme-http-01-webroot | | ||
| dns-01 | [GoDaddy](https://git.rootprojects.org/root/acme-dns-01-godaddy.js) | acme-dns-01-godaddy | | ||
| dns-01 | [Gandi](https://git.rootprojects.org/root/acme-dns-01-gandi.js) | acme-dns-01-gandi | | ||
| dns-01 | [NameCheap](https://git.rootprojects.org/root/acme-dns-01-namecheap.js) | acme-dns-01-namecheap | | ||
| dns-01 | [Name.com](https://git.rootprojects.org/root/acme-dns-01-namedotcom.js) | acme-dns-01-namedotcom | | ||
| dns-01 | Route53 (AWS) | acme-dns-01-route53 | | ||
| http-01 | S3 (AWS, Digital Ocean, Scaleway) | acme-http-01-s3 | | ||
| dns-01 | [Vultr](https://git.rootprojects.org/root/acme-dns-01-vultr.js) | acme-dns-01-vultr | | ||
| dns-01 | [Build your own](https://git.rootprojects.org/root/acme-dns-01-test.js) | acme-dns-01-test | | ||
| http-01 | [Build your own](https://git.rootprojects.org/root/acme-http-01-test.js) | acme-http-01-test | | ||
| tls-alpn-01 | [Contact us](mailto:support@therootcompany.com) | - | | ||
# IDN - International Domain Names | ||
# Running the Tests | ||
Convert domain names to `punycode` before creating the certificate: | ||
```js | ||
var punycode = require('punycode'); | ||
acme.certificates.create({ | ||
// ... | ||
domains: ['example.com', 'www.example.com'].map(function(name) { | ||
return punycode.toASCII(name); | ||
}) | ||
}); | ||
```bash | ||
npm test | ||
``` | ||
The punycode library itself is lightweight and dependency-free. | ||
It is available both in node and for browsers. | ||
## Usa a dns-01 challenge | ||
# Testing | ||
Although you can run the tests from a public facing server, its easiest to do so using a dns-01 challenge. | ||
@@ -381,6 +325,5 @@ You will need to use one of the [`acme-dns-01-*` plugins](https://www.npmjs.com/search?q=acme-dns-01-) | ||
You'll also need a `.env` that looks something like the one in `examples/example.env`: | ||
```bash | ||
ENV=DEV | ||
MAINTAINER_EMAIL=letsencrypt+staging@example.com | ||
SUBSCRIBER_EMAIL=letsencrypt+staging@example.com | ||
@@ -393,3 +336,3 @@ BASE_DOMAIN=test.example.com | ||
For example: | ||
### For Example | ||
@@ -403,3 +346,9 @@ ```bash | ||
npm install --save-dev acme-dns-01-digitalocean | ||
``` | ||
## Create a `.env` config | ||
You'll need a `.env` in the project root that looks something like the one in `examples/example.env`: | ||
```bash | ||
# Copy the sample .env file | ||
@@ -418,5 +367,2 @@ rsync -av examples/example.env .env | ||
You can see `<script>` tags in the `index.html` in the repo, which references the original | ||
source files. | ||
Join `@rootprojects` `#general` on [Keybase](https://keybase.io) if you'd like to chat with us. | ||
@@ -435,3 +381,3 @@ | ||
Greenlock™ is a [trademark](https://rootprojects.org/legal/#trademark) of AJ ONeal | ||
ACME.jsk™ is a [trademark](https://rootprojects.org/legal/#trademark) of AJ ONeal | ||
@@ -438,0 +384,0 @@ The rule of thumb is "attribute, but don't confuse". For example: |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
87809
1979
1
381