| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var A = module.exports; | 
					
						
							|  |  |  | var U = require('./utils.js'); | 
					
						
							|  |  |  | var E = require('./errors.js'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var pending = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | A._getOrCreate = function(gnlck, mconf, db, acme, args) { | 
					
						
							|  |  |  | 	var email = | 
					
						
							|  |  |  | 		args.subscriberEmail || | 
					
						
							|  |  |  | 		mconf.subscriberEmail || | 
					
						
							|  |  |  | 		gnlck._defaults.subscriberEmail; | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!email) { | 
					
						
							|  |  |  | 		throw E.NO_SUBSCRIBER('get account', args.subject); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// TODO send welcome message with benefit info
 | 
					
						
							|  |  |  | 	return U._validMx(email) | 
					
						
							|  |  |  | 		.catch(function() { | 
					
						
							|  |  |  | 			throw E.NO_SUBSCRIBER('get account', args.subcriberEmail); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		.then(function() { | 
					
						
							|  |  |  | 			if (pending[email]) { | 
					
						
							|  |  |  | 				return pending[email]; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 			pending[email] = A._rawGetOrCreate( | 
					
						
							|  |  |  | 				gnlck, | 
					
						
							|  |  |  | 				mconf, | 
					
						
							|  |  |  | 				db, | 
					
						
							|  |  |  | 				acme, | 
					
						
							|  |  |  | 				args, | 
					
						
							|  |  |  | 				email | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 				.catch(function(e) { | 
					
						
							|  |  |  | 					delete pending[email]; | 
					
						
							|  |  |  | 					throw e; | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				.then(function(result) { | 
					
						
							|  |  |  | 					delete pending[email]; | 
					
						
							|  |  |  | 					return result; | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return pending[email]; | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // What we really need out of this is the private key and the ACME "key" id
 | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | A._rawGetOrCreate = function(gnlck, mconf, db, acme, args, email) { | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 	var p; | 
					
						
							|  |  |  | 	if (db.check) { | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 		p = A._checkStore(gnlck, mconf, db, acme, args, email); | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		p = Promise.resolve(null); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p.then(function(fullAccount) { | 
					
						
							|  |  |  | 		if (!fullAccount) { | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 			return A._newAccount(gnlck, mconf, db, acme, args, email, null); | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (fullAccount.keypair && fullAccount.key && fullAccount.key.kid) { | 
					
						
							|  |  |  | 			return fullAccount; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 		return A._newAccount(gnlck, mconf, db, acme, args, email, fullAccount); | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | A._newAccount = function(gnlck, mconf, db, acme, args, email, fullAccount) { | 
					
						
							|  |  |  | 	var keyType = | 
					
						
							|  |  |  | 		args.accountKeyType || | 
					
						
							|  |  |  | 		mconf.accountKeyType || | 
					
						
							|  |  |  | 		gnlck._defaults.accountKeyType; | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 	var query = { | 
					
						
							|  |  |  | 		subject: args.subject, | 
					
						
							|  |  |  | 		email: email, | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 		subscriberEmail: email, | 
					
						
							|  |  |  | 		customerEmail: args.customerEmail, | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 		account: fullAccount || {} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return U._getOrCreateKeypair(db, args.subject, query, keyType).then( | 
					
						
							|  |  |  | 		function(kresult) { | 
					
						
							|  |  |  | 			var keypair = kresult.keypair; | 
					
						
							|  |  |  | 			var accReg = { | 
					
						
							|  |  |  | 				subscriberEmail: email, | 
					
						
							|  |  |  | 				agreeToTerms: | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 					args.agreeToTerms || | 
					
						
							|  |  |  | 					mconf.agreeToTerms || | 
					
						
							|  |  |  | 					gnlck._defaults.agreeToTerms, | 
					
						
							|  |  |  | 				accountKey: keypair.privateKeyJwk || keypair.private, | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 				debug: args.debug | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			return acme.accounts.create(accReg).then(function(receipt) { | 
					
						
							|  |  |  | 				var reg = { | 
					
						
							|  |  |  | 					keypair: keypair, | 
					
						
							|  |  |  | 					receipt: receipt, | 
					
						
							|  |  |  | 					// shudder... not actually a KeyID... but so it is called anyway...
 | 
					
						
							|  |  |  | 					kid: | 
					
						
							|  |  |  | 						receipt && | 
					
						
							|  |  |  | 						receipt.key && | 
					
						
							|  |  |  | 						(receipt.key.kid || receipt.kid), | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 					email: args.email, | 
					
						
							|  |  |  | 					subscriberEmail: email, | 
					
						
							|  |  |  | 					customerEmail: args.customerEmail | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 				}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var keyP; | 
					
						
							|  |  |  | 				if (kresult.exists) { | 
					
						
							|  |  |  | 					keyP = Promise.resolve(); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					query.keypair = keypair; | 
					
						
							|  |  |  | 					query.receipt = receipt; | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 					query.directoryUrl = gnlck._defaults.directoryUrl; | 
					
						
							|  |  |  | 					/* | 
					
						
							|  |  |  | 					query.server = gnlck._defaults.directoryUrl.replace( | 
					
						
							|  |  |  | 						/^https?:\/\//i, | 
					
						
							|  |  |  | 						'' | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  |           */ | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 					keyP = db.setKeypair(query, keypair); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return keyP | 
					
						
							|  |  |  | 					.then(function() { | 
					
						
							|  |  |  | 						if (!db.set) { | 
					
						
							|  |  |  | 							return Promise.resolve({ | 
					
						
							|  |  |  | 								keypair: keypair | 
					
						
							|  |  |  | 							}); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						return db.set( | 
					
						
							|  |  |  | 							{ | 
					
						
							|  |  |  | 								// id to be set by Store
 | 
					
						
							|  |  |  | 								email: email, | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 								subscriberEmail: email, | 
					
						
							|  |  |  | 								customerEmail: args.customerEmail, | 
					
						
							|  |  |  | 								agreeTos: true, | 
					
						
							|  |  |  | 								directoryUrl: gnlck._defaults.directoryUrl | 
					
						
							|  |  |  | 								/* | 
					
						
							|  |  |  | 								server: gnlck._defaults.directoryUrl.replace( | 
					
						
							|  |  |  | 									/^https?:\/\//i, | 
					
						
							|  |  |  | 									'' | 
					
						
							|  |  |  | 								) | 
					
						
							|  |  |  |                 */ | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 							}, | 
					
						
							|  |  |  | 							reg | 
					
						
							|  |  |  | 						); | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 					.then(function(fullAccount) { | 
					
						
							|  |  |  | 						if (fullAccount && 'object' !== typeof fullAccount) { | 
					
						
							|  |  |  | 							throw new Error( | 
					
						
							|  |  |  | 								"accounts.set should either return 'null' or an object with an 'id' string" | 
					
						
							|  |  |  | 							); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						if (!fullAccount) { | 
					
						
							|  |  |  | 							fullAccount = {}; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						fullAccount.keypair = keypair; | 
					
						
							|  |  |  | 						if (!fullAccount.key) { | 
					
						
							|  |  |  | 							fullAccount.key = {}; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						fullAccount.key.kid = reg.kid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						return fullAccount; | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | A._checkStore = function(gnlck, mconf, db, acme, args, email) { | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 	if ((args.domain || args.domains) && !args.subject) { | 
					
						
							|  |  |  | 		console.warn("use 'subject' instead of 'domain'"); | 
					
						
							|  |  |  | 		args.subject = args.domain; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var account = args.account; | 
					
						
							|  |  |  | 	if (!account) { | 
					
						
							|  |  |  | 		account = {}; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 	if (args.accountKey) { | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 		console.warn( | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 			'rather than passing accountKey, put it directly into your account key store' | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 		); | 
					
						
							|  |  |  | 		// TODO we probably don't need this
 | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 		return U._importKeypair(args.accountKey); | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!db.check) { | 
					
						
							|  |  |  | 		return Promise.resolve(null); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return db | 
					
						
							|  |  |  | 		.check({ | 
					
						
							|  |  |  | 			//keypair: undefined,
 | 
					
						
							|  |  |  | 			//receipt: undefined,
 | 
					
						
							|  |  |  | 			email: email, | 
					
						
							| 
									
										
										
										
											2019-10-27 04:38:05 -06:00
										 |  |  | 			subscriberEmail: email, | 
					
						
							|  |  |  | 			customerEmail: args.customerEmail || mconf.customerEmail, | 
					
						
							| 
									
										
										
										
											2019-10-20 02:51:19 -06:00
										 |  |  | 			account: account | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		.then(function(fullAccount) { | 
					
						
							|  |  |  | 			if (!fullAccount) { | 
					
						
							|  |  |  | 				return null; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return fullAccount; | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | }; |