| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | (function (exports) { | 
					
						
							|  |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var BACME = exports.BACME = {}; | 
					
						
							|  |  |  | var webFetch = exports.fetch; | 
					
						
							|  |  |  | var webCrypto = exports.crypto; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var directoryUrl = 'https://acme-staging-v02.api.letsencrypt.org/directory'; | 
					
						
							|  |  |  | var directory; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 08:15:41 +00:00
										 |  |  | var nonceUrl; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | var nonce; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var accountKeypair; | 
					
						
							|  |  |  | var accountJwk; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 08:15:41 +00:00
										 |  |  | var accountUrl; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | var signedAccount; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BACME.challengePrefixes = { | 
					
						
							|  |  |  |   'http-01': '/.well-known/acme-challenge' | 
					
						
							|  |  |  | , 'dns-01': '_acme-challenge' | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BACME._logHeaders = function (resp) { | 
					
						
							|  |  |  | 	console.log('Headers:'); | 
					
						
							|  |  |  | 	Array.from(resp.headers.entries()).forEach(function (h) { console.log(h[0] + ': ' + h[1]); }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BACME._logBody = function (body) { | 
					
						
							|  |  |  | 	console.log('Body:'); | 
					
						
							|  |  |  | 	console.log(JSON.stringify(body, null, 2)); | 
					
						
							|  |  |  | 	console.log(''); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 20:35:34 +00:00
										 |  |  | BACME.directory = function (opts) { | 
					
						
							|  |  |  | 	return webFetch(opts.directoryUrl || directoryUrl, { mode: 'cors' }).then(function (resp) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		BACME._logHeaders(resp); | 
					
						
							|  |  |  | 		return resp.json().then(function (body) { | 
					
						
							|  |  |  | 			directory = body; | 
					
						
							| 
									
										
										
										
											2018-05-01 08:15:41 +00:00
										 |  |  |       nonceUrl = directory.newNonce || 'https://acme-staging-v02.api.letsencrypt.org/acme/new-nonce'; | 
					
						
							|  |  |  |       accountUrl = directory.newAccount || 'https://acme-staging-v02.api.letsencrypt.org/acme/new-account'; | 
					
						
							|  |  |  |       orderUrl = directory.newOrder || "https://acme-staging-v02.api.letsencrypt.org/acme/new-order"; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  |       BACME._logBody(body); | 
					
						
							|  |  |  |       return body; | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BACME.nonce = function () { | 
					
						
							|  |  |  | 	return webFetch(nonceUrl, { mode: 'cors' }).then(function (resp) { | 
					
						
							|  |  |  |     BACME._logHeaders(resp); | 
					
						
							|  |  |  | 		nonce = resp.headers.get('replay-nonce'); | 
					
						
							|  |  |  | 		console.log('Nonce:', nonce); | 
					
						
							|  |  |  | 		// resp.body is empty
 | 
					
						
							|  |  |  | 		return resp.headers.get('replay-nonce'); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BACME.accounts = {}; | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // type = ECDSA
 | 
					
						
							|  |  |  | // bitlength = 256
 | 
					
						
							|  |  |  | BACME.accounts.generateKeypair = function (opts) { | 
					
						
							|  |  |  |   var wcOpts = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // ECDSA has only the P curves and an associated bitlength
 | 
					
						
							|  |  |  |   if (/^EC/i.test(opts.type)) { | 
					
						
							|  |  |  |     wcOpts.name = 'ECDSA'; | 
					
						
							|  |  |  |     if (/256/.test(opts.bitlength)) { | 
					
						
							|  |  |  |       wcOpts.namedCurve = 'P-256'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // RSA-PSS is another option, but I don't think it's used for Let's Encrypt
 | 
					
						
							|  |  |  |   // I think the hash is only necessary for signing, not generation or import
 | 
					
						
							|  |  |  |   if (/^RS/i.test(opts.type)) { | 
					
						
							|  |  |  |     wcOpts.name = 'RSASSA-PKCS1-v1_5'; | 
					
						
							|  |  |  |     wcOpts.modulusLength = opts.bitlength; | 
					
						
							|  |  |  |     if (opts.bitlength < 2048) { | 
					
						
							|  |  |  |       wcOpts.modulusLength = opts.bitlength * 8; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     wcOpts.publicExponent = new Uint8Array([0x01, 0x00, 0x01]); | 
					
						
							|  |  |  |     wcOpts.hash = { name: "SHA-256" }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 	// https://github.com/diafygi/webcrypto-examples#ecdsa---generatekey
 | 
					
						
							|  |  |  | 	var extractable = true; | 
					
						
							|  |  |  | 	return webCrypto.subtle.generateKey( | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 		wcOpts | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 	, extractable | 
					
						
							|  |  |  | 	, [ 'sign', 'verify' ] | 
					
						
							|  |  |  | 	).then(function (result) { | 
					
						
							|  |  |  | 		accountKeypair = result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return webCrypto.subtle.exportKey( | 
					
						
							|  |  |  | 			"jwk" | 
					
						
							|  |  |  | 		, result.privateKey | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 		).then(function (privJwk) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 			accountJwk = privJwk; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 			console.log('private jwk:'); | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 			console.log(JSON.stringify(privJwk, null, 2)); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  |       return privJwk; | 
					
						
							|  |  |  |       /* | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 			return webCrypto.subtle.exportKey( | 
					
						
							|  |  |  | 				"pkcs8" | 
					
						
							|  |  |  | 			, result.privateKey | 
					
						
							|  |  |  | 			).then(function (keydata) { | 
					
						
							|  |  |  | 				console.log('pkcs8:'); | 
					
						
							|  |  |  | 				console.log(Array.from(new Uint8Array(keydata))); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |         return privJwk; | 
					
						
							|  |  |  |         //return accountKeypair;
 | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  |       */ | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // json to url-safe base64
 | 
					
						
							|  |  |  | BACME._jsto64 = function (json) { | 
					
						
							|  |  |  | 	return btoa(JSON.stringify(json)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var textEncoder = new TextEncoder(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | BACME._importKey = function (jwk) { | 
					
						
							|  |  |  |   var alg; // I think the 256 refers to the hash
 | 
					
						
							|  |  |  |   var wcOpts = {}; | 
					
						
							| 
									
										
										
										
											2018-05-04 11:10:43 +00:00
										 |  |  |   var extractable = true; // TODO make optionally false?
 | 
					
						
							|  |  |  |   var priv = jwk; | 
					
						
							|  |  |  |   var pub; | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // ECDSA
 | 
					
						
							|  |  |  |   if (/^EC/i.test(jwk.kty)) { | 
					
						
							|  |  |  |     wcOpts.name = 'ECDSA'; | 
					
						
							|  |  |  |     wcOpts.namedCurve = jwk.crv; | 
					
						
							|  |  |  |     alg = 'ES256'; | 
					
						
							| 
									
										
										
										
											2018-05-04 11:10:43 +00:00
										 |  |  |     pub = { | 
					
						
							|  |  |  |       crv: priv.crv | 
					
						
							|  |  |  |     , kty: priv.kty | 
					
						
							|  |  |  |     , x: priv.x | 
					
						
							|  |  |  |     , y: priv.y | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     if (!priv.d) { | 
					
						
							|  |  |  |       priv = null; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // RSA
 | 
					
						
							|  |  |  |   if (/^RS/i.test(jwk.kty)) { | 
					
						
							|  |  |  |     wcOpts.name = 'RSASSA-PKCS1-v1_5'; | 
					
						
							|  |  |  |     wcOpts.hash = { name: "SHA-256" }; | 
					
						
							|  |  |  |     alg = 'RS256'; | 
					
						
							| 
									
										
										
										
											2018-05-04 11:10:43 +00:00
										 |  |  |     pub = { | 
					
						
							|  |  |  |       e: priv.e | 
					
						
							|  |  |  |     , kty: priv.kty | 
					
						
							|  |  |  |     , n: priv.n | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!priv.p) { | 
					
						
							|  |  |  |       priv = null; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return window.crypto.subtle.importKey( | 
					
						
							|  |  |  |     "jwk" | 
					
						
							| 
									
										
										
										
											2018-05-04 11:10:43 +00:00
										 |  |  |   , pub | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 	, wcOpts | 
					
						
							|  |  |  |   , extractable | 
					
						
							| 
									
										
										
										
											2018-05-04 11:10:43 +00:00
										 |  |  |   , [ "verify" ] | 
					
						
							|  |  |  |   ).then(function (publicKey) { | 
					
						
							|  |  |  |     function give(privateKey) { | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         wcPub: publicKey | 
					
						
							|  |  |  |       , wcKey: privateKey | 
					
						
							|  |  |  |       , wcKeypair: { publicKey: publicKey, privateKey: privateKey } | 
					
						
							|  |  |  |       , meta: { | 
					
						
							|  |  |  |           alg: alg | 
					
						
							|  |  |  |         , name: wcOpts.name | 
					
						
							|  |  |  |         , hash: wcOpts.hash | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       , jwk: jwk | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!priv) { | 
					
						
							|  |  |  |       return give(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return window.crypto.subtle.importKey( | 
					
						
							|  |  |  |       "jwk" | 
					
						
							|  |  |  |     , priv | 
					
						
							|  |  |  |     , wcOpts | 
					
						
							|  |  |  |     , extractable | 
					
						
							|  |  |  |     , [ "sign"/*, "verify"*/ ] | 
					
						
							|  |  |  |     ).then(give); | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | BACME._sign = function (opts) { | 
					
						
							| 
									
										
										
										
											2018-05-04 11:10:43 +00:00
										 |  |  |   var wcPrivKey = opts.abstractKey.wcKeypair.privateKey; | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |   var wcOpts = opts.abstractKey.meta; | 
					
						
							|  |  |  |   var alg = opts.abstractKey.meta.alg; // I think the 256 refers to the hash
 | 
					
						
							|  |  |  |   var signHash; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   console.log('kty', opts.abstractKey.jwk.kty); | 
					
						
							|  |  |  |   signHash = { name: "SHA-" + alg.replace(/[a-z]+/ig, '') }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var msg = textEncoder.encode(opts.protected64 + '.' + opts.payload64); | 
					
						
							|  |  |  |   console.log('msg:', msg); | 
					
						
							|  |  |  |   return window.crypto.subtle.sign( | 
					
						
							|  |  |  |     { name: wcOpts.name, hash: signHash } | 
					
						
							|  |  |  |   , wcPrivKey | 
					
						
							|  |  |  |   , msg | 
					
						
							|  |  |  |   ).then(function (signature) { | 
					
						
							|  |  |  |     //console.log('sig1:', signature);
 | 
					
						
							|  |  |  |     //console.log('sig2:', new Uint8Array(signature));
 | 
					
						
							|  |  |  |     //console.log('sig3:', Array.prototype.slice.call(new Uint8Array(signature)));
 | 
					
						
							|  |  |  |     // convert buffer to urlsafe base64
 | 
					
						
							|  |  |  |     var sig64 = btoa(Array.prototype.map.call(new Uint8Array(signature), function (ch) { | 
					
						
							|  |  |  |       return String.fromCharCode(ch); | 
					
						
							|  |  |  |     }).join('')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     console.log('[1] URL-safe Base64 Signature:'); | 
					
						
							|  |  |  |     console.log(sig64); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var signedMsg = { | 
					
						
							|  |  |  |       protected: opts.protected64 | 
					
						
							|  |  |  |     , payload: opts.payload64 | 
					
						
							|  |  |  |     , signature: sig64 | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |     console.log('Signed Base64 Msg:'); | 
					
						
							|  |  |  |     console.log(JSON.stringify(signedMsg, null, 2)); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |     return signedMsg; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | // email = john.doe@gmail.com
 | 
					
						
							|  |  |  | // jwk = { ... }
 | 
					
						
							|  |  |  | // agree = true
 | 
					
						
							|  |  |  | BACME.accounts.sign = function (opts) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return BACME._importKey(opts.jwk).then(function (abstractKey) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var payloadJson = | 
					
						
							|  |  |  |       { termsOfServiceAgreed: opts.agree | 
					
						
							|  |  |  |       , onlyReturnExisting: false | 
					
						
							|  |  |  |       , contact: opts.contacts || [ 'mailto:' + opts.email ] | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     console.log('payload:'); | 
					
						
							|  |  |  |     console.log(payloadJson); | 
					
						
							|  |  |  |     var payload64 = BACME._jsto64( | 
					
						
							|  |  |  |       payloadJson | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // TODO RSA
 | 
					
						
							|  |  |  |     var protectedJson = | 
					
						
							|  |  |  |       { nonce: opts.nonce | 
					
						
							|  |  |  |       , url: accountUrl | 
					
						
							|  |  |  |       , alg: abstractKey.meta.alg | 
					
						
							|  |  |  |       , jwk: { | 
					
						
							|  |  |  |           kty: opts.jwk.kty | 
					
						
							|  |  |  |         , crv: opts.jwk.crv | 
					
						
							|  |  |  |         , x: opts.jwk.x | 
					
						
							|  |  |  |         , y: opts.jwk.y | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     console.log('protected:'); | 
					
						
							|  |  |  |     console.log(protectedJson); | 
					
						
							|  |  |  |     var protected64 = BACME._jsto64( | 
					
						
							|  |  |  |       protectedJson | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Note: this function hashes before signing so send data, not the hash
 | 
					
						
							|  |  |  | 		return BACME._sign({ | 
					
						
							|  |  |  |       abstractKey: abstractKey | 
					
						
							|  |  |  |     , payload64: payload64 | 
					
						
							|  |  |  |     , protected64: protected64 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var account; | 
					
						
							|  |  |  | var accountId; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | BACME.accounts.set = function (opts) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 	nonce = null; | 
					
						
							|  |  |  | 	return window.fetch(accountUrl, { | 
					
						
							|  |  |  | 		mode: 'cors' | 
					
						
							|  |  |  | 	, method: 'POST' | 
					
						
							|  |  |  | 	, headers: { 'Content-Type': 'application/jose+json' } | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 	, body: JSON.stringify(opts.signedAccount) | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 	}).then(function (resp) { | 
					
						
							|  |  |  | 		BACME._logHeaders(resp); | 
					
						
							|  |  |  | 		nonce = resp.headers.get('replay-nonce'); | 
					
						
							|  |  |  | 		accountId = resp.headers.get('location'); | 
					
						
							|  |  |  | 		console.log('Next nonce:', nonce); | 
					
						
							|  |  |  | 		console.log('Location/kid:', accountId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!resp.headers.get('content-type')) { | 
					
						
							|  |  |  | 		 console.log('Body: <none>'); | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		 return { kid: accountId }; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return resp.json().then(function (result) { | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |       if (/^Error/i.test(result.detail)) { | 
					
						
							|  |  |  |         return Promise.reject(new Error(result.detail)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       result.kid = accountId; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  |       BACME._logBody(result); | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return result; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 08:15:41 +00:00
										 |  |  | var orderUrl; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | var signedOrder; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BACME.orders = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // identifiers = [ { type: 'dns', value: 'example.com' }, { type: 'dns', value: '*.example.com' } ]
 | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | // signedAccount
 | 
					
						
							|  |  |  | BACME.orders.sign = function (opts) { | 
					
						
							|  |  |  | 	var payload64 = BACME._jsto64({ identifiers: opts.identifiers }); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 	return BACME._importKey(opts.jwk).then(function (abstractKey) { | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  |     var protected64 = BACME._jsto64( | 
					
						
							|  |  |  |       { nonce: nonce, alg: abstractKey.meta.alg/*'ES256'*/, url: orderUrl, kid: opts.kid } | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |     console.log('abstractKey:'); | 
					
						
							|  |  |  |     console.log(abstractKey); | 
					
						
							|  |  |  |     return BACME._sign({ | 
					
						
							|  |  |  |       abstractKey: abstractKey | 
					
						
							|  |  |  |     , payload64: payload64 | 
					
						
							|  |  |  |     , protected64: protected64 | 
					
						
							|  |  |  |     }).then(function (sig) { | 
					
						
							|  |  |  |       if (!sig) { | 
					
						
							|  |  |  |         throw new Error('sig is undefined... nonsense!'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       console.log('newsig', sig); | 
					
						
							|  |  |  |       return sig; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var order; | 
					
						
							|  |  |  | var currentOrderUrl; | 
					
						
							|  |  |  | var authorizationUrls; | 
					
						
							|  |  |  | var finalizeUrl; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | BACME.orders.create = function (opts) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 	nonce = null; | 
					
						
							|  |  |  | 	return window.fetch(orderUrl, { | 
					
						
							|  |  |  | 		mode: 'cors' | 
					
						
							|  |  |  | 	, method: 'POST' | 
					
						
							|  |  |  | 	, headers: { 'Content-Type': 'application/jose+json' } | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 	, body: JSON.stringify(opts.signedOrder) | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 	}).then(function (resp) { | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |     BACME._logHeaders(resp); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		currentOrderUrl = resp.headers.get('location'); | 
					
						
							|  |  |  | 		nonce = resp.headers.get('replay-nonce'); | 
					
						
							|  |  |  | 		console.log('Next nonce:', nonce); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return resp.json().then(function (result) { | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |       if (/^Error/i.test(result.detail)) { | 
					
						
							|  |  |  |         return Promise.reject(new Error(result.detail)); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 			authorizationUrls = result.authorizations; | 
					
						
							|  |  |  | 			finalizeUrl = result.finalize; | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |       BACME._logBody(result); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  |       result.url = currentOrderUrl; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  |       return result; | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BACME.challenges = {}; | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | BACME.challenges.all = function () { | 
					
						
							|  |  |  |   var challenges = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function next() { | 
					
						
							|  |  |  |     if (!authorizationUrls.length) { | 
					
						
							|  |  |  |       return challenges; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return BACME.challenges.view().then(function (challenge) { | 
					
						
							|  |  |  |       challenges.push(challenge); | 
					
						
							|  |  |  |       return next(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return next(); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | BACME.challenges.view = function () { | 
					
						
							|  |  |  | 	var authzUrl = authorizationUrls.pop(); | 
					
						
							|  |  |  | 	var token; | 
					
						
							|  |  |  | 	var challengeDomain; | 
					
						
							|  |  |  | 	var challengeUrl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return window.fetch(authzUrl, { | 
					
						
							|  |  |  | 		mode: 'cors' | 
					
						
							|  |  |  | 	}).then(function (resp) { | 
					
						
							|  |  |  |     BACME._logHeaders(resp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return resp.json().then(function (result) { | 
					
						
							|  |  |  | 			// Note: select the challenge you wish to use
 | 
					
						
							|  |  |  | 			var challenge = result.challenges.slice(0).pop(); | 
					
						
							|  |  |  | 			token = challenge.token; | 
					
						
							|  |  |  | 			challengeUrl = challenge.url; | 
					
						
							|  |  |  | 			challengeDomain = result.identifier.value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       BACME._logBody(result); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  |       return { | 
					
						
							|  |  |  |         challenges: result.challenges | 
					
						
							|  |  |  |       , expires: result.expires | 
					
						
							|  |  |  |       , identifier: result.identifier | 
					
						
							|  |  |  |       , status: result.status | 
					
						
							|  |  |  |       , wildcard: result.wildcard | 
					
						
							|  |  |  |       //, token: challenge.token
 | 
					
						
							|  |  |  |       //, url: challenge.url
 | 
					
						
							|  |  |  |       //, domain: result.identifier.value,
 | 
					
						
							|  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var thumbprint; | 
					
						
							|  |  |  | var keyAuth; | 
					
						
							|  |  |  | var httpPath; | 
					
						
							|  |  |  | var dnsAuth; | 
					
						
							|  |  |  | var dnsRecord; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | BACME.thumbprint = function (opts) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 	// https://stackoverflow.com/questions/42588786/how-to-fingerprint-a-jwk
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |   var accountJwk = opts.jwk; | 
					
						
							|  |  |  |   var keys; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (/^EC/i.test(opts.jwk.kty)) { | 
					
						
							|  |  |  |     keys = [ 'crv', 'kty', 'x', 'y' ]; | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  |   } else if (/^RS/i.test(opts.jwk.kty)) { | 
					
						
							|  |  |  |     keys = [ 'e', 'kty', 'n' ]; | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var accountPublicStr = '{' + keys.map(function (key) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		return '"' + key + '":"' + accountJwk[key] + '"'; | 
					
						
							|  |  |  | 	}).join(',') + '}'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return window.crypto.subtle.digest( | 
					
						
							|  |  |  | 		{ name: "SHA-256" } // SHA-256 is spec'd, non-optional
 | 
					
						
							|  |  |  | 	, textEncoder.encode(accountPublicStr) | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  | 	).then(function (hash) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		thumbprint = btoa(Array.prototype.map.call(new Uint8Array(hash), function (ch) { | 
					
						
							|  |  |  | 			return String.fromCharCode(ch); | 
					
						
							|  |  |  | 		}).join('')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		console.log('Thumbprint:'); | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  | 		console.log(opts); | 
					
						
							|  |  |  | 		console.log(accountPublicStr); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		console.log(thumbprint); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return thumbprint; | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | // { token, thumbprint, challengeDomain }
 | 
					
						
							|  |  |  | BACME.challenges['http-01'] = function (opts) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 	// The contents of the key authorization file
 | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | 	keyAuth = opts.token + '.' + opts.thumbprint; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Where the key authorization file goes
 | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | 	httpPath = 'http://' + opts.challengeDomain + '/.well-known/acme-challenge/' + opts.token; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   console.log("echo '" + keyAuth + "' > '" + httpPath + "'"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     path: httpPath | 
					
						
							|  |  |  |   , value: keyAuth | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2018-05-01 08:15:41 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | // { keyAuth }
 | 
					
						
							|  |  |  | BACME.challenges['dns-01'] = function (opts) { | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  |   console.log('opts.keyAuth for DNS:'); | 
					
						
							|  |  |  |   console.log(opts.keyAuth); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 	return window.crypto.subtle.digest( | 
					
						
							|  |  |  | 		{ name: "SHA-256", } | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | 	, textEncoder.encode(opts.keyAuth) | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  | 	).then(function (hash) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		dnsAuth = btoa(Array.prototype.map.call(new Uint8Array(hash), function (ch) { | 
					
						
							|  |  |  | 			return String.fromCharCode(ch); | 
					
						
							|  |  |  | 		}).join('')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | 		dnsRecord = '_acme-challenge.' + opts.challengeDomain; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		console.log('DNS TXT Auth:'); | 
					
						
							|  |  |  | 		// The name of the record
 | 
					
						
							|  |  |  | 		console.log(dnsRecord); | 
					
						
							|  |  |  | 		// The TXT record value
 | 
					
						
							|  |  |  | 		console.log(dnsAuth); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       type: 'TXT' | 
					
						
							|  |  |  |     , host: dnsRecord | 
					
						
							| 
									
										
										
										
											2018-05-01 08:15:41 +00:00
										 |  |  |     , answer: dnsAuth | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  |     }; | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var challengePollUrl; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | // { jwk, challengeUrl, accountId (kid) }
 | 
					
						
							|  |  |  | BACME.challenges.accept = function (opts) { | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |   var payload64 = BACME._jsto64( | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		{} | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  |   return BACME._importKey(opts.jwk).then(function (abstractKey) { | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  |     var protected64 = BACME._jsto64( | 
					
						
							|  |  |  |       { nonce: nonce, alg: abstractKey.meta.alg/*'ES256'*/, url: opts.challengeUrl, kid: opts.accountId } | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 		return BACME._sign({ | 
					
						
							|  |  |  |       abstractKey: abstractKey | 
					
						
							|  |  |  |     , payload64: payload64 | 
					
						
							|  |  |  |     , protected64: protected64 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }).then(function (signedAccept) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  | 	  nonce = null; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		return window.fetch( | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | 			opts.challengeUrl | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		, { mode: 'cors' | 
					
						
							|  |  |  | 			, method: 'POST' | 
					
						
							|  |  |  | 			, headers: { 'Content-Type': 'application/jose+json' } | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | 			, body: JSON.stringify(signedAccept) | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		).then(function (resp) { | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  |       BACME._logHeaders(resp); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 			nonce = resp.headers.get('replay-nonce'); | 
					
						
							| 
									
										
										
										
											2018-05-04 11:10:43 +00:00
										 |  |  |       console.log("ACCEPT NONCE:", nonce); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			return resp.json().then(function (reply) { | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  |         challengePollUrl = reply.url; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				console.log('Challenge ACK:'); | 
					
						
							|  |  |  | 				console.log(JSON.stringify(reply)); | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  |         return reply; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | BACME.challenges.check = function (opts) { | 
					
						
							|  |  |  | 	return window.fetch(opts.challengePollUrl, { mode: 'cors' }).then(function (resp) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  |     BACME._logHeaders(resp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return resp.json().then(function (reply) { | 
					
						
							|  |  |  | 			challengePollUrl = reply.url; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       BACME._logBody(reply); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return reply; | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var domainKeypair; | 
					
						
							|  |  |  | var domainJwk; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BACME.domains = {}; | 
					
						
							|  |  |  | // TODO factor out from BACME.accounts.generateKeypair
 | 
					
						
							|  |  |  | BACME.domains.generateKeypair = function () { | 
					
						
							|  |  |  | 	var extractable = true; | 
					
						
							|  |  |  | 	return window.crypto.subtle.generateKey( | 
					
						
							|  |  |  | 		{ name: "ECDSA", namedCurve: "P-256" } | 
					
						
							|  |  |  | 	, extractable | 
					
						
							|  |  |  | 	, [ 'sign', 'verify' ] | 
					
						
							|  |  |  | 	).then(function (result) { | 
					
						
							|  |  |  | 		domainKeypair = result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return window.crypto.subtle.exportKey( | 
					
						
							|  |  |  | 			"jwk" | 
					
						
							|  |  |  | 		, result.privateKey | 
					
						
							|  |  |  | 		).then(function (jwk) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			domainJwk = jwk; | 
					
						
							|  |  |  | 			console.log('private jwk:'); | 
					
						
							|  |  |  | 			console.log(JSON.stringify(jwk, null, 2)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return domainKeypair; | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  | // { serverJwk, domains }
 | 
					
						
							|  |  |  | BACME.orders.generateCsr = function (opts) { | 
					
						
							|  |  |  |   return BACME._importKey(opts.serverJwk).then(function (abstractKey) { | 
					
						
							| 
									
										
										
										
											2018-05-04 11:10:43 +00:00
										 |  |  |     return Promise.resolve(CSR.generate({ keypair: abstractKey.wcKeypair, domains: opts.domains })); | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var certificateUrl; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | // { csr, jwk, finalizeUrl, accountId }
 | 
					
						
							|  |  |  | BACME.orders.finalize = function (opts) { | 
					
						
							| 
									
										
										
										
											2018-05-02 08:02:22 +00:00
										 |  |  | 	var payload64 = BACME._jsto64( | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | 		{ csr: opts.csr } | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 	); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  |   return BACME._importKey(opts.jwk).then(function (abstractKey) { | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  |     var protected64 = BACME._jsto64( | 
					
						
							|  |  |  |       { nonce: nonce, alg: abstractKey.meta.alg/*'ES256'*/, url: opts.finalizeUrl, kid: opts.accountId } | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 		return BACME._sign({ | 
					
						
							|  |  |  |       abstractKey: abstractKey | 
					
						
							|  |  |  |     , payload64: payload64 | 
					
						
							|  |  |  |     , protected64: protected64 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }).then(function (signedFinal) { | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  | 	  nonce = null; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		return window.fetch( | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  | 			opts.finalizeUrl | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 		, { mode: 'cors' | 
					
						
							|  |  |  | 			, method: 'POST' | 
					
						
							|  |  |  | 			, headers: { 'Content-Type': 'application/jose+json' } | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | 			, body: JSON.stringify(signedFinal) | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		).then(function (resp) { | 
					
						
							|  |  |  |       BACME._logHeaders(resp); | 
					
						
							|  |  |  | 			nonce = resp.headers.get('replay-nonce'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return resp.json().then(function (reply) { | 
					
						
							|  |  |  | 				certificateUrl = reply.certificate; | 
					
						
							|  |  |  |         BACME._logBody(reply); | 
					
						
							| 
									
										
										
										
											2018-05-04 08:40:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return reply; | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  | BACME.orders.receive = function (opts) { | 
					
						
							|  |  |  |   return window.fetch( | 
					
						
							|  |  |  |     opts.certificateUrl | 
					
						
							|  |  |  |   , { mode: 'cors' | 
					
						
							|  |  |  |     , method: 'GET' | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   ).then(function (resp) { | 
					
						
							|  |  |  |     BACME._logHeaders(resp); | 
					
						
							|  |  |  |     nonce = resp.headers.get('replay-nonce'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 11:10:43 +00:00
										 |  |  |     return resp.text().then(function (reply) { | 
					
						
							| 
									
										
										
										
											2018-05-04 10:16:31 +00:00
										 |  |  |       BACME._logBody(reply); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return reply; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BACME.orders.check = function (opts) { | 
					
						
							|  |  |  |   return window.fetch( | 
					
						
							|  |  |  |     opts.orderUrl | 
					
						
							|  |  |  |   , { mode: 'cors' | 
					
						
							|  |  |  |     , method: 'GET' | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   ).then(function (resp) { | 
					
						
							|  |  |  |     BACME._logHeaders(resp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return resp.json().then(function (reply) { | 
					
						
							|  |  |  |       BACME._logBody(reply); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return reply; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 07:21:32 +00:00
										 |  |  | }(window)); |