| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 | 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-apiconst 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.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.subscriberEmail,          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    }  }}
 |