From a8e4d405d57121d65bf46fe2fca6d38c190a3adf Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 26 Apr 2020 20:42:24 +0100 Subject: [PATCH] feat: add ACME.js propagationDelay support fix: wait 10 seconds before attempting first propagation check, to prevent poluting the DNS cache with an invalid result Work towards implementing suggestions in #9 --- CHANGELOG.md | 4 ++++ index.js | 43 ++++++++++++++++++++++++------------------- package-lock.json | 40 ++++++++++++++++++++-------------------- package.json | 2 +- test.js | 3 ++- 5 files changed, 51 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f9328a..1d64076 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.2.0] - 2020-04-26 +- Add ACME.js propagationDelay support +- Wait 10 seconds before attempting first propagation check, to prevent poluting the DNS cache with an invalid result + ## [1.1.1] - 2020-02-04 - Simplify promise handlers diff --git a/index.js b/index.js index 5baad0e..efd07c8 100644 --- a/index.js +++ b/index.js @@ -38,13 +38,18 @@ function delay(ms){ } class Challenge { - constructor(options){ + constructor(options = {}){ this.options = options; this.client = new cloudflare({ email: options.email, key: options.key, token: options.token }); + this.propagationDelay = options.propagationDelay || 15000; // set propagationDelay for ACME.js + if(this.options.verifyPropagation){ + // if our own propagation is set, like is required for greenlock.js at time of writing, disable use native ACME.js propagation delay to prevent double verification + this.propagationDelay = 0; + } } static create(config){ @@ -52,7 +57,7 @@ class Challenge { } async init(){ - return Promise.resolve(null); + return null; } async set(args){ @@ -72,7 +77,10 @@ class Challenge { content: args.challenge.dnsAuthorization, ttl: 120 }); + // verify propagation if(this.options.verifyPropagation){ + // wait for one "tick" before attempting to query. This can help prevent the DNS cache from getting polluted with a bad value + await delay(this.options.waitFor || 10000); await Challenge.verifyPropagation(args.challenge, this.options.verbose, this.options.waitFor, this.options.retries); } return null; @@ -100,8 +108,12 @@ class Challenge { await this.client.dnsRecords.del(zone.id, record.id); } } - // allow time for deletion to propagate - await Challenge.verifyPropagation(Object.assign({}, args.challenge, {removed: true}), this.options.verbose); + if(this.options.verifyPropagation){ + // wait for one "tick" before attempting to query. This can help prevent the DNS cache from getting polluted with a bad value + await delay(this.options.waitFor || 10000); + // allow time for deletion to propagate + await Challenge.verifyPropagation(Object.assign({}, args.challenge, {removed: true}), this.options.verbose); + } return null; }catch(err){ throw new Error(err); @@ -146,9 +158,7 @@ class Challenge { async zones(args){ // eslint-disable-line no-unused-vars try{ const zones = []; - for await(const zone of consumePages((pagination) => { - this.client.zones.browse(pagination); - })){ + for await(const zone of consumePages(pagination => this.client.zones.browse(pagination))){ zones.push(zone.name); } return zones; @@ -181,8 +191,7 @@ class Challenge { return; } if(verbose){ - console.error(err); - console.log(`Waiting for ${waitFor} ms before attempting propagation verification retry ${i + 1} / ${retries}.`); + console.log(`DNS not propagated yet for ${fullRecordName}. Checking again in ${waitFor}ms. (Attempt ${i + 1} / ${retries})`); } await delay(waitFor); } @@ -191,9 +200,7 @@ class Challenge { } async getZoneForDomain(domain){ - for await(const zone of consumePages((pagination) => { - this.client.zones.browse(pagination); - })){ + for await(const zone of consumePages(pagination => this.client.zones.browse(pagination))){ if(domain.endsWith(zone.name)){ return zone; } @@ -204,13 +211,11 @@ class Challenge { async getTxtRecords(zone, name){ const records = []; - for await(const txtRecord of consumePages((pagination) => { - this.client.dnsRecords.browse(zone.id, { - ...pagination, - type: 'TXT', - name - }); - })){ + for await(const txtRecord of consumePages(pagination => this.client.dnsRecords.browse(zone.id, { + ...pagination, + type: 'TXT', + name + }))){ if(txtRecord.name === name){ records.push(txtRecord); } diff --git a/package-lock.json b/package-lock.json index 3e4deb5..e4dbb6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "acme-dns-01-cloudflare", - "version": "1.1.1", + "version": "1.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -81,9 +81,9 @@ } }, "ajv": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", - "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -198,9 +198,9 @@ } }, "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", "dev": true }, "cloudflare": { @@ -498,18 +498,18 @@ "dev": true }, "esquery": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.2.0.tgz", - "integrity": "sha512-weltsSqdeWIX9G2qQZz7KlTRJdkkOCTPgLYJUz1Hacf48R4YOwGPHO3+ORfWedqJKbq5WQmsgK90n+pFLIKt/Q==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", "dev": true, "requires": { - "estraverse": "^5.0.0" + "estraverse": "^5.1.0" }, "dependencies": { "estraverse": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.0.0.tgz", - "integrity": "sha512-j3acdrMzqrxmJTNj5dbr1YbjacrYgAxVMeF0gK16E3j494mOe7xygM/ZLIguEQ0ETwAg2hlJCtHRGav+y0Ny5A==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", "dev": true } } @@ -832,9 +832,9 @@ } }, "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true }, "is-redirect": { @@ -1066,9 +1066,9 @@ "dev": true }, "resolve": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", - "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", "dev": true, "requires": { "path-parse": "^1.0.6" diff --git a/package.json b/package.json index 6bcc241..d4a67bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "acme-dns-01-cloudflare", - "version": "1.1.1", + "version": "1.2.0", "description": "Cloudflare DNS for Let's Encrypt / ACME dns-01 challenges with Greenlock.js and ACME.js", "keywords": [ "acme", diff --git a/test.js b/test.js index 51a6e27..d64bacf 100644 --- a/test.js +++ b/test.js @@ -16,7 +16,8 @@ const challenger = require("./index.js").create({ token: process.env.CLOUDFLARE_TOKEN, email: process.env.CLOUDFLARE_EMAIL, key: process.env.CLOUDFLARE_APIKEY, - verifyPropagation: true + verifyPropagation: true, + verbose: true }); const domain = process.env.DOMAIN;