-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
458 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ services: | |
restart: unless-stopped | ||
ports: | ||
- "80:3000" | ||
- "443:3443" | ||
|
||
volumes: | ||
db-data: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
const express = require('express') | ||
const router = express.Router() | ||
const _ = require('lodash') | ||
|
||
/* global WIKI */ | ||
|
||
/** | ||
* Let's Encrypt Challenge | ||
*/ | ||
router.get('/.well-known/acme-challenge/:token', (req, res, next) => { | ||
res.type('text/plain') | ||
if (_.get(WIKI.config, 'letsencrypt.challenge', false)) { | ||
if (WIKI.config.letsencrypt.challenge.token === req.params.token) { | ||
res.send(WIKI.config.letsencrypt.challenge.keyAuthorization) | ||
WIKI.logger.info(`(LETSENCRYPT) Received valid challenge request. [ ACCEPTED ]`) | ||
} else { | ||
res.status(406).send('Invalid Challenge Token!') | ||
WIKI.logger.warn(`(LETSENCRYPT) Received invalid challenge request. [ REJECTED ]`) | ||
} | ||
} else { | ||
res.status(418).end() | ||
} | ||
}) | ||
|
||
module.exports = router |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
const ACME = require('acme') | ||
const Keypairs = require('@root/keypairs') | ||
const _ = require('lodash') | ||
const moment = require('moment') | ||
const CSR = require('@root/csr') | ||
const PEM = require('@root/pem') | ||
// eslint-disable-next-line node/no-deprecated-api | ||
const punycode = require('punycode') | ||
|
||
/* global WIKI */ | ||
|
||
module.exports = { | ||
apiDirectory: WIKI.dev ? 'https://acme-staging-v02.api.letsencrypt.org/directory' : 'https://acme-v02.api.letsencrypt.org/directory', | ||
acme: null, | ||
async init () { | ||
if (!_.get(WIKI.config, 'letsencrypt.payload', false)) { | ||
await this.requestCertificate() | ||
} else if (WIKI.config.letsencrypt.domain !== WIKI.config.ssl.domain) { | ||
WIKI.logger.info(`(LETSENCRYPT) Domain has changed. Requesting new certificates...`) | ||
await this.requestCertificate() | ||
} else if (moment(WIKI.config.letsencrypt.payload.expires).isSameOrBefore(moment().add(5, 'days'))) { | ||
WIKI.logger.info(`(LETSENCRYPT) Certificate is about to or has expired, requesting a new one...`) | ||
await this.requestCertificate() | ||
} else { | ||
WIKI.logger.info(`(LETSENCRYPT) Using existing certificate for ${WIKI.config.ssl.domain}, expires on ${WIKI.config.letsencrypt.payload.expires}: [ OK ]`) | ||
} | ||
WIKI.config.ssl.format = 'pem' | ||
WIKI.config.ssl.inline = true | ||
WIKI.config.ssl.key = WIKI.config.letsencrypt.serverKey | ||
WIKI.config.ssl.cert = WIKI.config.letsencrypt.payload.cert + '\n' + WIKI.config.letsencrypt.payload.chain | ||
WIKI.config.ssl.passphrase = null | ||
WIKI.config.ssl.dhparam = null | ||
}, | ||
async requestCertificate () { | ||
try { | ||
WIKI.logger.info(`(LETSENCRYPT) Initializing Let's Encrypt client...`) | ||
this.acme = ACME.create({ | ||
maintainerEmail: WIKI.config.ssl.maintainerEmail, | ||
packageAgent: `wikijs/${WIKI.version}`, | ||
notify: (ev, msg) => { | ||
if (_.includes(['warning', 'error'], ev)) { | ||
WIKI.logger.warn(`${ev}: ${msg}`) | ||
} else { | ||
WIKI.logger.debug(`${ev}: ${JSON.stringify(msg)}`) | ||
} | ||
} | ||
}) | ||
|
||
await this.acme.init(this.apiDirectory) | ||
|
||
// -> Create ACME Subscriber account | ||
|
||
if (!_.get(WIKI.config, 'letsencrypt.account', false)) { | ||
WIKI.logger.info(`(LETSENCRYPT) Setting up account for the first time...`) | ||
const accountKeypair = await Keypairs.generate({ kty: 'EC', format: 'jwk' }) | ||
const account = await this.acme.accounts.create({ | ||
subscriberEmail: WIKI.config.ssl.maintainerEmail, | ||
agreeToTerms: true, | ||
accountKey: accountKeypair.private | ||
}) | ||
WIKI.config.letsencrypt = { | ||
accountKeypair: accountKeypair, | ||
account: account, | ||
domain: WIKI.config.ssl.domain | ||
} | ||
await WIKI.configSvc.saveToDb(['letsencrypt']) | ||
WIKI.logger.info(`(LETSENCRYPT) Account was setup successfully [ OK ]`) | ||
} | ||
|
||
// -> Create Server Keypair | ||
|
||
if (!WIKI.config.letsencrypt.serverKey) { | ||
WIKI.logger.info(`(LETSENCRYPT) Generating server keypairs...`) | ||
const serverKeypair = await Keypairs.generate({ kty: 'RSA', format: 'jwk' }) | ||
WIKI.config.letsencrypt.serverKey = await Keypairs.export({ jwk: serverKeypair.private }) | ||
WIKI.logger.info(`(LETSENCRYPT) Server keypairs generated successfully [ OK ]`) | ||
} | ||
|
||
// -> Create CSR | ||
|
||
WIKI.logger.info(`(LETSENCRYPT) Generating certificate signing request (CSR)...`) | ||
const domains = [ punycode.toASCII(WIKI.config.ssl.domain) ] | ||
const serverKey = await Keypairs.import({ pem: WIKI.config.letsencrypt.serverKey }) | ||
const csrDer = await CSR.csr({ jwk: serverKey, domains, encoding: 'der' }) | ||
const csr = PEM.packBlock({ type: 'CERTIFICATE REQUEST', bytes: csrDer }) | ||
WIKI.logger.info(`(LETSENCRYPT) CSR generated successfully [ OK ]`) | ||
|
||
// -> Verify Domain + Get Certificate | ||
|
||
WIKI.logger.info(`(LETSENCRYPT) Requesting certificate from Let's Encrypt...`) | ||
const certResp = await this.acme.certificates.create({ | ||
account: WIKI.config.letsencrypt.account, | ||
accountKey: WIKI.config.letsencrypt.accountKeypair.private, | ||
csr, | ||
domains, | ||
challenges: { | ||
'http-01': { | ||
init () {}, | ||
set (data) { | ||
WIKI.logger.info(`(LETSENCRYPT) Setting HTTP challenge for ${data.challenge.hostname}: [ READY ]`) | ||
WIKI.config.letsencrypt.challenge = data.challenge | ||
WIKI.logger.info(`(LETSENCRYPT) Waiting for challenge to complete...`) | ||
return null // <- this is needed, cannot be undefined | ||
}, | ||
get (data) { | ||
return WIKI.config.letsencrypt.challenge | ||
}, | ||
async remove (data) { | ||
WIKI.logger.info(`(LETSENCRYPT) Removing HTTP challenge: [ OK ]`) | ||
WIKI.config.letsencrypt.challenge = null | ||
return null // <- this is needed, cannot be undefined | ||
} | ||
} | ||
} | ||
}) | ||
WIKI.logger.info(`(LETSENCRYPT) New certifiate received successfully: [ COMPLETED ]`) | ||
WIKI.config.letsencrypt.payload = certResp | ||
WIKI.config.letsencrypt.domain = WIKI.config.ssl.domain | ||
await WIKI.configSvc.saveToDb(['letsencrypt']) | ||
} catch (err) { | ||
WIKI.logger.warn(`(LETSENCRYPT) ${err}`) | ||
throw err | ||
} | ||
} | ||
} |
Oops, something went wrong.