forked from root/acme.js
		
	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) {
 | 
					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
 | 
						// It's just fine if there's no account, we'll go get the key id we need via the existing key
 | 
				
			||||||
	options._kid =
 | 
						var kid =
 | 
				
			||||||
		options._kid ||
 | 
							options.kid ||
 | 
				
			||||||
		options.accountKid ||
 | 
							(options.account && (options.account.key && options.account.key.kid));
 | 
				
			||||||
		(options.account &&
 | 
					 | 
				
			||||||
			(options.account.kid ||
 | 
					 | 
				
			||||||
				(options.account.key && options.account.key.kid)));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (options._kid) {
 | 
						if (kid) {
 | 
				
			||||||
		return Promise.resolve(options._kid);
 | 
							return Promise.resolve(kid);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//return Promise.reject(new Error("must include KeyID"));
 | 
						//return Promise.reject(new Error("must include KeyID"));
 | 
				
			||||||
	// This is an idempotent request. It'll return the same account for the same public key.
 | 
						// This is an idempotent request. It'll return the same account for the same public key.
 | 
				
			||||||
	return A._registerAccount(me, options).then(function(account) {
 | 
						return A._registerAccount(me, options).then(function(account) {
 | 
				
			||||||
		options._kid = account.key.kid;
 | 
							return account.key.kid;
 | 
				
			||||||
		// start back from the top
 | 
					 | 
				
			||||||
		return options._kid;
 | 
					 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -54,50 +49,33 @@ A._registerAccount = function(me, options) {
 | 
				
			|||||||
	function agree(tosUrl) {
 | 
						function agree(tosUrl) {
 | 
				
			||||||
		var err;
 | 
							var err;
 | 
				
			||||||
		if (me._tos !== tosUrl) {
 | 
							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';
 | 
								err.code = 'E_AGREE_TOS';
 | 
				
			||||||
			throw err;
 | 
								throw err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return U._importKeypair(
 | 
						function getAccount() {
 | 
				
			||||||
			me,
 | 
							return U._importKeypair(options.accountKey).then(function(pair) {
 | 
				
			||||||
			options.accountKey || options.accountKeypair
 | 
					 | 
				
			||||||
		).then(function(pair) {
 | 
					 | 
				
			||||||
			var contact;
 | 
								var contact;
 | 
				
			||||||
			if (options.contact) {
 | 
								if (options.contact) {
 | 
				
			||||||
				contact = options.contact.slice(0);
 | 
									contact = options.contact.slice(0);
 | 
				
			||||||
			} else if (options.subscriberEmail || options.email) {
 | 
								} else if (options.subscriberEmail) {
 | 
				
			||||||
				contact = [
 | 
									contact = ['mailto:' + options.subscriberEmail];
 | 
				
			||||||
					'mailto:' + (options.subscriberEmail || options.email)
 | 
					 | 
				
			||||||
				];
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var accountRequest = {
 | 
								var accountRequest = {
 | 
				
			||||||
				termsOfServiceAgreed: tosUrl === me._tos,
 | 
									termsOfServiceAgreed: true,
 | 
				
			||||||
				onlyReturnExisting: false,
 | 
									onlyReturnExisting: false,
 | 
				
			||||||
				contact: contact
 | 
									contact: contact
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
			var pExt;
 | 
					
 | 
				
			||||||
			if (options.externalAccount) {
 | 
								var pub = pair.public;
 | 
				
			||||||
				pExt = Keypairs.signJws({
 | 
								return attachExtAcc(pub, accountRequest).then(function(accReq) {
 | 
				
			||||||
					// TODO is HMAC the standard, or is this arbitrary?
 | 
									var payload = JSON.stringify(accReq);
 | 
				
			||||||
					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);
 | 
					 | 
				
			||||||
				return U._jwsRequest(me, {
 | 
									return U._jwsRequest(me, {
 | 
				
			||||||
					options: options,
 | 
										accountKey: options.accountKey,
 | 
				
			||||||
					url: me._directoryUrls.newAccount,
 | 
										url: me._directoryUrls.newAccount,
 | 
				
			||||||
					protected: { kid: false, jwk: pair.public },
 | 
										protected: { kid: false, jwk: pair.public },
 | 
				
			||||||
					payload: Enc.strToBuf(payload)
 | 
										payload: Enc.strToBuf(payload)
 | 
				
			||||||
@ -118,34 +96,42 @@ A._registerAccount = function(me, options) {
 | 
				
			|||||||
						);
 | 
											);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					var location = resp.headers.location;
 | 
										// the account id url is the "kid"
 | 
				
			||||||
					// the account id url
 | 
										var kid = resp.headers.location;
 | 
				
			||||||
					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'
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            */
 | 
					 | 
				
			||||||
					if (!account) {
 | 
										if (!account) {
 | 
				
			||||||
						account = { _emptyResponse: true };
 | 
											account = { _emptyResponse: true };
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					// https://git.rootprojects.org/root/acme.js/issues/8
 | 
					 | 
				
			||||||
					if (!account.key) {
 | 
										if (!account.key) {
 | 
				
			||||||
						account.key = {};
 | 
											account.key = {};
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					account.key.kid = options._kid;
 | 
										account.key.kid = kid;
 | 
				
			||||||
					return account;
 | 
										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()
 | 
						return Promise.resolve()
 | 
				
			||||||
		.then(function() {
 | 
							.then(function() {
 | 
				
			||||||
			//#console.debug('[ACME.js] agreeToTerms');
 | 
								//#console.debug('[ACME.js] agreeToTerms');
 | 
				
			||||||
@ -157,5 +143,6 @@ A._registerAccount = function(me, options) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			return agreeToTerms(me._tos);
 | 
								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;
 | 
					var http = module.exports;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
http.request = function(opts) {
 | 
					http.request = function(opts) {
 | 
				
			||||||
 | 
						opts.cors = true;
 | 
				
			||||||
	return window.fetch(opts.url, opts).then(function(resp) {
 | 
						return window.fetch(opts.url, opts).then(function(resp) {
 | 
				
			||||||
		var headers = {};
 | 
							var headers = {};
 | 
				
			||||||
		var result = {
 | 
							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();
 | 
				
			||||||
							
								
								
									
										34
									
								
								utils.js
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								utils.js
									
									
									
									
									
								
							@ -3,6 +3,7 @@
 | 
				
			|||||||
var U = module.exports;
 | 
					var U = module.exports;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var Keypairs = require('@root/keypairs');
 | 
					var Keypairs = require('@root/keypairs');
 | 
				
			||||||
 | 
					var UserAgent = require('./lib/node/client-user-agent.js');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Handle nonce, signing, and request altogether
 | 
					// Handle nonce, signing, and request altogether
 | 
				
			||||||
U._jwsRequest = function(me, bigopts) {
 | 
					U._jwsRequest = function(me, bigopts) {
 | 
				
			||||||
@ -12,16 +13,14 @@ U._jwsRequest = function(me, bigopts) {
 | 
				
			|||||||
		// protected.alg: added by Keypairs.signJws
 | 
							// protected.alg: added by Keypairs.signJws
 | 
				
			||||||
		if (!bigopts.protected.jwk) {
 | 
							if (!bigopts.protected.jwk) {
 | 
				
			||||||
			// protected.kid must be overwritten due to ACME's interpretation of the spec
 | 
								// protected.kid must be overwritten due to ACME's interpretation of the spec
 | 
				
			||||||
			if (!bigopts.protected.kid) {
 | 
								if (!('kid' in bigopts.protected)) {
 | 
				
			||||||
				bigopts.protected.kid = bigopts.options._kid;
 | 
									bigopts.protected.kid = bigopts.kid;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// this will shasum the thumbprint the 2nd time
 | 
							// this will shasum the thumbprint the 2nd time
 | 
				
			||||||
		return Keypairs.signJws({
 | 
							return Keypairs.signJws({
 | 
				
			||||||
			jwk:
 | 
								jwk: bigopts.accountKey,
 | 
				
			||||||
				bigopts.options.accountKey ||
 | 
					 | 
				
			||||||
				bigopts.options.accountKeypair.privateKeyJwk,
 | 
					 | 
				
			||||||
			protected: bigopts.protected,
 | 
								protected: bigopts.protected,
 | 
				
			||||||
			payload: bigopts.payload
 | 
								payload: bigopts.payload
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
@ -72,16 +71,36 @@ U._getNonce = function(me) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Handle some ACME-specific defaults
 | 
					// Handle some ACME-specific defaults
 | 
				
			||||||
U._request = function(me, opts) {
 | 
					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) {
 | 
						if (!opts.headers) {
 | 
				
			||||||
		opts.headers = {};
 | 
							opts.headers = {};
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ua && !opts.headers['User-Agent']) {
 | 
				
			||||||
 | 
							opts.headers['User-Agent'] = ua;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (opts.json && true !== opts.json) {
 | 
						if (opts.json && true !== opts.json) {
 | 
				
			||||||
		opts.headers['Content-Type'] = 'application/jose+json';
 | 
							opts.headers['Content-Type'] = 'application/jose+json';
 | 
				
			||||||
		opts.body = JSON.stringify(opts.json);
 | 
							opts.body = JSON.stringify(opts.json);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (!opts.method) {
 | 
						if (!opts.method) {
 | 
				
			||||||
 | 
							opts.method = 'GET';
 | 
				
			||||||
 | 
							if (opts.body) {
 | 
				
			||||||
			opts.method = 'POST';
 | 
								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) {
 | 
						return me.request(opts).then(function(resp) {
 | 
				
			||||||
		if (resp.toJSON) {
 | 
							if (resp.toJSON) {
 | 
				
			||||||
			resp = resp.toJSON();
 | 
								resp = resp.toJSON();
 | 
				
			||||||
@ -89,6 +108,9 @@ U._request = function(me, opts) {
 | 
				
			|||||||
		if (resp.headers['replay-nonce']) {
 | 
							if (resp.headers['replay-nonce']) {
 | 
				
			||||||
			U._setNonce(me, 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 e;
 | 
				
			||||||
		var err;
 | 
							var err;
 | 
				
			||||||
@ -122,7 +144,7 @@ U._setNonce = function(me, nonce) {
 | 
				
			|||||||
	me._nonces.unshift({ nonce: nonce, createdAt: Date.now() });
 | 
						me._nonces.unshift({ nonce: nonce, createdAt: Date.now() });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
U._importKeypair = function(me, key) {
 | 
					U._importKeypair = function(key) {
 | 
				
			||||||
	var p;
 | 
						var p;
 | 
				
			||||||
	var pub;
 | 
						var pub;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user