89 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			89 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| var native = module.exports;
 | |
| var promisify = require('util').promisify;
 | |
| var resolveTxt = promisify(require('dns').resolveTxt);
 | |
| var crypto = require('crypto');
 | |
| 
 | |
| native._canCheck = function(me) {
 | |
| 	me._canCheck = {};
 | |
| 	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;
 | |
| 	});
 | |
| };
 | |
| 
 | |
| // 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';
 | |
| 		});
 | |
| };
 |