| 
									
										
										
										
											2019-10-21 13:45:47 -06:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var native = module.exports; | 
					
						
							|  |  |  | var promisify = require('util').promisify; | 
					
						
							|  |  |  | var resolveTxt = promisify(require('dns').resolveTxt); | 
					
						
							| 
									
										
										
										
											2019-10-25 04:54:40 -06:00
										 |  |  | var crypto = require('crypto'); | 
					
						
							| 
									
										
										
										
											2019-10-21 13:45:47 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | native._canCheck = function(me) { | 
					
						
							| 
									
										
										
										
											2019-10-21 13:53:50 -06:00
										 |  |  | 	me._canCheck = {}; | 
					
						
							| 
									
										
										
										
											2019-10-21 13:45:47 -06:00
										 |  |  | 	me._canCheck['http-01'] = true; | 
					
						
							|  |  |  | 	me._canCheck['dns-01'] = true; | 
					
						
							|  |  |  | 	return Promise.resolve(); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | native._dns01 = function(me, ch) { | 
					
						
							|  |  |  | 	// TODO use digd.js
 | 
					
						
							|  |  |  | 	return resolveTxt(ch.dnsHost).then(function(records) { | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			answer: records.map(function(rr) { | 
					
						
							|  |  |  | 				return { | 
					
						
							|  |  |  | 					data: rr | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | native._http01 = function(me, ch) { | 
					
						
							|  |  |  | 	return new me.request({ | 
					
						
							|  |  |  | 		url: ch.challengeUrl | 
					
						
							|  |  |  | 	}).then(function(resp) { | 
					
						
							|  |  |  | 		return resp.body; | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2019-10-25 04:54:40 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | // the hashcash here is for browser parity only
 | 
					
						
							|  |  |  | // basically we ask the client to find a needle in a haystack
 | 
					
						
							|  |  |  | // (very similar to CloudFlare's api protection)
 | 
					
						
							|  |  |  | native._hashcash = function(ch) { | 
					
						
							|  |  |  | 	if (!ch || !ch.nonce) { | 
					
						
							|  |  |  | 		ch = { nonce: 'xxx' }; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return Promise.resolve() | 
					
						
							|  |  |  | 		.then(function() { | 
					
						
							|  |  |  | 			// only get easy answers
 | 
					
						
							|  |  |  | 			var len = ch.needle.length; | 
					
						
							|  |  |  | 			var start = ch.start || 0; | 
					
						
							|  |  |  | 			var end = ch.end || Math.ceil(len / 2); | 
					
						
							|  |  |  | 			var window = parseInt(end - start, 10) || 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var maxLen = 6; | 
					
						
							|  |  |  | 			var maxTries = Math.pow(2, maxLen * 8); | 
					
						
							|  |  |  | 			if ( | 
					
						
							|  |  |  | 				len > maxLen || | 
					
						
							|  |  |  | 				window < Math.ceil(len / 2) || | 
					
						
							|  |  |  | 				ch.needle.toLowerCase() !== ch.needle || | 
					
						
							|  |  |  | 				ch.alg !== 'SHA-256' | 
					
						
							|  |  |  | 			) { | 
					
						
							|  |  |  | 				// bail unless the server is issuing very easy challenges
 | 
					
						
							|  |  |  | 				throw new Error('possible and easy answers only, please'); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var haystack; | 
					
						
							|  |  |  | 			var i; | 
					
						
							|  |  |  | 			var answer; | 
					
						
							|  |  |  | 			var needle = Buffer.from(ch.needle, 'hex'); | 
					
						
							|  |  |  | 			for (i = 0; i < maxTries; i += 1) { | 
					
						
							|  |  |  | 				answer = i.toString(16); | 
					
						
							|  |  |  | 				if (answer.length % 2) { | 
					
						
							|  |  |  | 					answer = '0' + answer; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				haystack = crypto | 
					
						
							|  |  |  | 					.createHash('sha256') | 
					
						
							|  |  |  | 					.update(Buffer.from(ch.nonce + answer, 'hex')) | 
					
						
							|  |  |  | 					.digest() | 
					
						
							|  |  |  | 					.slice(ch.start, ch.end); | 
					
						
							|  |  |  | 				if (-1 !== haystack.indexOf(needle)) { | 
					
						
							|  |  |  | 					return ch.nonce + ':' + answer; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return ch.nonce + ':xxx'; | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		.catch(function() { | 
					
						
							|  |  |  | 			//console.log('[debug]', err);
 | 
					
						
							|  |  |  | 			// ignore any error
 | 
					
						
							|  |  |  | 			return ch.nonce + ':xxx'; | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | }; |