| 
									
										
										
										
											2016-08-05 03:54:57 -04:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var fs = require('fs'); | 
					
						
							|  |  |  | var path = require('path'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 16:25:17 -06:00
										 |  |  | var myDefaults = { | 
					
						
							| 
									
										
										
										
											2016-08-11 00:59:03 -06:00
										 |  |  |   //webrootPath: [ '~', 'letsencrypt', 'var', 'lib' ].join(path.sep)
 | 
					
						
							| 
									
										
										
										
											2016-08-30 18:29:29 -06:00
										 |  |  |   webrootPath: path.join(require('os').tmpdir(), 'acme-challenge') | 
					
						
							| 
									
										
										
										
											2016-08-05 04:10:33 -04:00
										 |  |  | , debug: false | 
					
						
							| 
									
										
										
										
											2016-08-05 03:54:57 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-09 12:57:41 -04:00
										 |  |  | var Challenge = module.exports; | 
					
						
							| 
									
										
										
										
											2016-08-05 04:10:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-09 12:57:41 -04:00
										 |  |  | Challenge.create = function (options) { | 
					
						
							| 
									
										
										
										
											2016-08-05 04:10:33 -04:00
										 |  |  |   var results = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-09 12:57:41 -04:00
										 |  |  |   Object.keys(Challenge).forEach(function (key) { | 
					
						
							|  |  |  |     results[key] = Challenge[key]; | 
					
						
							| 
									
										
										
										
											2016-08-05 04:10:33 -04:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-08-09 12:57:41 -04:00
										 |  |  |   results.create = undefined; | 
					
						
							| 
									
										
										
										
											2016-08-05 04:10:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 16:25:17 -06:00
										 |  |  |   Object.keys(myDefaults).forEach(function (key) { | 
					
						
							| 
									
										
										
										
											2016-08-11 01:01:36 -06:00
										 |  |  |     if ('undefined' === typeof options[key]) { | 
					
						
							| 
									
										
										
										
											2016-10-12 16:25:17 -06:00
										 |  |  |       options[key] = myDefaults[key]; | 
					
						
							| 
									
										
										
										
											2016-08-05 04:10:33 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-08-09 12:57:41 -04:00
										 |  |  |   results._options = options; | 
					
						
							| 
									
										
										
										
											2016-08-05 04:10:33 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   results.getOptions = function () { | 
					
						
							|  |  |  |     return results._options; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return results; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-09 13:05:36 -04:00
										 |  |  | //
 | 
					
						
							|  |  |  | // NOTE: the "args" here in `set()` are NOT accessible to `get()` and `remove()`
 | 
					
						
							|  |  |  | // They are provided so that you can store them in an implementation-specific way
 | 
					
						
							|  |  |  | // if you need access to them.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | Challenge.set = function (args, domain, challengePath, keyAuthorization, done) { | 
					
						
							| 
									
										
										
										
											2016-08-05 03:54:57 -04:00
										 |  |  |   var mkdirp = require('mkdirp'); | 
					
						
							| 
									
										
										
										
											2016-08-31 11:44:51 +12:00
										 |  |  |   keyAuthorization = String(keyAuthorization); | 
					
						
							| 
									
										
										
										
											2016-08-05 03:54:57 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-09 13:05:36 -04:00
										 |  |  |   mkdirp(args.webrootPath, function (err) { | 
					
						
							| 
									
										
										
										
											2016-08-05 03:54:57 -04:00
										 |  |  |     if (err) { | 
					
						
							|  |  |  |       done(err); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-09 13:05:36 -04:00
										 |  |  |     fs.writeFile(path.join(args.webrootPath, challengePath), keyAuthorization, 'utf8', function (err) { | 
					
						
							| 
									
										
										
										
											2016-08-05 03:54:57 -04:00
										 |  |  |       done(err); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-09 13:05:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: the "defaults" here are still merged and templated, just like "args" would be,
 | 
					
						
							|  |  |  | // but if you specifically need "args" you must retrieve them from some storage mechanism
 | 
					
						
							|  |  |  | // based on domain and key
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-08-09 12:57:41 -04:00
										 |  |  | Challenge.get = function (defaults, domain, key, done) { | 
					
						
							|  |  |  |   fs.readFile(path.join(defaults.webrootPath, key), 'utf8', done); | 
					
						
							| 
									
										
										
										
											2016-08-05 03:54:57 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-09 12:57:41 -04:00
										 |  |  | Challenge.remove = function (defaults, domain, key, done) { | 
					
						
							|  |  |  |   fs.unlink(path.join(defaults.webrootPath, key), done); | 
					
						
							| 
									
										
										
										
											2016-08-05 03:54:57 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2016-10-12 16:25:17 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | Challenge.loopback = function (defaults, domain, key, done) { | 
					
						
							|  |  |  |   var hostname = domain + (defaults.test ? ':' + defaults.test : ''); | 
					
						
							|  |  |  |   var urlstr = 'http://' + hostname + '/.well-known/acme-challenge/' + key; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   require('http').get(urlstr, function (res) { | 
					
						
							|  |  |  |     if (200 !== res.statusCode) { | 
					
						
							|  |  |  |       done(new Error("local loopback failed with statusCode " + res.statusCode)); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     var chunks = []; | 
					
						
							|  |  |  |     res.on('data', function (chunk) { | 
					
						
							|  |  |  |       chunks.push(chunk); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     res.on('end', function () { | 
					
						
							|  |  |  |       var str = Buffer.concat(chunks).toString('utf8').trim(); | 
					
						
							|  |  |  |       done(null, str); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }).on('error', function (err) { | 
					
						
							|  |  |  |     done(err); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Challenge.test = function (args, domain, challenge, keyAuthorization, done) { | 
					
						
							|  |  |  |   var me = this; | 
					
						
							|  |  |  |   var key = keyAuthorization || challenge; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   me.set(args, domain, challenge, key, function (err) { | 
					
						
							|  |  |  |     if (err) { done(err); return; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // test is actually the port to be used
 | 
					
						
							|  |  |  |     myDefaults.test = args.test; | 
					
						
							|  |  |  |     myDefaults.webrootPath = args.webrootPath; | 
					
						
							|  |  |  |     me.loopback(args, domain, challenge, function (err, _key) { | 
					
						
							|  |  |  |       if (err) { done(err); return; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (key !== _key) { | 
					
						
							|  |  |  |         err = new Error("keyAuthorization [original] '" + key + "'" | 
					
						
							|  |  |  |           + " did not match [result] '" + _key + "'"); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       me.remove(myDefaults, domain, challenge, function (_err) { | 
					
						
							|  |  |  |         if (_err) { done(_err); return; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         done(err); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; |