mirror of
				https://github.com/therootcompany/acme.js.git
				synced 2024-11-16 17:29:00 +00:00 
			
		
		
		
	v1.7.1: don't self-poison dns cache, more consistency
This commit is contained in:
		
							parent
							
								
									b1182457cd
								
							
						
					
					
						commit
						e5e7377712
					
				
							
								
								
									
										194
									
								
								node.js
									
									
									
									
									
								
							
							
						
						
									
										194
									
								
								node.js
									
									
									
									
									
								
							| @ -47,10 +47,9 @@ ACME.challengeTests = { | |||||||
|   } |   } | ||||||
| , 'dns-01': function (me, auth) { | , 'dns-01': function (me, auth) { | ||||||
|     // remove leading *. on wildcard domains
 |     // remove leading *. on wildcard domains
 | ||||||
|     var hostname = ACME.challengePrefixes['dns-01'] + '.' + auth.hostname.replace(/^\*\./, ''); |  | ||||||
|     return me._dig({ |     return me._dig({ | ||||||
|       type: 'TXT' |       type: 'TXT' | ||||||
|     , name: hostname |     , name: auth.dnsHost | ||||||
|     }).then(function (ans) { |     }).then(function (ans) { | ||||||
|       var err; |       var err; | ||||||
| 
 | 
 | ||||||
| @ -62,7 +61,7 @@ ACME.challengeTests = { | |||||||
| 
 | 
 | ||||||
|       err = new Error( |       err = new Error( | ||||||
|         "Error: Failed DNS-01 Pre-Flight Dry Run.\n" |         "Error: Failed DNS-01 Pre-Flight Dry Run.\n" | ||||||
|       + "dig TXT '" + hostname + "' does not return '" + auth.dnsAuthorization + "'\n" |       + "dig TXT '" + auth.dnsHost + "' does not return '" + auth.dnsAuthorization + "'\n" | ||||||
|       + "See https://git.coolaj86.com/coolaj86/acme-v2.js/issues/4" |       + "See https://git.coolaj86.com/coolaj86/acme-v2.js/issues/4" | ||||||
|       ); |       ); | ||||||
|       err.code = 'E_FAIL_DRY_CHALLENGE'; |       err.code = 'E_FAIL_DRY_CHALLENGE'; | ||||||
| @ -164,7 +163,7 @@ ACME._registerAccount = function (me, options) { | |||||||
|           options.accountKeypair |           options.accountKeypair | ||||||
|         , undefined |         , undefined | ||||||
|         , { nonce: me._nonce |         , { nonce: me._nonce | ||||||
|           , alg: 'RS256' |           , alg: (me._alg || 'RS256') | ||||||
|           , url: me._directoryUrls.newAccount |           , url: me._directoryUrls.newAccount | ||||||
|           , jwk: jwk |           , jwk: jwk | ||||||
|           } |           } | ||||||
| @ -296,48 +295,58 @@ ACME._testChallenges = function (me, options) { | |||||||
|     return Promise.resolve(); |     return Promise.resolve(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   var CHECK_DELAY = 0; | ||||||
|   return Promise.all(options.domains.map(function (identifierValue) { |   return Promise.all(options.domains.map(function (identifierValue) { | ||||||
|     // TODO we really only need one to pass, not all to pass
 |     // TODO we really only need one to pass, not all to pass
 | ||||||
|     var results = ACME._testChallengeOptions(); |     var challenges = ACME._testChallengeOptions(); | ||||||
|     if (identifierValue.inludes("*")) { |     if (identifierValue.includes("*")) { | ||||||
|       results = results.filter(function (ch) { return ch._wildcard; }); |       challenges = challenges.filter(function (ch) { return ch._wildcard; }); | ||||||
|     } |     } | ||||||
|     var challenge = ACME._chooseChallenge(options, results); | 
 | ||||||
|  |     var challenge = ACME._chooseChallenge(options, { challenges: challenges }); | ||||||
|     if (!challenge) { |     if (!challenge) { | ||||||
|       // For example, wildcards require dns-01 and, if we don't have that, we have to bail
 |       // For example, wildcards require dns-01 and, if we don't have that, we have to bail
 | ||||||
|       var enabled = options.challengeTypes.join(', ') || 'none'; |       var enabled = options.challengeTypes.join(', ') || 'none'; | ||||||
|       var suitable = results.map(function (r) { return r.type; }).join(', ') || 'none'; |       var suitable = challenges.map(function (r) { return r.type; }).join(', ') || 'none'; | ||||||
|       return Promise.reject(new Error( |       return Promise.reject(new Error( | ||||||
|         "None of the challenge types that you've enabled ( " + enabled + " )" |         "None of the challenge types that you've enabled ( " + enabled + " )" | ||||||
|           + " are suitable for validating the domain you've selected (" + identifierValue + ")." |           + " are suitable for validating the domain you've selected (" + identifierValue + ")." | ||||||
|           + " You must enable one of ( " + suitable + " )." |           + " You must enable one of ( " + suitable + " )." | ||||||
|       )); |       )); | ||||||
|     } |     } | ||||||
|     return Promise.resolve().then(function () { |     if ('dns-01' === challenge.type) { | ||||||
|       var thumbprint = me.RSA.thumbprint(options.accountKeypair); |       // nameservers take a second to propagate
 | ||||||
|       var keyAuthorization = challenge.token + '.' + thumbprint; |       CHECK_DELAY = 5 * 1000; | ||||||
|       var auth = { |     } | ||||||
|         identifier: { type: "dns", value: identifierValue } |  | ||||||
|       , hostname: identifierValue |  | ||||||
|       , type: challenge.type |  | ||||||
|       , token: challenge.token |  | ||||||
|       , thumbprint: thumbprint |  | ||||||
|       , keyAuthorization: keyAuthorization |  | ||||||
|       , dnsAuthorization: ACME._toWebsafeBase64( |  | ||||||
|           require('crypto').createHash('sha256').update(keyAuthorization).digest('base64') |  | ||||||
|         ) |  | ||||||
|       }; |  | ||||||
| 
 | 
 | ||||||
|  |     return Promise.resolve().then(function () { | ||||||
|  |       var results = { | ||||||
|  |         identifier: { | ||||||
|  |           type: "dns" | ||||||
|  |         , value: identifierValue.replace(/^\*\./, '') | ||||||
|  |         , wildcard: identifierValue.includes('*.') || undefined | ||||||
|  |         } | ||||||
|  |       , challenges: [ challenge ] | ||||||
|  |       , expires: new Date(Date.now() + (60 * 1000)).toISOString() | ||||||
|  |       }; | ||||||
|  |       var dryrun = true; | ||||||
|  |       var auth = ACME._challengeToAuth(me, options, results, challenge, dryrun); | ||||||
|       return ACME._setChallenge(me, options, auth).then(function () { |       return ACME._setChallenge(me, options, auth).then(function () { | ||||||
|         return ACME.challengeTests[challenge.type](me, auth); |         return auth; | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
|  |   })).then(function (auths) { | ||||||
|  |     return ACME._wait(CHECK_DELAY).then(function () { | ||||||
|  |       return Promise.all(auths.map(function (auth) { | ||||||
|  |         return ACME.challengeTests[auth.type](me, auth); | ||||||
|       })); |       })); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
| }; | }; | ||||||
| ACME._chooseChallenge = function(options, results) { | ACME._chooseChallenge = function(options, results) { | ||||||
|   // For each of the challenge types that we support
 |   // For each of the challenge types that we support
 | ||||||
|   var challenge; |   var challenge; | ||||||
|   options.challengesTypes.some(function (chType) { |   options.challengeTypes.some(function (chType) { | ||||||
|     // And for each of the challenge types that are allowed
 |     // And for each of the challenge types that are allowed
 | ||||||
|     return results.challenges.some(function (ch) { |     return results.challenges.some(function (ch) { | ||||||
|       // Check to see if there are any matches
 |       // Check to see if there are any matches
 | ||||||
| @ -350,30 +359,57 @@ ACME._chooseChallenge = function(options, results) { | |||||||
| 
 | 
 | ||||||
|   return challenge; |   return challenge; | ||||||
| }; | }; | ||||||
|  | ACME._challengeToAuth = function (me, options, request, challenge, dryrun) { | ||||||
|  |   // we don't poison the dns cache with our dummy request
 | ||||||
|  |   var dnsPrefix = ACME.challengePrefixes['dns-01']; | ||||||
|  |   if (dryrun) { | ||||||
|  |     dnsPrefix = dnsPrefix.replace('acme-challenge', 'greenlock-dryrun-' + Math.random().toString().slice(2,6)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   var auth = {}; | ||||||
|  | 
 | ||||||
|  |   // straight copy from the new order response
 | ||||||
|  |   // { identifier, status, expires, challenges, wildcard }
 | ||||||
|  |   Object.keys(request).forEach(function (key) { | ||||||
|  |     auth[key] = request[key]; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   // copy from the challenge we've chosen
 | ||||||
|  |   // { type, status, url, token }
 | ||||||
|  |   // (note the duplicate status overwrites the one above, but they should be the same)
 | ||||||
|  |   Object.keys(challenge).forEach(function (key) { | ||||||
|  |     auth[key] = challenge[key]; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   // batteries-included helpers
 | ||||||
|  |   auth.hostname = request.identifier.value; | ||||||
|  |   auth.thumbprint = me.RSA.thumbprint(options.accountKeypair); | ||||||
|  |   //   keyAuthorization = token || '.' || base64url(JWK_Thumbprint(accountKey))
 | ||||||
|  |   auth.keyAuthorization = challenge.token + '.' + auth.thumbprint; | ||||||
|  |   auth.dnsHost = dnsPrefix + '.' + auth.hostname.replace('*.', ''); | ||||||
|  |   auth.dnsAuthorization = ACME._toWebsafeBase64( | ||||||
|  |     require('crypto').createHash('sha256').update(auth.keyAuthorization).digest('base64') | ||||||
|  |   ); | ||||||
|  |   // because I'm not 100% clear if the wildcard identifier does or doesn't have the leading *. in all cases
 | ||||||
|  |   auth.altname = ACME._untame(request.identifier.value, request.wildcard); | ||||||
|  | 
 | ||||||
|  |   return auth; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | ACME._untame = function (name, wild) { | ||||||
|  |   if (wild) { name = '*.' + name.replace('*.', ''); } | ||||||
|  |   return name; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| // https://tools.ietf.org/html/draft-ietf-acme-acme-10#section-7.5.1
 | // https://tools.ietf.org/html/draft-ietf-acme-acme-10#section-7.5.1
 | ||||||
| ACME._postChallenge = function (me, options, identifier, ch) { | ACME._postChallenge = function (me, options, auth) { | ||||||
|   var RETRY_INTERVAL = me.retryInterval || 1000; |   var RETRY_INTERVAL = me.retryInterval || 1000; | ||||||
|   var DEAUTH_INTERVAL = me.deauthWait || 10 * 1000; |   var DEAUTH_INTERVAL = me.deauthWait || 10 * 1000; | ||||||
|   var MAX_POLL = me.retryPoll || 8; |   var MAX_POLL = me.retryPoll || 8; | ||||||
|   var MAX_PEND = me.retryPending || 4; |   var MAX_PEND = me.retryPending || 4; | ||||||
|   var count = 0; |   var count = 0; | ||||||
| 
 | 
 | ||||||
|   var thumbprint = me.RSA.thumbprint(options.accountKeypair); |   var altname = ACME._untame(auth.identifier.value, auth.wildcard); | ||||||
|   var keyAuthorization = ch.token + '.' + thumbprint; |  | ||||||
|   //   keyAuthorization = token || '.' || base64url(JWK_Thumbprint(accountKey))
 |  | ||||||
|   //   /.well-known/acme-challenge/:token
 |  | ||||||
|   var auth = { |  | ||||||
|     identifier: identifier |  | ||||||
|   , hostname: identifier.value |  | ||||||
|   , type: ch.type |  | ||||||
|   , token: ch.token |  | ||||||
|   , thumbprint: thumbprint |  | ||||||
|   , keyAuthorization: keyAuthorization |  | ||||||
|   , dnsAuthorization: ACME._toWebsafeBase64( |  | ||||||
|       require('crypto').createHash('sha256').update(keyAuthorization).digest('base64') |  | ||||||
|     ) |  | ||||||
|   }; |  | ||||||
| 
 | 
 | ||||||
|   /* |   /* | ||||||
|    POST /acme/authz/1234 HTTP/1.1 |    POST /acme/authz/1234 HTTP/1.1 | ||||||
| @ -397,13 +433,13 @@ ACME._postChallenge = function (me, options, identifier, ch) { | |||||||
|     var jws = me.RSA.signJws( |     var jws = me.RSA.signJws( | ||||||
|       options.accountKeypair |       options.accountKeypair | ||||||
|     , undefined |     , undefined | ||||||
|     , { nonce: me._nonce, alg: (me._alg || 'RS256'), url: ch.url, kid: me._kid } |     , { nonce: me._nonce, alg: (me._alg || 'RS256'), url: auth.url, kid: me._kid } | ||||||
|     , Buffer.from(JSON.stringify({ "status": "deactivated" })) |     , Buffer.from(JSON.stringify({ "status": "deactivated" })) | ||||||
|     ); |     ); | ||||||
|     me._nonce = null; |     me._nonce = null; | ||||||
|     return me._request({ |     return me._request({ | ||||||
|       method: 'POST' |       method: 'POST' | ||||||
|     , url: ch.url |     , url: auth.url | ||||||
|     , headers: { 'Content-Type': 'application/jose+json' } |     , headers: { 'Content-Type': 'application/jose+json' } | ||||||
|     , json: jws |     , json: jws | ||||||
|     }).then(function (resp) { |     }).then(function (resp) { | ||||||
| @ -422,14 +458,14 @@ ACME._postChallenge = function (me, options, identifier, ch) { | |||||||
|   function pollStatus() { |   function pollStatus() { | ||||||
|     if (count >= MAX_POLL) { |     if (count >= MAX_POLL) { | ||||||
|       return Promise.reject(new Error( |       return Promise.reject(new Error( | ||||||
|         "[acme-v2] stuck in bad pending/processing state for '" + identifier.value + "'" |         "[acme-v2] stuck in bad pending/processing state for '" + altname + "'" | ||||||
|       )); |       )); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     count += 1; |     count += 1; | ||||||
| 
 | 
 | ||||||
|     if (me.debug) { console.debug('\n[DEBUG] statusChallenge\n'); } |     if (me.debug) { console.debug('\n[DEBUG] statusChallenge\n'); } | ||||||
|     return me._request({ method: 'GET', url: ch.url, json: true }).then(function (resp) { |     return me._request({ method: 'GET', url: auth.url, json: true }).then(function (resp) { | ||||||
|       if ('processing' === resp.body.status) { |       if ('processing' === resp.body.status) { | ||||||
|         if (me.debug) { console.debug('poll: again'); } |         if (me.debug) { console.debug('poll: again'); } | ||||||
|         return ACME._wait(RETRY_INTERVAL).then(pollStatus); |         return ACME._wait(RETRY_INTERVAL).then(pollStatus); | ||||||
| @ -453,7 +489,12 @@ ACME._postChallenge = function (me, options, identifier, ch) { | |||||||
|           } else if (2 === options.removeChallenge.length) { |           } else if (2 === options.removeChallenge.length) { | ||||||
|             options.removeChallenge(auth, function (err) { return err; }); |             options.removeChallenge(auth, function (err) { return err; }); | ||||||
|           } else { |           } else { | ||||||
|             options.removeChallenge(identifier.value, ch.token, function () {}); |             if (!ACME._removeChallengeWarn) { | ||||||
|  |               console.warn("Please update to acme-v2 removeChallenge(options) <Promise> or removeChallenge(options, cb)."); | ||||||
|  |               console.warn("The API has been changed for compatibility with all ACME / Let's Encrypt challenge types."); | ||||||
|  |               ACME._removeChallengeWarn = true; | ||||||
|  |             } | ||||||
|  |             options.removeChallenge(auth.request.identifier, auth.token, function () {}); | ||||||
|           } |           } | ||||||
|         } catch(e) {} |         } catch(e) {} | ||||||
|         return resp.body; |         return resp.body; | ||||||
| @ -461,13 +502,13 @@ ACME._postChallenge = function (me, options, identifier, ch) { | |||||||
| 
 | 
 | ||||||
|       var errmsg; |       var errmsg; | ||||||
|       if (!resp.body.status) { |       if (!resp.body.status) { | ||||||
|         errmsg = "[acme-v2] (E_STATE_EMPTY) empty challenge state for '" + identifier.value + "':"; |         errmsg = "[acme-v2] (E_STATE_EMPTY) empty challenge state for '" + altname + "':"; | ||||||
|       } |       } | ||||||
|       else if ('invalid' === resp.body.status) { |       else if ('invalid' === resp.body.status) { | ||||||
|         errmsg = "[acme-v2] (E_STATE_INVALID) challenge state for '" + identifier.value + "': '" + resp.body.status + "'"; |         errmsg = "[acme-v2] (E_STATE_INVALID) challenge state for '" + altname + "': '" + resp.body.status + "'"; | ||||||
|       } |       } | ||||||
|       else { |       else { | ||||||
|         errmsg = "[acme-v2] (E_STATE_UKN) challenge state for '" + identifier.value + "': '" + resp.body.status + "'"; |         errmsg = "[acme-v2] (E_STATE_UKN) challenge state for '" + altname + "': '" + resp.body.status + "'"; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       return Promise.reject(new Error(errmsg)); |       return Promise.reject(new Error(errmsg)); | ||||||
| @ -478,13 +519,13 @@ ACME._postChallenge = function (me, options, identifier, ch) { | |||||||
|     var jws = me.RSA.signJws( |     var jws = me.RSA.signJws( | ||||||
|       options.accountKeypair |       options.accountKeypair | ||||||
|     , undefined |     , undefined | ||||||
|     , { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid } |     , { nonce: me._nonce, alg: (me._alg || 'RS256'), url: auth.url, kid: me._kid } | ||||||
|     , Buffer.from(JSON.stringify({ })) |     , Buffer.from(JSON.stringify({ })) | ||||||
|     ); |     ); | ||||||
|     me._nonce = null; |     me._nonce = null; | ||||||
|     return me._request({ |     return me._request({ | ||||||
|       method: 'POST' |       method: 'POST' | ||||||
|     , url: ch.url |     , url: auth.url | ||||||
|     , headers: { 'Content-Type': 'application/jose+json' } |     , headers: { 'Content-Type': 'application/jose+json' } | ||||||
|     , json: jws |     , json: jws | ||||||
|     }).then(function (resp) { |     }).then(function (resp) { | ||||||
| @ -519,6 +560,11 @@ ACME._setChallenge = function (me, options, auth) { | |||||||
|         Object.keys(auth).forEach(function (key) { |         Object.keys(auth).forEach(function (key) { | ||||||
|           challengeCb[key] = auth[key]; |           challengeCb[key] = auth[key]; | ||||||
|         }); |         }); | ||||||
|  |         if (!ACME._setChallengeWarn) { | ||||||
|  |           console.warn("Please update to acme-v2 setChallenge(options) <Promise> or setChallenge(options, cb)."); | ||||||
|  |           console.warn("The API has been changed for compatibility with all ACME / Let's Encrypt challenge types."); | ||||||
|  |           ACME._setChallengeWarn = true; | ||||||
|  |         } | ||||||
|         options.setChallenge(auth.identifier.value, auth.token, auth.keyAuthorization, challengeCb); |         options.setChallenge(auth.identifier.value, auth.token, auth.keyAuthorization, challengeCb); | ||||||
|       } |       } | ||||||
|     } catch(e) { |     } catch(e) { | ||||||
| @ -541,7 +587,7 @@ ACME._finalizeOrder = function (me, options, validatedDomains) { | |||||||
|     var jws = me.RSA.signJws( |     var jws = me.RSA.signJws( | ||||||
|       options.accountKeypair |       options.accountKeypair | ||||||
|     , undefined |     , undefined | ||||||
|     , { nonce: me._nonce, alg: 'RS256', url: me._finalize, kid: me._kid } |     , { nonce: me._nonce, alg: (me._alg || 'RS256'), url: me._finalize, kid: me._kid } | ||||||
|     , Buffer.from(payload) |     , Buffer.from(payload) | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
| @ -642,14 +688,13 @@ ACME._getCertificate = function (me, options) { | |||||||
|   } |   } | ||||||
|   // TODO check that all challengeTypes are represented in challenges
 |   // TODO check that all challengeTypes are represented in challenges
 | ||||||
|   if (!options.challengeTypes.length) { |   if (!options.challengeTypes.length) { | ||||||
|     return Promise.reject(new Error("options.challengesTypes (string array) must be specified" |     return Promise.reject(new Error("options.challengeTypes (string array) must be specified" | ||||||
|       + " (and in order of preferential priority).")); |       + " (and in order of preferential priority).")); | ||||||
|   } |   } | ||||||
|   if (!(options.domains && options.domains.length)) { |   if (!(options.domains && options.domains.length)) { | ||||||
|     return Promise.reject(new Error("options.domains must be a list of string domain names," |     return Promise.reject(new Error("options.domains must be a list of string domain names," | ||||||
|     + " with the first being the subject of the domain (or options.subject must specified).")); |     + " with the first being the subject of the domain (or options.subject must specified).")); | ||||||
|   } |   } | ||||||
|   if (!options.subject) { options.subject = options.domains[0]; } |  | ||||||
| 
 | 
 | ||||||
|   // It's just fine if there's no account, we'll go get the key id we need via the public key
 |   // It's just fine if there's no account, we'll go get the key id we need via the public key
 | ||||||
|   if (!me._kid) { |   if (!me._kid) { | ||||||
| @ -670,8 +715,15 @@ ACME._getCertificate = function (me, options) { | |||||||
|     if (me.debug) { console.debug('[acme-v2] certificates.create'); } |     if (me.debug) { console.debug('[acme-v2] certificates.create'); } | ||||||
|     return ACME._getNonce(me).then(function () { |     return ACME._getNonce(me).then(function () { | ||||||
|       var body = { |       var body = { | ||||||
|         identifiers: options.domains.map(function (hostname) { |         // raw wildcard syntax MUST be used here
 | ||||||
|           return { type: "dns" , value: hostname }; |         identifiers: options.domains.sort(function (a, b) { | ||||||
|  |           // the first in the list will be the subject of the certificate, I believe (and hope)
 | ||||||
|  |           if (!options.subject) { return 0; } | ||||||
|  |           if (options.subject === a) { return -1; } | ||||||
|  |           if (options.subject === b) { return 1; } | ||||||
|  |           return 0; | ||||||
|  |         }).map(function (hostname) { | ||||||
|  |           return { type: "dns", value: hostname }; | ||||||
|         }) |         }) | ||||||
|         //, "notBefore": "2016-01-01T00:00:00Z"
 |         //, "notBefore": "2016-01-01T00:00:00Z"
 | ||||||
|         //, "notAfter": "2016-01-08T00:00:00Z"
 |         //, "notAfter": "2016-01-08T00:00:00Z"
 | ||||||
| @ -698,7 +750,8 @@ ACME._getCertificate = function (me, options) { | |||||||
|       }).then(function (resp) { |       }).then(function (resp) { | ||||||
|         me._nonce = resp.toJSON().headers['replay-nonce']; |         me._nonce = resp.toJSON().headers['replay-nonce']; | ||||||
|         var location = resp.toJSON().headers.location; |         var location = resp.toJSON().headers.location; | ||||||
|         var auths; |         var setAuths; | ||||||
|  |         var auths = []; | ||||||
|         if (me.debug) { console.debug(location); } // the account id url
 |         if (me.debug) { console.debug(location); } // the account id url
 | ||||||
|         if (me.debug) { console.debug(resp.toJSON()); } |         if (me.debug) { console.debug(resp.toJSON()); } | ||||||
|         me._authorizations = resp.body.authorizations; |         me._authorizations = resp.body.authorizations; | ||||||
| @ -713,12 +766,10 @@ ACME._getCertificate = function (me, options) { | |||||||
|           )); |           )); | ||||||
|         } |         } | ||||||
|         if (me.debug) { console.debug("[acme-v2] POST newOrder has authorizations"); } |         if (me.debug) { console.debug("[acme-v2] POST newOrder has authorizations"); } | ||||||
|  |         setAuths = me._authorizations.slice(0); | ||||||
| 
 | 
 | ||||||
|         //return resp.body;
 |         function setNext() { | ||||||
|         auths = me._authorizations.slice(0); |           var authUrl = setAuths.shift(); | ||||||
| 
 |  | ||||||
|         function next() { |  | ||||||
|           var authUrl = auths.shift(); |  | ||||||
|           if (!authUrl) { return; } |           if (!authUrl) { return; } | ||||||
| 
 | 
 | ||||||
|           return ACME._getChallenges(me, options, authUrl).then(function (results) { |           return ACME._getChallenges(me, options, authUrl).then(function (results) { | ||||||
| @ -726,7 +777,7 @@ ACME._getCertificate = function (me, options) { | |||||||
| 
 | 
 | ||||||
|             // If it's already valid, we're golden it regardless
 |             // If it's already valid, we're golden it regardless
 | ||||||
|             if (results.challenges.some(function (ch) { return 'valid' === ch.status; })) { |             if (results.challenges.some(function (ch) { return 'valid' === ch.status; })) { | ||||||
|               return; |               return setNext(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             var challenge = ACME._chooseChallenge(options, results); |             var challenge = ACME._chooseChallenge(options, results); | ||||||
| @ -737,13 +788,22 @@ ACME._getCertificate = function (me, options) { | |||||||
|               )); |               )); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return ACME._postChallenge(me, options, results.identifier, challenge); |             var auth = ACME._challengeToAuth(me, options, results, challenge); | ||||||
|           }).then(function () { |             auths.push(auth); | ||||||
|             return next(); |             return ACME._setChallenge(me, options, auth).then(setNext); | ||||||
|           }); |           }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return next().then(function () { |         function challengeNext() { | ||||||
|  |           var auth = auths.shift(); | ||||||
|  |           if (!auth) { return; } | ||||||
|  |           return ACME._postChallenge(me, options, auth).then(challengeNext); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // First we set every challenge
 | ||||||
|  |         // Then we ask for each challenge to be checked
 | ||||||
|  |         // Doing otherwise would potentially cause us to poison our own DNS cache with misses
 | ||||||
|  |         return setNext().then(challengeNext).then(function () { | ||||||
|           if (me.debug) { console.debug("[getCertificate] next.then"); } |           if (me.debug) { console.debug("[getCertificate] next.then"); } | ||||||
|           var validatedDomains = body.identifiers.map(function (ident) { |           var validatedDomains = body.identifiers.map(function (ident) { | ||||||
|             return ident.value; |             return ident.value; | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "acme-v2", |   "name": "acme-v2", | ||||||
|   "version": "1.7.0", |   "version": "1.7.1", | ||||||
|   "description": "Free SSL. A framework for building Let's Encrypt v2 clients, and other ACME v2 (draft 11) clients. Successor to le-acme-core.js", |   "description": "Free SSL. A framework for building Let's Encrypt v2 clients, and other ACME v2 (draft 11) clients. Successor to le-acme-core.js", | ||||||
|   "homepage": "https://git.coolaj86.com/coolaj86/acme-v2.js", |   "homepage": "https://git.coolaj86.com/coolaj86/acme-v2.js", | ||||||
|   "main": "node.js", |   "main": "node.js", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user