All pastes #177843 Raw Edit

Mine

public javascript v1 · immutable
#177843 ·published 2006-09-20 19:23 UTC
rendered paste body
/* * SENDER POLICY FRAMEWORK LIBRARY IN JAVASCRIPT * * Copyright 2005 Joshua Tauberer <tauberer@for.net> * * Feel free to use this file however you want, but * credit would be nice. */ // http://www.ozonehouse.com/mark/spf/draft-lentczner-spf-00.txtvar SPF_GUESS = 1;var spfRecordCache = Array(50);var spfRecordCacheIndex = 0;var spfConsoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);//SPF("68.167.112.147", "for.net", function(result) { alert(result.message); });//SPF("130.94.251.12", "craigslist.org", function(result) { alert(result.message); });//SPF("64.4.240.67", "paypal.com", function(result) { alert(result.message); });function SPF(ip, domain, callback) {	SPF_Debug("Begin SPF Test on " + ip + " for " + domain);	// none, neutral, pass, fail, softfail, temperror, permerror	SPF_GetRecord(		domain,		function(record) {			if (record == null) {				callback(new SPFResult("0", "Domain does not support SPF verification.", 0));				return;			}						// Do a reverse DNS if the SPF record might need it.			// It would be better to do a reverse DNS only when			// we get to that point in the processing, but then			// we're not in a position to do the lookup async.			if (record.usesPTR) {				reverseDNS(ip, function(data) { if (data == null) data = Array(0); SPF_DoCheck(record, ip, domain, data, callback, 0); });				return;			}						SPF_DoCheck(record, ip, domain, null, callback, 0);		});}function SPF_DoCheck(record, ip, domain, reversedns, callback, hops) {	if (hops == 5) { callback(new SPFResult("permerror", "The maximum number of SPF redirects was reached.", 0)); return; }		var result = SPF_DoCheck2(record, ip, domain, reversedns);	if (result != null) {		var message;		if (result == "+") message = "The sender was " + (!record.isguess ? "explicitly" : "implicitly") + " permitted by <" + domain + ">.";		else if (result == "-") message = "The sender was denied by <" + domain + ">.";		else if (result == "~") message = "The sender was not permitted by <" + domain + ">.";		else if (result == "?") message = "The sender could not be verified by <" + domain + ">.";		else if (result == "permerror") message = "The sender has a SPF configuration problem or uses an unsupported feature.";		else if (result == "temperror") message = "There was a temporary problem using SPF verification.";				callback(new SPFResult(result, message, record.isguess));		return;	}		if (record.isguess) {		callback(new SPFResult("0", "Domain <" + domain + "> does not support SPF verification.", 0));		return;	}		if (record["redirect"] != null) {		SPF(ip, SPF_ExpandDomainSpec(record["redirect"]), callback);		return;	}				// Processing fell through to the end.	callback(new SPFResult("?", "The sender could not be verified by <" + domain + ">.", false));}function SPF_DoCheck2(record, ip, domain, reversedns) {	var mech = record.firstMechanism;	var test;	while (mech != null) {		try {			test = mech.matchTest(ip, domain, reversedns, mech);		} catch (e) {			SPF_Debug(e);			return "permerror";		}		SPF_Debug(" Mechanism " + mech.prefix + mech.name + " => " + test);		if (test)			return mech.prefix;				mech = mech.nextMechanism;	}	return null;}function SPF_GetRecord(domain, callback) {	for (var i = 0; i < spfRecordCache.length; i++) {		if (spfRecordCache[i] == null) break;		if (spfRecordCache[i].domain == domain) {			SPF_Debug(" Cached Entry Found");			callback(spfRecordCache[i].record);			return;		}	}		queryDNS(domain, "TXT",		function(txtrecords) {			if (txtrecords != null) {				var i;				for (i = 0; i < txtrecords.length; i++) {					if (txtrecords[i] == "v=spf1" || SPF_StartsWith(txtrecords[i], "v=spf1 ")) {						txtrecords[i] = txtrecords[i].substr(6); // chop off v=spf1							ParseSPFRecord(txtrecords[i], domain, callback, false);						return;					}				}			}			if (SPF_GUESS) {				SPF_Debug(" Using Guess Mechanisms");				ParseSPFRecord("a/24 mx/24", domain, callback, true);			} else {				SPF_Debug(" No 'v=spf1' TXT Record Found");				callback(null);			}		} );	}function ParseSPFRecord(record, domain, callback, isguess) {	var recobj = new SPFRecord();	recobj.isguess = isguess;		// Process each term	while (record != "") {		for (var i = 0; i < record.length; i++) {			if (record.charAt(i) == " " || i == record.length-1) {				if (record.charAt(i) != " " && i == record.length-1)					i++;				ProcessTerm(record.substring(0, i), recobj, domain);				record = record.substr(i+1);				break;			} 		}	}		if (recobj.needsResolving == 0)		callback(recobj);		var doneFunc = function() { callback(recobj); };		// Start resolving the things that need extra resolving.	var mech = recobj.firstMechanism;	while (mech != null) {		if (mech.startResolving != null)			mech.startResolving(doneFunc);		mech = mech.nextMechanism;	}		spfRecordCache[spfRecordCacheIndex] = new Object();	spfRecordCache[spfRecordCacheIndex].domain = domain;	spfRecordCache[spfRecordCacheIndex].record = recobj;	spfRecordCacheIndex++}function ProcessTerm(term, recobj, domain) {	if (term == "" || term == " ") return;		var prefix = "+";	if (term.charAt(0) == "+" || term.charAt(0) == "-" || term.charAt(0) == "?" || term.charAt(0) == "~") {		prefix = term.charAt(0);		term = term.substr(1);	}		var eq = term.indexOf("=");	if (eq == -1) {		var mech = null;		var domcidr;		var domain2;				// Mechanism		if (term == "all") {			mech = new SPFMechanism(prefix, term,				function(ip, domain, reversedns, mech) { return true; } );				} else if (SPF_StartsWith(term, "include:")) {			var target = SPF_ExpandDomainSpec(term.substr(8));			mech = new SPFMechanism(prefix, term, 				function(ip, domain, reversedns, mech) {					var incresult = SPF_DoCheck2(mech.include, ip, domain, reversedns);					return (incresult == "+");				});			mech.startResolving = function(callbackWhenAllDone) {				SPF_GetRecord(					target,					function(record) {						mech.include = record;						if (record.usesPTR) recobj.usesPTR = true;						if (--recobj.needsResolving == 0) callbackWhenAllDone();					});			};			recobj.needsResolving++;				} else if (			(term == "a" || SPF_StartsWith(term, "a:") || SPF_StartsWith(term, "a/"))			|| (term == "mx" || SPF_StartsWith(term, "mx:") || SPF_StartsWith(term, "mx/")) ) {						domcidr = SPF_ParseDomainCidr(term, domain);			domcidr.addrType = domcidr.mechanism.toUpperCase();			mech = new SPFMechanism(prefix, term,				function(ip, domain, reversedns, mech) {					for (var i = 0; i < mech.addresses.length; i++) {						if (mech.addresses[i] == null) {							// ??						} else if (typeof(mech.addresses[i]) == "string") {							SPF_Debug(" Comparing " + ip + " and " + mech.addresses[i] + " with CIDR4=" + domcidr.cidr4);							if (SPF_TestIP(ip, mech.addresses[i], domcidr.cidr4))								return true;						} else {							for (var j = 0; j < mech.addresses[i].length; j++) {								SPF_Debug(" Comparing " + ip + " and " + mech.addresses[i][j] + " with CIDR4=" + domcidr.cidr4);								if (SPF_TestIP(ip, mech.addresses[i][j], domcidr.cidr4))									return true;							}						}					}					return false;				} );			mech.startResolving = function(callbackWhenAllDone) {				queryDNS(domcidr.domain, domcidr.addrType,					function(dnsrecords) {						if (dnsrecords == null) { dnsrecords = Array(0); }						mech.addresses = Array(0);						for (var i = 0; i < dnsrecords.length; i++) {							if (dnsrecords[i].address != null) {								for (var j = 0; j < dnsrecords[i].address.length; j++)									mech.addresses[mech.addresses.length] = dnsrecords[i].address[j];							} else if (dnsrecords[i].host != null) {								recobj.needsResolving++;								SPF_Debug(" Resolving Host for '" + term + "': " + dnsrecords[i].host);								domain2 = dnsrecords[i].host;								queryDNS(domain2, "A",									function(dnsrecords2) {										SPF_Debug(" Resolved Host for '" + term + "': " + domain2);										if (dnsrecords2 == null) { dnsrecords2 = Array(0); }										mech.addresses[i] = Array(dnsrecords2.length);										for (var j = 0; j < dnsrecords2.length; j++) {											SPF_Debug(" Resolved Address for '" + domain2 + "': " + dnsrecords2[j]);											mech.addresses[i][j] = dnsrecords2[j];										}										if (--recobj.needsResolving == 0) callbackWhenAllDone();									});							} else {								SPF_Debug(" Resolved Address for '" + term + "': " + dnsrecords[i]);								mech.addresses[mech.addresses.length] = dnsrecords[i];							}						}						if (--recobj.needsResolving == 0) callbackWhenAllDone();					});			};			recobj.needsResolving++;					} else if (SPF_StartsWith(term, "ip4:")) {			domcidr = SPF_ParseDomainCidr(term, null);			domcidr.address = domcidr.domain;						mech = new SPFMechanism(prefix, term,				function(ip, domain, reversedns, mech) {					SPF_Debug(" Comparing " + ip + " and " + domcidr.address + " with CIDR4=" + domcidr.cidr4);					return SPF_TestIP(ip, domcidr.address, domcidr.cidr4);				} );						/*} else if (SPF_StartsWith(term, "exists:")) {			domcidr = SPF_ParseDomainCidr(term, null);						mech = new SPFMechanism(prefix, term,				function(ip, domain, reversedns, mech) {					return mech.exists;				} );			mech.startResolving = function(callbackWhenAllDone) {				queryDNS(domain, "A",					function(dnsrecords) {						mech.exists = (dnsrecords != null);						if (--recobj.needsResolving == 0) callbackWhenAllDone();					});			};			recobj.needsResolving++;*/						} else if (term == "ptr" || SPF_StartsWith(term, "ptr:")) {			domcidr = SPF_ParseDomainCidr(term, domain);						mech = new SPFMechanism(prefix, term,				function(ip, domain, reversedns, mech) {					for (var j = 0; j < reversedns.length; j++) {						if (reversedns[j] == domcidr.domain || endsWith(reversedns[j], "." + domcidr.domain))							return true;					}					return false;				} );							recobj.usesPTR = true;					} else {			// When an unrecognized mechanism is hit, always return ?-status.			mech = new SPFMechanism(prefix, term,				function(ip, domain, mech) {					SPF_Debug("The SPF mechanism <" + term + "> is not supported.");					return true;				} );			mech.prefix = "?";		}				if (recobj.lastMechanism == null) {			recobj.firstMechanism = mech;			recobj.lastMechanism = mech;		} else {			recobj.lastMechanism.nextMechanism = mech;			recobj.lastMechanism = mech;		}	} else {		// Modifier: Store as a property of the record object.		recobj[term.substr(0, eq)] = term.substr(eq+1);	}}function SPF_DottedQuadToInt(ip) {	var q = ip.split(".");  // The "1*" forces the first term to be numeric	return (1*q[3]) + (q[2] << 8) + (q[1] << 16) + (q[0] << 24);}function SPF_IntToBin(x) {	var i;	var b = "";	for (i = 0; i <= 7; i++) {		if ((x & (1<<i)) != 0)			b = "1" + b;		else			b = "0" + b;	}	return b;}function SPF_DottedQuadToBinary(ip) {	var q = ip.split(".");	return SPF_IntToBin(q[0]) + SPF_IntToBin(q[1]) + SPF_IntToBin(q[2]) + SPF_IntToBin(q[3]);}function SPF_TestIP(ip1, ip2, cidr) {	return (SPF_DottedQuadToInt(ip1) >> (32-cidr)) == (SPF_DottedQuadToInt(ip2) >> (32-cidr));}function SPF_ParseDomainCidr(target, domain) {	var ret = new Object();	ret.domain = domain;	ret.cidr4 = 32;	ret.cidr6 = 32*4;		if (target.indexOf("/") != -1) {		var cidr = target.substr(target.indexOf("/")+1);		target = target.substr(0, target.indexOf("/"));				if (cidr.indexOf("/") == -1) {			ret.cidr4 = cidr;		} else if (cidr.indexOf("/") == 0) {			ret.cidr6 = cidr.substr(1);		} else {			ret.cidr4 = cidr.substr(0, cidr.indexOf("/"));			ret.cidr6 = cidr.substr(cidr.indexOf("/")+1);		}	}		if (target.indexOf(":") != -1) {		ret.domain = SPF_ExpandDomainSpec( target.substr(target.indexOf(":")+1) );		target = target.substr(0, target.indexOf(":"));	}		ret.mechanism = target;		return ret;}function SPF_ExpandDomainSpec(domainspec) {	return domainspec;}function SPFRecord(domain) {	this.domain = domain;	this.firstMechanism = null; // linked list of mechanisms	this.lastMechanism = null; // last mechanism in list	this.needsResolving = 0;}function SPFMechanism(prefix, name, matchTest) {	this.prefix = prefix;	this.name = name;	this.matchTest = matchTest;	this.nextMechanism = null;}function SPFResult(status, message, isguess) {	this.status = status;	this.message = message;	this.isguess = isguess;}function SPF_Debug(message) {	if (false) {		spfConsoleService.logStringMessage(message);	}}function SPF_StartsWith(a, b) {	if (b.length > a.length) return false;	return a.substring(0, b.length) == b;}