WIP Building out all features necessary for Let's Encrypt #6
							
								
								
									
										4
									
								
								app.js
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								app.js
									
									
									
									
									
								
							| @ -114,7 +114,7 @@ | ||||
|       acme.init('https://acme-staging-v02.api.letsencrypt.org/directory').then(function (result) { | ||||
|         console.log('acme result', result); | ||||
|         var privJwk = JSON.parse($('.js-jwk').innerText).private; | ||||
|         var email = $('.js-email').innerText; | ||||
|         var email = $('.js-email').value; | ||||
|         function checkTos(tos) { | ||||
|           console.log("TODO checkbox for agree to terms"); | ||||
|           return tos; | ||||
| @ -130,7 +130,7 @@ | ||||
|           , modulusLength: 2048 | ||||
|           }).then(function (pair) { | ||||
|             console.log('domain keypair:', pair); | ||||
|             var domains = ($('.js-domains').innerText||'example.com').split(/[, ]+/g); | ||||
|             var domains = ($('.js-domains').value||'example.com').split(/[, ]+/g); | ||||
|             return acme.certificates.create({ | ||||
|               accountKeypair: { privateKeyJwk: privJwk } | ||||
|             , account: account | ||||
|  | ||||
							
								
								
									
										91
									
								
								lib/acme.js
									
									
									
									
									
								
							
							
						
						
									
										91
									
								
								lib/acme.js
									
									
									
									
									
								
							| @ -29,20 +29,19 @@ ACME.challengePrefixes = { | ||||
| }; | ||||
| ACME.challengeTests = { | ||||
|   'http-01': function (me, auth) { | ||||
|     var url = 'http://' + auth.hostname + ACME.challengePrefixes['http-01'] + '/' + auth.token; | ||||
|     return me.request({ method: 'GET', url: url }).then(function (resp) { | ||||
|     return me.http01(auth).then(function (keyAuth) { | ||||
|       var err; | ||||
| 
 | ||||
|       // TODO limit the number of bytes that are allowed to be downloaded
 | ||||
|       if (auth.keyAuthorization === resp.body.toString('utf8').trim()) { | ||||
|       if (auth.keyAuthorization === (keyAuth||'').trim()) { | ||||
|         return true; | ||||
|       } | ||||
| 
 | ||||
|       err = new Error( | ||||
|         "Error: Failed HTTP-01 Pre-Flight / Dry Run.\n" | ||||
|       + "curl '" + url + "'\n" | ||||
|       + "curl '" + auth.challengeUrl + "'\n" | ||||
|       + "Expected: '" + auth.keyAuthorization + "'\n" | ||||
|       + "Got: '" + resp.body + "'\n" | ||||
|       + "Got: '" + keyAuth + "'\n" | ||||
|       + "See https://git.coolaj86.com/coolaj86/acme-v2.js/issues/4" | ||||
|       ); | ||||
|       err.code = 'E_FAIL_DRY_CHALLENGE'; | ||||
| @ -51,10 +50,7 @@ ACME.challengeTests = { | ||||
|   } | ||||
| , 'dns-01': function (me, auth) { | ||||
|     // remove leading *. on wildcard domains
 | ||||
|     return me.dig({ | ||||
|       type: 'TXT' | ||||
|     , name: auth.dnsHost | ||||
|     }).then(function (ans) { | ||||
|     return me.dns01(auth).then(function (ans) { | ||||
|       var err; | ||||
| 
 | ||||
|       if (ans.answer.some(function (txt) { | ||||
| @ -154,7 +150,7 @@ ACME._registerAccount = function (me, options) { | ||||
|             , kid: options.externalAccount.id | ||||
|             , url: me._directoryUrls.newAccount | ||||
|             } | ||||
|           , payload: Enc.strToBuf(JSON.stringify(pair.public)) | ||||
|           , payload: Enc.binToBuf(JSON.stringify(pair.public)) | ||||
|           }).then(function (jws) { | ||||
|             body.externalAccountBinding = jws; | ||||
|             return body; | ||||
| @ -390,6 +386,7 @@ ACME._challengeToAuth = function (me, options, request, challenge, dryrun) { | ||||
|       //   keyAuthorization = token || '.' || base64url(JWK_Thumbprint(accountKey))
 | ||||
|       auth.keyAuthorization = challenge.token + '.' + auth.thumbprint; | ||||
|       // conflicts with ACME challenge id url is already in use, so we call this challengeUrl instead
 | ||||
|       // TODO auth.http01Url ?
 | ||||
|       auth.challengeUrl = 'http://' + auth.identifier.value + ACME.challengePrefixes['http-01'] + '/' + auth.token; | ||||
|       auth.dnsHost = dnsPrefix + '.' + auth.hostname.replace('*.', ''); | ||||
| 
 | ||||
| @ -440,7 +437,7 @@ ACME._postChallenge = function (me, options, auth) { | ||||
|       options: options | ||||
|     , url: auth.url | ||||
|     , protected: { kid: options._kid } | ||||
|     , payload: Enc.strToBuf(JSON.stringify({ "status": "deactivated" })) | ||||
|     , payload: Enc.binToBuf(JSON.stringify({ "status": "deactivated" })) | ||||
|     }).then(function (resp) { | ||||
|       if (me.debug) { console.debug('deactivate challenge: resp.body:'); } | ||||
|       if (me.debug) { console.debug(resp.body); } | ||||
| @ -515,7 +512,7 @@ ACME._postChallenge = function (me, options, auth) { | ||||
|       options: options | ||||
|     , url: auth.url | ||||
|     , protected: { kid: options._kid } | ||||
|     , payload: Enc.strToBuf(JSON.stringify({})) | ||||
|     , payload: Enc.binToBuf(JSON.stringify({})) | ||||
|     }).then(function (resp) { | ||||
|       if (me.debug) { console.debug('respond to challenge: resp.body:'); } | ||||
|       if (me.debug) { console.debug(resp.body); } | ||||
| @ -576,7 +573,7 @@ ACME._finalizeOrder = function (me, options, validatedDomains) { | ||||
|         options: options | ||||
|       , url: options._finalize | ||||
|       , protected: { kid: options._kid } | ||||
|       , payload: Enc.strToBuf(payload) | ||||
|       , payload: Enc.binToBuf(payload) | ||||
|       }).then(function (resp) { | ||||
|         if (me.debug) { console.debug('order finalized: resp.body:'); } | ||||
|         if (me.debug) { console.debug(resp.body); } | ||||
| @ -717,7 +714,7 @@ ACME._getCertificate = function (me, options) { | ||||
|       options: options | ||||
|     , url: me._directoryUrls.newOrder | ||||
|     , protected: { kid: options._kid } | ||||
|     , payload: Enc.strToBuf(payload) | ||||
|     , payload: Enc.binToBuf(payload) | ||||
|     }).then(function (resp) { | ||||
|       var location = resp.headers.location; | ||||
|       var setAuths; | ||||
| @ -818,21 +815,21 @@ ACME.create = function create(me) { | ||||
|   me.challengePrefixes = ACME.challengePrefixes; | ||||
|   me.Keypairs = me.Keypairs || me.RSA || require('rsa-compat').RSA; | ||||
|   me._nonces = []; | ||||
|   if (!me._baseUrl) { | ||||
|     me._baseUrl = ""; | ||||
|   } | ||||
|   //me.Keypairs = me.Keypairs || require('keypairs');
 | ||||
|   //me.request = me.request || require('@root/request');
 | ||||
|   if (!me.dig) { | ||||
|     me.dig = function (query) { | ||||
|       // TODO use digd.js
 | ||||
|       return new me.request({ url: "/api/dns/" + query.name + "?type=" + query.type }).then(function (resp) { | ||||
|         if (!resp.body || !Array.isArray(resp.body.answer)) { | ||||
|           throw new Error("failed to get DNS response"); | ||||
|         } | ||||
|         return { | ||||
|           answer: resp.body.answer.map(function (ans) { | ||||
|             return { data: ans.data, ttl: ans.ttl }; | ||||
|           }) | ||||
|         }; | ||||
|       }); | ||||
|   if (!me.dns01) { | ||||
|     me.dns01 = function (auth) { | ||||
|       return ACME._dns01(me, auth); | ||||
|     }; | ||||
|   } | ||||
|   // backwards compat
 | ||||
|   if (!me.dig) { me.dig = me.dns01; } | ||||
|   if (!me.http01) { | ||||
|     me.http01 = function (auth) { | ||||
|       return ACME._http01(me, auth); | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
| @ -853,8 +850,21 @@ ACME.create = function create(me) { | ||||
|     if ('string' !== typeof me.directoryUrl) { | ||||
|       throw new Error("you must supply either the ACME directory url as a string or an object of the ACME urls"); | ||||
|     } | ||||
|     return ACME._directory(me).then(function (resp) { | ||||
|       return fin(resp.body); | ||||
|     var p = Promise.resolve(); | ||||
|     if (!me.skipChallengeTest) { | ||||
|       p = me.request({ url: me._baseUrl + "/api/_acme_api_/" }).then(function (resp) { | ||||
|         if (resp.body.success) { | ||||
|           me._canCheckHttp01 = true; | ||||
|           me._canCheckDns01 = true; | ||||
|         } | ||||
|       }).catch(function () { | ||||
|         // ignore
 | ||||
|       }); | ||||
|     } | ||||
|     return p.then(function () { | ||||
|       return ACME._directory(me).then(function (resp) { | ||||
|         return fin(resp.body); | ||||
|       }); | ||||
|     }); | ||||
|   }; | ||||
|   me.accounts = { | ||||
| @ -992,6 +1002,29 @@ ACME._prnd = function (n) { | ||||
| ACME._toHex = function (pair) { | ||||
|   return parseInt(pair, 10).toString(16); | ||||
| }; | ||||
| ACME._dns01 = function (me, auth) { | ||||
|   return new me.request({ url: me._baseUrl + "/api/dns/" + auth.dnsHost + "?type=TXT" }).then(function (resp) { | ||||
|     var err; | ||||
|     if (!resp.body || !Array.isArray(resp.body.answer)) { | ||||
|       err = new Error("failed to get DNS response"); | ||||
|       console.error(err); | ||||
|       throw err; | ||||
|     } | ||||
|     var result = { | ||||
|       answer: resp.body.answer.map(function (ans) { | ||||
|         return { data: ans.data, ttl: ans.ttl }; | ||||
|       }) | ||||
|     }; | ||||
|     console.log(result); | ||||
|     return result; | ||||
|   }); | ||||
| }; | ||||
| ACME._http01 = function (me, auth) { | ||||
|   var url = encodeURIComponent(auth.challengeUrl); | ||||
|   return new me.request({ url: me._baseUrl + "/api/http?url=" + url }).then(function (resp) { | ||||
|     return resp.body; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| Enc.bufToUrlBase64 = function (u8) { | ||||
|   return Enc.bufToBase64(u8) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user