Omit email, cache keypair
This commit is contained in:
parent
2a3b44a1a1
commit
d09a2d8cb5
3 changed files with 25 additions and 29 deletions
|
|
@ -28,29 +28,20 @@ To forward from `www.old.com` to `old.com`, add these records to your DNS:
|
||||||
```
|
```
|
||||||
www.old.com IN CNAME r.forwarddomain.net
|
www.old.com IN CNAME r.forwarddomain.net
|
||||||
_.www.old.com IN TXT forward-domain=https://old.com/*
|
_.www.old.com IN TXT forward-domain=https://old.com/*
|
||||||
_.www.old.com IN TXT forward-domain-cert-maintainer=<your email address>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> IMPORTANT: replace `<your email address>` with your email address!
|
|
||||||
|
|
||||||
Because CNAME can't be used in apex domains, you can use A/AAAA records.<br>
|
Because CNAME can't be used in apex domains, you can use A/AAAA records.<br>
|
||||||
To forward from `old.com` to `new.net`, add these records to your DNS:
|
To forward from `old.com` to `new.net`, add these records to your DNS:
|
||||||
|
|
||||||
```
|
```
|
||||||
old.com IN A 167.172.5.31
|
old.com IN A 167.172.5.31
|
||||||
_.old.com IN TXT forward-domain=https://new.net/*
|
_.old.com IN TXT forward-domain=https://new.net/*
|
||||||
_.old.com IN TXT forward-domain-cert-maintainer=<your email address>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> BETA service notice: IP addresses may change anytime.
|
> BETA service notice: IP addresses may change anytime.
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
### Why email address?
|
|
||||||
|
|
||||||
This is required in order to sign HTTPS certificates.<br>
|
|
||||||
You can omit it but HTTPS redirects will not work.
|
|
||||||
|
|
||||||
### Is it really free?
|
### Is it really free?
|
||||||
|
|
||||||
Forwarding domains should be easy to setup.<br>
|
Forwarding domains should be easy to setup.<br>
|
||||||
|
|
|
||||||
|
|
@ -91,14 +91,14 @@ class Client {
|
||||||
* Generate a certificate from Let's Encrypt for your domain.
|
* Generate a certificate from Let's Encrypt for your domain.
|
||||||
*
|
*
|
||||||
* @param {String} domain - the domain you want a certificate for
|
* @param {String} domain - the domain you want a certificate for
|
||||||
* @param {String} email - the email used to register the certificate
|
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
async generateCertificate(domain, email) {
|
async generateCertificate(domain) {
|
||||||
await this.directory()
|
await this.directory()
|
||||||
await this.newNonce()
|
await this.newNonce()
|
||||||
await this.newAccount(email)
|
if (!this.myAccountUrl)
|
||||||
|
await this.newAccount()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
authzUrls,
|
authzUrls,
|
||||||
|
|
@ -113,7 +113,7 @@ class Client {
|
||||||
const {
|
const {
|
||||||
certificate,
|
certificate,
|
||||||
privateKeyData
|
privateKeyData
|
||||||
} = await this.finalizeOrder(finalizeUrl, domain, email)
|
} = await this.finalizeOrder(finalizeUrl, domain)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
certificate,
|
certificate,
|
||||||
|
|
@ -228,7 +228,7 @@ class Client {
|
||||||
return res.data
|
return res.data
|
||||||
}
|
}
|
||||||
|
|
||||||
async finalizeOrder(finalizeUrl, domain, email) {
|
async finalizeOrder(finalizeUrl, domain) {
|
||||||
const {
|
const {
|
||||||
privateKey
|
privateKey
|
||||||
} = await generateKeyPair(common.CERTIFICATE_KEY_ALGORITHM)
|
} = await generateKeyPair(common.CERTIFICATE_KEY_ALGORITHM)
|
||||||
|
|
@ -240,7 +240,6 @@ class Client {
|
||||||
} = await createCsr({
|
} = await createCsr({
|
||||||
clientKey,
|
clientKey,
|
||||||
commonName: domain,
|
commonName: domain,
|
||||||
email
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// "The CSR is sent in the base64url-encoded version of the DER format.
|
// "The CSR is sent in the base64url-encoded version of the DER format.
|
||||||
|
|
@ -304,7 +303,6 @@ class Client {
|
||||||
nonce: this.replayNonce,
|
nonce: this.replayNonce,
|
||||||
url: this.newAccountUrl
|
url: this.newAccountUrl
|
||||||
}, {
|
}, {
|
||||||
contact: emails.map(email => 'mailto:' + email),
|
|
||||||
termsOfServiceAgreed: true
|
termsOfServiceAgreed: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
33
src/sni.js
33
src/sni.js
|
|
@ -7,10 +7,12 @@ const {
|
||||||
ensureDir,
|
ensureDir,
|
||||||
findTxtRecord
|
findTxtRecord
|
||||||
} = require('./util');
|
} = require('./util');
|
||||||
const { default: AwaitLock } = require('await-lock');
|
const {
|
||||||
const record_email_prefix = 'forward-domain-cert-maintainer=';
|
default: AwaitLock
|
||||||
const client = new certnode.Client();
|
} = require('await-lock');
|
||||||
const certsDir = path.join(__dirname, '../.certs');
|
const certsDir = path.join(__dirname, '../.certs');
|
||||||
|
const accountDir = path.join(__dirname, '../.certs/account');
|
||||||
|
const client = new certnode.Client();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Object<string, {cert: any, key: any, expire: number}>}
|
* @type {Object<string, {cert: any, key: any, expire: number}>}
|
||||||
|
|
@ -22,13 +24,6 @@ function getCertCachePath(host) {
|
||||||
return path.join(certsDir, hash.substr(0, 2), hash.substr(2), host);
|
return path.join(certsDir, hash.substr(0, 2), hash.substr(2), host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} host
|
|
||||||
*/
|
|
||||||
async function findMaintainerEmail(host) {
|
|
||||||
return await findTxtRecord(host, record_email_prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} host
|
* @param {string} host
|
||||||
*/
|
*/
|
||||||
|
|
@ -56,7 +51,7 @@ async function buildCache(host) {
|
||||||
const {
|
const {
|
||||||
certificate,
|
certificate,
|
||||||
privateKeyData
|
privateKeyData
|
||||||
} = await client.generateCertificate(host, await findMaintainerEmail(host));
|
} = await client.generateCertificate(host);
|
||||||
await fs.promises.writeFile(certP, certificate);
|
await fs.promises.writeFile(certP, certificate);
|
||||||
await certnode.writeKeyToFile(keyP, privateKeyData, '');
|
await certnode.writeKeyToFile(keyP, privateKeyData, '');
|
||||||
const expire = (Date.now() + 45 * 86400 * 1000);
|
const expire = (Date.now() + 45 * 86400 * 1000);
|
||||||
|
|
@ -88,7 +83,11 @@ async function getKeyCert(servername) {
|
||||||
|
|
||||||
let lock = new AwaitLock();
|
let lock = new AwaitLock();
|
||||||
|
|
||||||
const SniListener = async (servername, ctx) => {
|
/**
|
||||||
|
* @param {string} servername
|
||||||
|
* @param {(err: any, cb: tls.SecureContext) => void} ctx
|
||||||
|
*/
|
||||||
|
async function SniListener(servername, ctx) {
|
||||||
// Had to use lock because the best authenticator
|
// Had to use lock because the best authenticator
|
||||||
// library seems don't yet fully stateless.
|
// library seems don't yet fully stateless.
|
||||||
// Generate fresh account keys for Let's Encrypt
|
// Generate fresh account keys for Let's Encrypt
|
||||||
|
|
@ -104,8 +103,16 @@ const SniListener = async (servername, ctx) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const SniPrepare = async () => {
|
const SniPrepare = async () => {
|
||||||
await client.generateAccountKeyPair()
|
|
||||||
await ensureDir(certsDir);
|
await ensureDir(certsDir);
|
||||||
|
await ensureDir(accountDir);
|
||||||
|
|
||||||
|
if (fs.existsSync(path.join(accountDir, 'privateKey.pem')) &&
|
||||||
|
fs.existsSync(path.join(accountDir, 'publicKey.pem'))) {
|
||||||
|
await client.importAccountKeyPair(accountDir, '');
|
||||||
|
} else {
|
||||||
|
await client.generateAccountKeyPair();
|
||||||
|
await client.exportAccountKeyPair(accountDir, '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
||||||
Loading…
Add table
editor.link_modal.header
Reference in a new issue