mirror of
				https://github.com/therootcompany/acme.js.git
				synced 2024-11-16 17:29:00 +00:00 
			
		
		
		
	API and test cleanup
This commit is contained in:
		
							parent
							
								
									161e9183c6
								
							
						
					
					
						commit
						90c7154a24
					
				
							
								
								
									
										105
									
								
								account.js
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								account.js
									
									
									
									
									
								
							| @ -8,23 +8,18 @@ var Enc = require('@root/encoding/bytes'); | ||||
| 
 | ||||
| A._getAccountKid = function(me, options) { | ||||
| 	// It's just fine if there's no account, we'll go get the key id we need via the existing key
 | ||||
| 	options._kid = | ||||
| 		options._kid || | ||||
| 		options.accountKid || | ||||
| 		(options.account && | ||||
| 			(options.account.kid || | ||||
| 				(options.account.key && options.account.key.kid))); | ||||
| 	var kid = | ||||
| 		options.kid || | ||||
| 		(options.account && (options.account.key && options.account.key.kid)); | ||||
| 
 | ||||
| 	if (options._kid) { | ||||
| 		return Promise.resolve(options._kid); | ||||
| 	if (kid) { | ||||
| 		return Promise.resolve(kid); | ||||
| 	} | ||||
| 
 | ||||
| 	//return Promise.reject(new Error("must include KeyID"));
 | ||||
| 	// This is an idempotent request. It'll return the same account for the same public key.
 | ||||
| 	return A._registerAccount(me, options).then(function(account) { | ||||
| 		options._kid = account.key.kid; | ||||
| 		// start back from the top
 | ||||
| 		return options._kid; | ||||
| 		return account.key.kid; | ||||
| 	}); | ||||
| }; | ||||
| 
 | ||||
| @ -54,50 +49,33 @@ A._registerAccount = function(me, options) { | ||||
| 	function agree(tosUrl) { | ||||
| 		var err; | ||||
| 		if (me._tos !== tosUrl) { | ||||
| 			err = new Error("You must agree to the ToS at '" + me._tos + "'"); | ||||
| 			err = new Error("must agree to '" + tosUrl + "'"); | ||||
| 			err.code = 'E_AGREE_TOS'; | ||||
| 			throw err; | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 		return U._importKeypair( | ||||
| 			me, | ||||
| 			options.accountKey || options.accountKeypair | ||||
| 		).then(function(pair) { | ||||
| 	function getAccount() { | ||||
| 		return U._importKeypair(options.accountKey).then(function(pair) { | ||||
| 			var contact; | ||||
| 			if (options.contact) { | ||||
| 				contact = options.contact.slice(0); | ||||
| 			} else if (options.subscriberEmail || options.email) { | ||||
| 				contact = [ | ||||
| 					'mailto:' + (options.subscriberEmail || options.email) | ||||
| 				]; | ||||
| 			} else if (options.subscriberEmail) { | ||||
| 				contact = ['mailto:' + options.subscriberEmail]; | ||||
| 			} | ||||
| 
 | ||||
| 			var accountRequest = { | ||||
| 				termsOfServiceAgreed: tosUrl === me._tos, | ||||
| 				termsOfServiceAgreed: true, | ||||
| 				onlyReturnExisting: false, | ||||
| 				contact: contact | ||||
| 			}; | ||||
| 			var pExt; | ||||
| 			if (options.externalAccount) { | ||||
| 				pExt = Keypairs.signJws({ | ||||
| 					// TODO is HMAC the standard, or is this arbitrary?
 | ||||
| 					secret: options.externalAccount.secret, | ||||
| 					protected: { | ||||
| 						alg: options.externalAccount.alg || 'HS256', | ||||
| 						kid: options.externalAccount.id, | ||||
| 						url: me._directoryUrls.newAccount | ||||
| 					}, | ||||
| 					payload: Enc.strToBuf(JSON.stringify(pair.public)) | ||||
| 				}).then(function(jws) { | ||||
| 					accountRequest.externalAccountBinding = jws; | ||||
| 					return accountRequest; | ||||
| 				}); | ||||
| 			} else { | ||||
| 				pExt = Promise.resolve(accountRequest); | ||||
| 			} | ||||
| 			return pExt.then(function(accountRequest) { | ||||
| 				var payload = JSON.stringify(accountRequest); | ||||
| 
 | ||||
| 			var pub = pair.public; | ||||
| 			return attachExtAcc(pub, accountRequest).then(function(accReq) { | ||||
| 				var payload = JSON.stringify(accReq); | ||||
| 				return U._jwsRequest(me, { | ||||
| 					options: options, | ||||
| 					accountKey: options.accountKey, | ||||
| 					url: me._directoryUrls.newAccount, | ||||
| 					protected: { kid: false, jwk: pair.public }, | ||||
| 					payload: Enc.strToBuf(payload) | ||||
| @ -118,34 +96,42 @@ A._registerAccount = function(me, options) { | ||||
| 						); | ||||
| 					} | ||||
| 
 | ||||
| 					var location = resp.headers.location; | ||||
| 					// the account id url
 | ||||
| 					options._kid = location; | ||||
| 					//#console.debug('[DEBUG] new account location:');
 | ||||
| 					//#console.debug(location);
 | ||||
| 					//#console.debug(resp);
 | ||||
| 
 | ||||
| 					/* | ||||
|             { | ||||
|               contact: ["mailto:jon@example.com"], | ||||
|               orders: "https://some-url", | ||||
|               status: 'valid' | ||||
|             } | ||||
|             */ | ||||
| 					// the account id url is the "kid"
 | ||||
| 					var kid = resp.headers.location; | ||||
| 					if (!account) { | ||||
| 						account = { _emptyResponse: true }; | ||||
| 					} | ||||
| 					// https://git.rootprojects.org/root/acme.js/issues/8
 | ||||
| 					if (!account.key) { | ||||
| 						account.key = {}; | ||||
| 					} | ||||
| 					account.key.kid = options._kid; | ||||
| 					account.key.kid = kid; | ||||
| 					return account; | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	// for external accounts (probably useless, but spec'd)
 | ||||
| 	function attachExtAcc(pubkey, accountRequest) { | ||||
| 		if (!options.externalAccount) { | ||||
| 			return Promise.resolve(accountRequest); | ||||
| 		} | ||||
| 
 | ||||
| 		return Keypairs.signJws({ | ||||
| 			// TODO is HMAC the standard, or is this arbitrary?
 | ||||
| 			secret: options.externalAccount.secret, | ||||
| 			protected: { | ||||
| 				alg: options.externalAccount.alg || 'HS256', | ||||
| 				kid: options.externalAccount.id, | ||||
| 				url: me._directoryUrls.newAccount | ||||
| 			}, | ||||
| 			payload: Enc.strToBuf(JSON.stringify(pubkey)) | ||||
| 		}).then(function(jws) { | ||||
| 			accountRequest.externalAccountBinding = jws; | ||||
| 			return accountRequest; | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	return Promise.resolve() | ||||
| 		.then(function() { | ||||
| 			//#console.debug('[ACME.js] agreeToTerms');
 | ||||
| @ -157,5 +143,6 @@ A._registerAccount = function(me, options) { | ||||
| 			} | ||||
| 			return agreeToTerms(me._tos); | ||||
| 		}) | ||||
| 		.then(agree); | ||||
| 		.then(agree) | ||||
| 		.then(getAccount); | ||||
| }; | ||||
|  | ||||
							
								
								
									
										81
									
								
								errors.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								errors.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| var E = module.exports; | ||||
| 
 | ||||
| E.NO_SUITABLE_CHALLENGE = function(domain, challenges, presenters) { | ||||
| 	// Bail with a descriptive message if no usable challenge could be selected
 | ||||
| 	// For example, wildcards require dns-01 and, if we don't have that, we have to bail
 | ||||
| 	var enabled = presenters.join(', ') || 'none'; | ||||
| 	var suitable = | ||||
| 		challenges | ||||
| 			.map(function(r) { | ||||
| 				return r.type; | ||||
| 			}) | ||||
| 			.join(', ') || 'none'; | ||||
| 	return new Error( | ||||
| 		"None of the challenge types that you've enabled ( " + | ||||
| 			enabled + | ||||
| 			' )' + | ||||
| 			" are suitable for validating the domain you've selected (" + | ||||
| 			domain + | ||||
| 			').' + | ||||
| 			' You must enable one of ( ' + | ||||
| 			suitable + | ||||
| 			' ).' | ||||
| 	); | ||||
| }; | ||||
| E.UNHANDLED_ORDER_STATUS = function(options, domains, resp) { | ||||
| 	return new Error( | ||||
| 		"Didn't finalize order: Unhandled status '" + | ||||
| 			resp.body.status + | ||||
| 			"'." + | ||||
| 			' This is not one of the known statuses...\n' + | ||||
| 			"Requested: '" + | ||||
| 			options.domains.join(', ') + | ||||
| 			"'\n" + | ||||
| 			"Validated: '" + | ||||
| 			domains.join(', ') + | ||||
| 			"'\n" + | ||||
| 			JSON.stringify(resp.body, null, 2) + | ||||
| 			'\n\n' + | ||||
| 			'Please open an issue at https://git.rootprojects.org/root/acme.js' | ||||
| 	); | ||||
| }; | ||||
| E.DOUBLE_READY_ORDER = function(options, domains, resp) { | ||||
| 	return new Error( | ||||
| 		"Did not finalize order: status 'ready'." + | ||||
| 			" Hmmm... this state shouldn't be possible here. That was the last state." + | ||||
| 			" This one should at least be 'processing'.\n" + | ||||
| 			"Requested: '" + | ||||
| 			options.domains.join(', ') + | ||||
| 			"'\n" + | ||||
| 			"Validated: '" + | ||||
| 			domains.join(', ') + | ||||
| 			"'\n" + | ||||
| 			JSON.stringify(resp.body, null, 2) + | ||||
| 			'\n\n' + | ||||
| 			'Please open an issue at https://git.rootprojects.org/root/acme.js' | ||||
| 	); | ||||
| }; | ||||
| E.ORDER_INVALID = function(options, domains, resp) { | ||||
| 	return new Error( | ||||
| 		"Did not finalize order: status 'invalid'." + | ||||
| 			' Best guess: One or more of the domain challenges could not be verified' + | ||||
| 			' (or the order was canceled).\n' + | ||||
| 			"Requested: '" + | ||||
| 			options.domains.join(', ') + | ||||
| 			"'\n" + | ||||
| 			"Validated: '" + | ||||
| 			domains.join(', ') + | ||||
| 			"'\n" + | ||||
| 			JSON.stringify(resp.body, null, 2) | ||||
| 	); | ||||
| }; | ||||
| E.NO_AUTHORIZATIONS = function(options, resp) { | ||||
| 	return new Error( | ||||
| 		"[acme-v2.js] authorizations were not fetched for '" + | ||||
| 			options.domains.join() + | ||||
| 			"':\n" + | ||||
| 			JSON.stringify(resp.body) | ||||
| 	); | ||||
| }; | ||||
| @ -3,6 +3,7 @@ | ||||
| var http = module.exports; | ||||
| 
 | ||||
| http.request = function(opts) { | ||||
| 	opts.cors = true; | ||||
| 	return window.fetch(opts.url, opts).then(function(resp) { | ||||
| 		var headers = {}; | ||||
| 		var result = { | ||||
|  | ||||
							
								
								
									
										10
									
								
								tests/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								tests/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| async function main() { | ||||
| 	await require('./generate-cert-key.js')(); | ||||
| 	await require('./format-pem-chains.js')(); | ||||
| 	await require('./compute-authorization-response.js')(); | ||||
| 	await require('./issue-certificates.js')(); | ||||
| } | ||||
| 
 | ||||
| main(); | ||||
							
								
								
									
										36
									
								
								utils.js
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								utils.js
									
									
									
									
									
								
							| @ -3,6 +3,7 @@ | ||||
| var U = module.exports; | ||||
| 
 | ||||
| var Keypairs = require('@root/keypairs'); | ||||
| var UserAgent = require('./lib/node/client-user-agent.js'); | ||||
| 
 | ||||
| // Handle nonce, signing, and request altogether
 | ||||
| U._jwsRequest = function(me, bigopts) { | ||||
| @ -12,16 +13,14 @@ U._jwsRequest = function(me, bigopts) { | ||||
| 		// protected.alg: added by Keypairs.signJws
 | ||||
| 		if (!bigopts.protected.jwk) { | ||||
| 			// protected.kid must be overwritten due to ACME's interpretation of the spec
 | ||||
| 			if (!bigopts.protected.kid) { | ||||
| 				bigopts.protected.kid = bigopts.options._kid; | ||||
| 			if (!('kid' in bigopts.protected)) { | ||||
| 				bigopts.protected.kid = bigopts.kid; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// this will shasum the thumbprint the 2nd time
 | ||||
| 		return Keypairs.signJws({ | ||||
| 			jwk: | ||||
| 				bigopts.options.accountKey || | ||||
| 				bigopts.options.accountKeypair.privateKeyJwk, | ||||
| 			jwk: bigopts.accountKey, | ||||
| 			protected: bigopts.protected, | ||||
| 			payload: bigopts.payload | ||||
| 		}) | ||||
| @ -72,16 +71,36 @@ U._getNonce = function(me) { | ||||
| 
 | ||||
| // Handle some ACME-specific defaults
 | ||||
| U._request = function(me, opts) { | ||||
| 	// no-op on browser
 | ||||
| 	var ua = UserAgent.get(me, opts); | ||||
| 
 | ||||
| 	// Note: the required User-Agent string will be set in node, but not browsers
 | ||||
| 	if (!opts.headers) { | ||||
| 		opts.headers = {}; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ua && !opts.headers['User-Agent']) { | ||||
| 		opts.headers['User-Agent'] = ua; | ||||
| 	} | ||||
| 	if (opts.json && true !== opts.json) { | ||||
| 		opts.headers['Content-Type'] = 'application/jose+json'; | ||||
| 		opts.body = JSON.stringify(opts.json); | ||||
| 		if (!opts.method) { | ||||
| 	} | ||||
| 	if (!opts.method) { | ||||
| 		opts.method = 'GET'; | ||||
| 		if (opts.body) { | ||||
| 			opts.method = 'POST'; | ||||
| 		} | ||||
| 	} | ||||
| 	if (opts.json) { | ||||
| 		opts.headers.Accept = 'application/json'; | ||||
| 		if (true !== opts.json) { | ||||
| 			opts.body = JSON.stringify(opts.json); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	//console.log('\n[debug] REQUEST');
 | ||||
| 	//console.log(opts);
 | ||||
| 	return me.request(opts).then(function(resp) { | ||||
| 		if (resp.toJSON) { | ||||
| 			resp = resp.toJSON(); | ||||
| @ -89,6 +108,9 @@ U._request = function(me, opts) { | ||||
| 		if (resp.headers['replay-nonce']) { | ||||
| 			U._setNonce(me, resp.headers['replay-nonce']); | ||||
| 		} | ||||
| 		//console.log('[debug] RESPONSE:');
 | ||||
| 		//console.log(resp.headers);
 | ||||
| 		//console.log(resp.body);
 | ||||
| 
 | ||||
| 		var e; | ||||
| 		var err; | ||||
| @ -122,7 +144,7 @@ U._setNonce = function(me, nonce) { | ||||
| 	me._nonces.unshift({ nonce: nonce, createdAt: Date.now() }); | ||||
| }; | ||||
| 
 | ||||
| U._importKeypair = function(me, key) { | ||||
| U._importKeypair = function(key) { | ||||
| 	var p; | ||||
| 	var pub; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user