mirror of
				https://github.com/therootcompany/acme.js.git
				synced 2024-11-16 17:29:00 +00:00 
			
		
		
		
	v1.5.0: perform full test challenge first
This commit is contained in:
		
							parent
							
								
									85a38f7b54
								
							
						
					
					
						commit
						d802fb4957
					
				| @ -193,6 +193,8 @@ ACME.challengePrefixes['dns-01']              // '_acme-challenge' | ||||
| 
 | ||||
| # Changelog | ||||
| 
 | ||||
| * v1.5 | ||||
|   * perform full test challenge first (even before nonce) | ||||
| * v1.3 | ||||
|   * Use node RSA keygen by default | ||||
|   * No non-optional external deps! | ||||
|  | ||||
							
								
								
									
										469
									
								
								node.js
									
									
									
									
									
								
							
							
						
						
									
										469
									
								
								node.js
									
									
									
									
									
								
							| @ -16,6 +16,9 @@ ACME.splitPemChain = function splitPemChain(str) { | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // http-01: GET https://example.org/.well-known/acme-challenge/{{token}} => {{keyAuth}}
 | ||||
| // dns-01: TXT _acme-challenge.example.org. => "{{urlSafeBase64(sha256(keyAuth))}}"
 | ||||
| ACME.challengePrefixes = { | ||||
|   'http-01': '/.well-known/acme-challenge' | ||||
| , 'dns-01': '_acme-challenge' | ||||
| @ -255,6 +258,37 @@ ACME._wait = function wait(ms) { | ||||
|     setTimeout(resolve, (ms || 1100)); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| ACME._testChallenges = function (me, options) { | ||||
|   if (me.skipChallengeTest) { | ||||
|     return Promise.resolve(); | ||||
|   } | ||||
| 
 | ||||
|   return Promise.all(options.domains.map(function (identifierValue) { | ||||
|     // TODO we really only need one to pass, not all to pass
 | ||||
|     return Promise.all(options.challengeTypes.map(function (chType) { | ||||
|       var chToken = require('crypto').randomBytes(16).toString('hex'); | ||||
|       var thumbprint = me.RSA.thumbprint(options.accountKeypair); | ||||
|       var keyAuthorization = chToken + '.' + thumbprint; | ||||
|       var auth = { | ||||
|         identifier: { type: "dns", value: identifierValue } | ||||
|       , hostname: identifierValue | ||||
|       , type: chType | ||||
|       , token: chToken | ||||
|       , thumbprint: thumbprint | ||||
|       , keyAuthorization: keyAuthorization | ||||
|       , dnsAuthorization: me.RSA.utils.toWebsafeBase64( | ||||
|           require('crypto').createHash('sha256').update(keyAuthorization).digest('base64') | ||||
|         ) | ||||
|       }; | ||||
| 
 | ||||
|       return ACME._setChallenge(me, options, auth).then(function () { | ||||
|         return ACME.challengeTests[chType](me, auth); | ||||
|       }); | ||||
|     })); | ||||
|   })); | ||||
| }; | ||||
| 
 | ||||
| // https://tools.ietf.org/html/draft-ietf-acme-acme-10#section-7.5.1
 | ||||
| ACME._postChallenge = function (me, options, identifier, ch) { | ||||
|   var RETRY_INTERVAL = me.retryInterval || 1000; | ||||
| @ -279,172 +313,157 @@ ACME._postChallenge = function (me, options, identifier, ch) { | ||||
|     ) | ||||
|   }; | ||||
| 
 | ||||
|   return new Promise(function (resolve, reject) { | ||||
|     /* | ||||
|      POST /acme/authz/1234 HTTP/1.1 | ||||
|      Host: example.com | ||||
|      Content-Type: application/jose+json | ||||
|   /* | ||||
|    POST /acme/authz/1234 HTTP/1.1 | ||||
|    Host: example.com | ||||
|    Content-Type: application/jose+json | ||||
| 
 | ||||
|      { | ||||
|        "protected": base64url({ | ||||
|          "alg": "ES256", | ||||
|          "kid": "https://example.com/acme/acct/1", | ||||
|          "nonce": "xWCM9lGbIyCgue8di6ueWQ", | ||||
|          "url": "https://example.com/acme/authz/1234" | ||||
|        }), | ||||
|        "payload": base64url({ | ||||
|          "status": "deactivated" | ||||
|        }), | ||||
|        "signature": "srX9Ji7Le9bjszhu...WTFdtujObzMtZcx4" | ||||
|      } | ||||
|      */ | ||||
|     function deactivate() { | ||||
|       var jws = me.RSA.signJws( | ||||
|         options.accountKeypair | ||||
|       , undefined | ||||
|       , { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid } | ||||
|       , Buffer.from(JSON.stringify({ "status": "deactivated" })) | ||||
|       ); | ||||
|       me._nonce = null; | ||||
|       return me._request({ | ||||
|         method: 'POST' | ||||
|       , url: ch.url | ||||
|       , headers: { 'Content-Type': 'application/jose+json' } | ||||
|       , json: jws | ||||
|       }).then(function (resp) { | ||||
|         if (me.debug) { console.debug('[acme-v2.js] deactivate:'); } | ||||
|         if (me.debug) { console.debug(resp.headers); } | ||||
|         if (me.debug) { console.debug(resp.body); } | ||||
|         if (me.debug) { console.debug(); } | ||||
|    { | ||||
|      "protected": base64url({ | ||||
|        "alg": "ES256", | ||||
|        "kid": "https://example.com/acme/acct/1", | ||||
|        "nonce": "xWCM9lGbIyCgue8di6ueWQ", | ||||
|        "url": "https://example.com/acme/authz/1234" | ||||
|      }), | ||||
|      "payload": base64url({ | ||||
|        "status": "deactivated" | ||||
|      }), | ||||
|      "signature": "srX9Ji7Le9bjszhu...WTFdtujObzMtZcx4" | ||||
|    } | ||||
|    */ | ||||
|   function deactivate() { | ||||
|     var jws = me.RSA.signJws( | ||||
|       options.accountKeypair | ||||
|     , undefined | ||||
|     , { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid } | ||||
|     , Buffer.from(JSON.stringify({ "status": "deactivated" })) | ||||
|     ); | ||||
|     me._nonce = null; | ||||
|     return me._request({ | ||||
|       method: 'POST' | ||||
|     , url: ch.url | ||||
|     , headers: { 'Content-Type': 'application/jose+json' } | ||||
|     , json: jws | ||||
|     }).then(function (resp) { | ||||
|       if (me.debug) { console.debug('[acme-v2.js] deactivate:'); } | ||||
|       if (me.debug) { console.debug(resp.headers); } | ||||
|       if (me.debug) { console.debug(resp.body); } | ||||
|       if (me.debug) { console.debug(); } | ||||
| 
 | ||||
|         me._nonce = resp.toJSON().headers['replay-nonce']; | ||||
|         if (me.debug) { console.debug('deactivate challenge: resp.body:'); } | ||||
|         if (me.debug) { console.debug(resp.body); } | ||||
|         return ACME._wait(DEAUTH_INTERVAL); | ||||
|       }); | ||||
|       me._nonce = resp.toJSON().headers['replay-nonce']; | ||||
|       if (me.debug) { console.debug('deactivate challenge: resp.body:'); } | ||||
|       if (me.debug) { console.debug(resp.body); } | ||||
|       return ACME._wait(DEAUTH_INTERVAL); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   function pollStatus() { | ||||
|     if (count >= MAX_POLL) { | ||||
|       return Promise.reject(new Error("[acme-v2] stuck in bad pending/processing state")); | ||||
|     } | ||||
| 
 | ||||
|     function pollStatus() { | ||||
|       if (count >= MAX_POLL) { | ||||
|         return Promise.reject(new Error("[acme-v2] stuck in bad pending/processing state")); | ||||
|     count += 1; | ||||
| 
 | ||||
|     if (me.debug) { console.debug('\n[DEBUG] statusChallenge\n'); } | ||||
|     return me._request({ method: 'GET', url: ch.url, json: true }).then(function (resp) { | ||||
|       if ('processing' === resp.body.status) { | ||||
|         if (me.debug) { console.debug('poll: again'); } | ||||
|         return ACME._wait(RETRY_INTERVAL).then(pollStatus); | ||||
|       } | ||||
| 
 | ||||
|       count += 1; | ||||
| 
 | ||||
|       if (me.debug) { console.debug('\n[DEBUG] statusChallenge\n'); } | ||||
|       return me._request({ method: 'GET', url: ch.url, json: true }).then(function (resp) { | ||||
| 
 | ||||
|         if ('processing' === resp.body.status) { | ||||
|           if (me.debug) { console.debug('poll: again'); } | ||||
|           return ACME._wait(RETRY_INTERVAL).then(pollStatus); | ||||
|       // This state should never occur
 | ||||
|       if ('pending' === resp.body.status) { | ||||
|         if (count >= MAX_PEND) { | ||||
|           return ACME._wait(RETRY_INTERVAL).then(deactivate).then(respondToChallenge); | ||||
|         } | ||||
|         if (me.debug) { console.debug('poll: again'); } | ||||
|         return ACME._wait(RETRY_INTERVAL).then(respondToChallenge); | ||||
|       } | ||||
| 
 | ||||
|         // This state should never occur
 | ||||
|         if ('pending' === resp.body.status) { | ||||
|           if (count >= MAX_PEND) { | ||||
|             return ACME._wait(RETRY_INTERVAL).then(deactivate).then(testChallenge); | ||||
|       if ('valid' === resp.body.status) { | ||||
|         if (me.debug) { console.debug('poll: valid'); } | ||||
| 
 | ||||
|         try { | ||||
|           if (1 === options.removeChallenge.length) { | ||||
|             options.removeChallenge(auth).then(function () {}, function () {}); | ||||
|           } else if (2 === options.removeChallenge.length) { | ||||
|             options.removeChallenge(auth, function (err) { return err; }); | ||||
|           } else { | ||||
|             options.removeChallenge(identifier.value, ch.token, function () {}); | ||||
|           } | ||||
|           if (me.debug) { console.debug('poll: again'); } | ||||
|           return ACME._wait(RETRY_INTERVAL).then(testChallenge); | ||||
|         } | ||||
|         } catch(e) {} | ||||
|         return resp.body; | ||||
|       } | ||||
| 
 | ||||
|         if ('valid' === resp.body.status) { | ||||
|           if (me.debug) { console.debug('poll: valid'); } | ||||
|       if (!resp.body.status) { | ||||
|         console.error("[acme-v2] (E_STATE_EMPTY) empty challenge state:"); | ||||
|       } | ||||
|       else if ('invalid' === resp.body.status) { | ||||
|         console.error("[acme-v2] (E_STATE_INVALID) challenge state: '" + resp.body.status + "'"); | ||||
|       } | ||||
|       else { | ||||
|         console.error("[acme-v2] (E_STATE_UKN) challenge state: '" + resp.body.status + "'"); | ||||
|       } | ||||
| 
 | ||||
|           try { | ||||
|             if (1 === options.removeChallenge.length) { | ||||
|               options.removeChallenge(auth).then(function () {}, function () {}); | ||||
|             } else if (2 === options.removeChallenge.length) { | ||||
|               options.removeChallenge(auth, function (err) { return err; }); | ||||
|             } else { | ||||
|               options.removeChallenge(identifier.value, ch.token, function () {}); | ||||
|             } | ||||
|           } catch(e) {} | ||||
|           return resp.body; | ||||
|         } | ||||
|       return Promise.reject(new Error("[acme-v2] [error] unacceptable challenge state '" + resp.body.status + "'")); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|         if (!resp.body.status) { | ||||
|           console.error("[acme-v2] (E_STATE_EMPTY) empty challenge state:"); | ||||
|         } | ||||
|         else if ('invalid' === resp.body.status) { | ||||
|           console.error("[acme-v2] (E_STATE_INVALID) challenge state: '" + resp.body.status + "'"); | ||||
|         } | ||||
|         else { | ||||
|           console.error("[acme-v2] (E_STATE_UKN) challenge state: '" + resp.body.status + "'"); | ||||
|         } | ||||
|   function respondToChallenge() { | ||||
|     var jws = me.RSA.signJws( | ||||
|       options.accountKeypair | ||||
|     , undefined | ||||
|     , { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid } | ||||
|     , Buffer.from(JSON.stringify({ })) | ||||
|     ); | ||||
|     me._nonce = null; | ||||
|     return me._request({ | ||||
|       method: 'POST' | ||||
|     , url: ch.url | ||||
|     , headers: { 'Content-Type': 'application/jose+json' } | ||||
|     , json: jws | ||||
|     }).then(function (resp) { | ||||
|       if (me.debug) { console.debug('[acme-v2.js] challenge accepted!'); } | ||||
|       if (me.debug) { console.debug(resp.headers); } | ||||
|       if (me.debug) { console.debug(resp.body); } | ||||
|       if (me.debug) { console.debug(); } | ||||
| 
 | ||||
|         return Promise.reject(new Error("[acme-v2] [error] unacceptable challenge state '" + resp.body.status + "'")); | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     function respondToChallenge() { | ||||
|       var jws = me.RSA.signJws( | ||||
|         options.accountKeypair | ||||
|       , undefined | ||||
|       , { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid } | ||||
|       , Buffer.from(JSON.stringify({ })) | ||||
|       ); | ||||
|       me._nonce = null; | ||||
|       return me._request({ | ||||
|         method: 'POST' | ||||
|       , url: ch.url | ||||
|       , headers: { 'Content-Type': 'application/jose+json' } | ||||
|       , json: jws | ||||
|       }).then(function (resp) { | ||||
|         if (me.debug) { console.debug('[acme-v2.js] challenge accepted!'); } | ||||
|         if (me.debug) { console.debug(resp.headers); } | ||||
|         if (me.debug) { console.debug(resp.body); } | ||||
|         if (me.debug) { console.debug(); } | ||||
| 
 | ||||
|         me._nonce = resp.toJSON().headers['replay-nonce']; | ||||
|         if (me.debug) { console.debug('respond to challenge: resp.body:'); } | ||||
|         if (me.debug) { console.debug(resp.body); } | ||||
|         return ACME._wait(RETRY_INTERVAL).then(pollStatus); | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     function testChallenge() { | ||||
|       // TODO put check dns / http checks here?
 | ||||
|       // http-01: GET https://example.org/.well-known/acme-challenge/{{token}} => {{keyAuth}}
 | ||||
|       // dns-01: TXT _acme-challenge.example.org. => "{{urlSafeBase64(sha256(keyAuth))}}"
 | ||||
| 
 | ||||
|       if (me.debug) {console.debug('\n[DEBUG] postChallenge\n'); } | ||||
|       //if (me.debug) console.debug('\n[DEBUG] stop to fix things\n'); return;
 | ||||
| 
 | ||||
|       return ACME._wait(RETRY_INTERVAL).then(function () { | ||||
|         if (!me.skipChallengeTest) { | ||||
|           return ACME.challengeTests[ch.type](me, auth); | ||||
|         } | ||||
|       }).then(respondToChallenge); | ||||
|     } | ||||
|       me._nonce = resp.toJSON().headers['replay-nonce']; | ||||
|       if (me.debug) { console.debug('respond to challenge: resp.body:'); } | ||||
|       if (me.debug) { console.debug(resp.body); } | ||||
|       return ACME._wait(RETRY_INTERVAL).then(pollStatus); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   return ACME._setChallenge(me, options, auth).then(respondToChallenge); | ||||
| }; | ||||
| ACME._setChallenge = function (me, options, auth) { | ||||
|   return new Promise(function (resolve, reject) { | ||||
|     try { | ||||
|       if (1 === options.setChallenge.length) { | ||||
|         options.setChallenge(auth).then(testChallenge).then(resolve, reject); | ||||
|         options.setChallenge(auth).then(resolve).catch(reject); | ||||
|       } else if (2 === options.setChallenge.length) { | ||||
|         options.setChallenge(auth, function (err) { | ||||
|           if(err) { | ||||
|             reject(err); | ||||
|           } else { | ||||
|             testChallenge().then(resolve, reject); | ||||
|           } | ||||
|           if(err) { reject(err); } else { resolve(); } | ||||
|         }); | ||||
|       } else { | ||||
|         var challengeCb = function(err) { | ||||
|           if(err) { | ||||
|             reject(err); | ||||
|           } else { | ||||
|             testChallenge().then(resolve, reject); | ||||
|           } | ||||
|           if(err) { reject(err); } else { resolve(); } | ||||
|         }; | ||||
|         // for backwards compat adding extra keys without changing params length
 | ||||
|         Object.keys(auth).forEach(function (key) { | ||||
|           challengeCb[key] = auth[key]; | ||||
|         }); | ||||
|         options.setChallenge(identifier.value, ch.token, keyAuthorization, challengeCb); | ||||
|         options.setChallenge(auth.identifier.value, auth.token, auth.keyAuthorization, challengeCb); | ||||
|       } | ||||
|     } catch(e) { | ||||
|       reject(e); | ||||
|     } | ||||
|   }).then(function () { | ||||
|     // TODO: Do we still need this delay? Or shall we leave it to plugins to account for themselves?
 | ||||
|     var DELAY = me.setChallengeWait || 500; | ||||
|     if (me.debug) { console.debug('\n[DEBUG] waitChallengeDelay %s\n', DELAY); } | ||||
|     return ACME._wait(DELAY); | ||||
|   }); | ||||
| }; | ||||
| ACME._finalizeOrder = function (me, options, validatedDomains) { | ||||
| @ -548,104 +567,106 @@ ACME._getCertificate = function (me, options) { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (me.debug) { console.debug('[acme-v2] certificates.create'); } | ||||
|   return ACME._getNonce(me).then(function () { | ||||
|     var body = { | ||||
|       identifiers: options.domains.map(function (hostname) { | ||||
|         return { type: "dns" , value: hostname }; | ||||
|       }) | ||||
|       //, "notBefore": "2016-01-01T00:00:00Z"
 | ||||
|       //, "notAfter": "2016-01-08T00:00:00Z"
 | ||||
|     }; | ||||
|   return ACME._testChallenges(me, options).then(function () { | ||||
|     if (me.debug) { console.debug('[acme-v2] certificates.create'); } | ||||
|     return ACME._getNonce(me).then(function () { | ||||
|       var body = { | ||||
|         identifiers: options.domains.map(function (hostname) { | ||||
|           return { type: "dns" , value: hostname }; | ||||
|         }) | ||||
|         //, "notBefore": "2016-01-01T00:00:00Z"
 | ||||
|         //, "notAfter": "2016-01-08T00:00:00Z"
 | ||||
|       }; | ||||
| 
 | ||||
|     var payload = JSON.stringify(body); | ||||
|     var jws = me.RSA.signJws( | ||||
|       options.accountKeypair | ||||
|     , undefined | ||||
|     , { nonce: me._nonce, alg: 'RS256', url: me._directoryUrls.newOrder, kid: me._kid } | ||||
|     , Buffer.from(payload) | ||||
|     ); | ||||
|       var payload = JSON.stringify(body); | ||||
|       var jws = me.RSA.signJws( | ||||
|         options.accountKeypair | ||||
|       , undefined | ||||
|       , { nonce: me._nonce, alg: 'RS256', url: me._directoryUrls.newOrder, kid: me._kid } | ||||
|       , Buffer.from(payload) | ||||
|       ); | ||||
| 
 | ||||
|     if (me.debug) { console.debug('\n[DEBUG] newOrder\n'); } | ||||
|     me._nonce = null; | ||||
|     return me._request({ | ||||
|       method: 'POST' | ||||
|     , url: me._directoryUrls.newOrder | ||||
|     , headers: { 'Content-Type': 'application/jose+json' } | ||||
|     , json: jws | ||||
|     }).then(function (resp) { | ||||
|       me._nonce = resp.toJSON().headers['replay-nonce']; | ||||
|       var location = resp.toJSON().headers.location; | ||||
|       var auths; | ||||
|       if (me.debug) { console.debug(location); } // the account id url
 | ||||
|       if (me.debug) { console.debug(resp.toJSON()); } | ||||
|       me._authorizations = resp.body.authorizations; | ||||
|       me._order = location; | ||||
|       me._finalize = resp.body.finalize; | ||||
|       //if (me.debug) console.debug('[DEBUG] finalize:', me._finalize); return;
 | ||||
|       if (me.debug) { console.debug('\n[DEBUG] newOrder\n'); } | ||||
|       me._nonce = null; | ||||
|       return me._request({ | ||||
|         method: 'POST' | ||||
|       , url: me._directoryUrls.newOrder | ||||
|       , headers: { 'Content-Type': 'application/jose+json' } | ||||
|       , json: jws | ||||
|       }).then(function (resp) { | ||||
|         me._nonce = resp.toJSON().headers['replay-nonce']; | ||||
|         var location = resp.toJSON().headers.location; | ||||
|         var auths; | ||||
|         if (me.debug) { console.debug(location); } // the account id url
 | ||||
|         if (me.debug) { console.debug(resp.toJSON()); } | ||||
|         me._authorizations = resp.body.authorizations; | ||||
|         me._order = location; | ||||
|         me._finalize = resp.body.finalize; | ||||
|         //if (me.debug) console.debug('[DEBUG] finalize:', me._finalize); return;
 | ||||
| 
 | ||||
|       if (!me._authorizations) { | ||||
|         console.error("[acme-v2.js] authorizations were not fetched:"); | ||||
|         console.error(resp.body); | ||||
|         return Promise.reject(new Error("authorizations were not fetched")); | ||||
|       } | ||||
|       if (me.debug) { console.debug("[acme-v2] POST newOrder has authorizations"); } | ||||
|         if (!me._authorizations) { | ||||
|           console.error("[acme-v2.js] authorizations were not fetched:"); | ||||
|           console.error(resp.body); | ||||
|           return Promise.reject(new Error("authorizations were not fetched")); | ||||
|         } | ||||
|         if (me.debug) { console.debug("[acme-v2] POST newOrder has authorizations"); } | ||||
| 
 | ||||
|       //return resp.body;
 | ||||
|       auths = me._authorizations.slice(0); | ||||
|         //return resp.body;
 | ||||
|         auths = me._authorizations.slice(0); | ||||
| 
 | ||||
|       function next() { | ||||
|         var authUrl = auths.shift(); | ||||
|         if (!authUrl) { return; } | ||||
|         function next() { | ||||
|           var authUrl = auths.shift(); | ||||
|           if (!authUrl) { return; } | ||||
| 
 | ||||
|         return ACME._getChallenges(me, options, authUrl).then(function (results) { | ||||
|           // var domain = options.domains[i]; // results.identifier.value
 | ||||
|           var chType = options.challengeTypes.filter(function (chType) { | ||||
|             return results.challenges.some(function (ch) { | ||||
|               return ch.type === chType; | ||||
|             }); | ||||
|           })[0]; | ||||
|           return ACME._getChallenges(me, options, authUrl).then(function (results) { | ||||
|             // var domain = options.domains[i]; // results.identifier.value
 | ||||
|             var chType = options.challengeTypes.filter(function (chType) { | ||||
|               return results.challenges.some(function (ch) { | ||||
|                 return ch.type === chType; | ||||
|               }); | ||||
|             })[0]; | ||||
| 
 | ||||
|           var challenge = results.challenges.filter(function (ch) { | ||||
|             if (chType === ch.type) { | ||||
|               return ch; | ||||
|             var challenge = results.challenges.filter(function (ch) { | ||||
|               if (chType === ch.type) { | ||||
|                 return ch; | ||||
|               } | ||||
|             })[0]; | ||||
| 
 | ||||
|             if (!challenge) { | ||||
|               return Promise.reject(new Error("Server didn't offer any challenge we can handle.")); | ||||
|             } | ||||
|           })[0]; | ||||
| 
 | ||||
|           if (!challenge) { | ||||
|             return Promise.reject(new Error("Server didn't offer any challenge we can handle.")); | ||||
|           } | ||||
|             return ACME._postChallenge(me, options, results.identifier, challenge); | ||||
|           }).then(function () { | ||||
|             return next(); | ||||
|           }); | ||||
|         } | ||||
| 
 | ||||
|           return ACME._postChallenge(me, options, results.identifier, challenge); | ||||
|         }).then(function () { | ||||
|           return next(); | ||||
|         }); | ||||
|       } | ||||
|         return next().then(function () { | ||||
|           if (me.debug) { console.debug("[getCertificate] next.then"); } | ||||
|           var validatedDomains = body.identifiers.map(function (ident) { | ||||
|             return ident.value; | ||||
|           }); | ||||
| 
 | ||||
|       return next().then(function () { | ||||
|         if (me.debug) { console.debug("[getCertificate] next.then"); } | ||||
|         var validatedDomains = body.identifiers.map(function (ident) { | ||||
|           return ident.value; | ||||
|         }); | ||||
| 
 | ||||
|         return ACME._finalizeOrder(me, options, validatedDomains); | ||||
|       }).then(function (order) { | ||||
|         if (me.debug) { console.debug('acme-v2: order was finalized'); } | ||||
|         return me._request({ method: 'GET', url: me._certificate, json: true }).then(function (resp) { | ||||
|           if (me.debug) { console.debug('acme-v2: csr submitted and cert received:'); } | ||||
|           // https://github.com/certbot/certbot/issues/5721
 | ||||
|           var certsarr = ACME.splitPemChain(ACME.formatPemChain((resp.body||''))); | ||||
|           //  cert, chain, fullchain, privkey, /*TODO, subject, altnames, issuedAt, expiresAt */
 | ||||
|           var certs = { | ||||
|             expires: order.expires | ||||
|           , identifiers: order.identifiers | ||||
|           //, authorizations: order.authorizations
 | ||||
|           , cert: certsarr.shift() | ||||
|           //, privkey: privkeyPem
 | ||||
|           , chain: certsarr.join('\n') | ||||
|           }; | ||||
|           if (me.debug) { console.debug(certs); } | ||||
|           return certs; | ||||
|           return ACME._finalizeOrder(me, options, validatedDomains); | ||||
|         }).then(function (order) { | ||||
|           if (me.debug) { console.debug('acme-v2: order was finalized'); } | ||||
|           return me._request({ method: 'GET', url: me._certificate, json: true }).then(function (resp) { | ||||
|             if (me.debug) { console.debug('acme-v2: csr submitted and cert received:'); } | ||||
|             // https://github.com/certbot/certbot/issues/5721
 | ||||
|             var certsarr = ACME.splitPemChain(ACME.formatPemChain((resp.body||''))); | ||||
|             //  cert, chain, fullchain, privkey, /*TODO, subject, altnames, issuedAt, expiresAt */
 | ||||
|             var certs = { | ||||
|               expires: order.expires | ||||
|             , identifiers: order.identifiers | ||||
|             //, authorizations: order.authorizations
 | ||||
|             , cert: certsarr.shift() | ||||
|             //, privkey: privkeyPem
 | ||||
|             , chain: certsarr.join('\n') | ||||
|             }; | ||||
|             if (me.debug) { console.debug(certs); } | ||||
|             return certs; | ||||
|           }); | ||||
|         }); | ||||
|       }); | ||||
|     }); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "acme-v2", | ||||
|   "version": "1.3.1", | ||||
|   "version": "1.5.0", | ||||
|   "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", | ||||
|   "main": "node.js", | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user