/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Google Safe Browsing. * * The Initial Developer of the Original Code is Google Inc. * Portions created by the Initial Developer are Copyright (C) 2006 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Fritz Schneider (original author) * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ // A helper class that does "trustrank" lookups on a remote // server. Right now this lookup just indicates if a page is // phishing. The response format is protocol4 name/value pairs. // // Since we're sending full URLs to the server, we try to encrypt // them before transmission. Else HTTPS query params could leak. /** * A helper class that fetches trustrank values, parses them, and * passes them via an object to a callback. * * @constructor */ function PROT_TRFetcher(opt_noCrypto) { this.debugZone = "trfetcher"; this.useCrypto_ = !opt_noCrypto; this.protocol4Parser_ = new G_Protocol4Parser(); // We lazily instantiate the UrlCrypto object due to: // https://bugzilla.mozilla.org/show_bug.cgi?id=321024 // // Otherwise here we would use: // this.urlCrypto_ = new PROT_UrlCrypto(); } PROT_TRFetcher.TRY_REKEYING_RESPONSE = "pleaserekey"; /** * Get the URL of the request that will fetch us TR for the argument URL * * @param url String containing the URL we'd like to fetch info about * * @returns String containing the url we should use to fetch tr info */ PROT_TRFetcher.prototype.getRequestURL_ = function(url) { if (!this.urlCrypto_) this.urlCrypto_ = new PROT_UrlCrypto(); G_Debug(this, "Fetching for " + url); var requestURL = gDataProvider.getLookupURL(); if (!requestURL) return null; if (this.useCrypto_) { var maybeCryptedParams = this.urlCrypto_.maybeCryptParams({ "q": url}); for (var param in maybeCryptedParams) requestURL += param + "=" + encodeURIComponent(maybeCryptedParams[param]) + "&"; } else { requestURL += "q=" + encodeURIComponent(url); } G_Debug(this, "Request URL: " + requestURL); return requestURL; }; /** * Fetches information about a page. * * @param forPage URL for which to fetch info * * @param callback Function to call back when complete. */ PROT_TRFetcher.prototype.get = function(forPage, callback) { var url = this.getRequestURL_(forPage); if (!url) { G_Debug(this, "No remote lookup url."); return; } var closure = BindToObject(this.onFetchComplete_, this, callback); (new PROT_XMLFetcher()).get(url, closure); }; /** * Invoked when a fetch has completed. * * @param callback Function to invoke with parsed response object * @param responseText Text of the protocol4 message * @param httpStatus Number HTTP status code or NS_ERROR_NOT_AVAILABLE if the * request failed */ PROT_TRFetcher.prototype.onFetchComplete_ = function(callback, responseText, httpStatus) { var responseObj = this.extractResponse_(responseText); // The server might tell us to rekey, for example if it sees that // our request was unencrypted (meaning that we might not yet have // a key). If so, pass this hint along to the crypto key manager. if (responseObj[PROT_TRFetcher.TRY_REKEYING_RESPONSE] == "1" && this.urlCrypto_) { G_Debug(this, "We're supposed to re-key. Trying."); var manager = this.urlCrypto_.getManager(); if (manager) manager.maybeReKey(); } G_Debug(this, "TR Response:"); for (var field in responseObj) G_Debug(this, field + "=" + responseObj[field]); callback(responseObj, httpStatus); }; /** * Parse a protocol4 message (lookup server response) * * @param responseText String containing the server's response * * @returns Object containing the returned values or null if no * response was received */ PROT_TRFetcher.prototype.extractResponse_ = function(responseText) { return this.protocol4Parser_.parse(responseText); }; #ifdef DEBUG // Unittests function TEST_PROT_TRFetcher() { if (G_GDEBUG) { var z = "trfetcher UNITTEST"; G_debugService.enableZone(z); G_Debug(z, "Starting"); // Old test from before protocol4parser was broken out on its own. // But they do no harm, so we leave 'em. var fetcher = new PROT_TRFetcher(); var fakeResponse = "foo:3:foo\nbar:3:bar\nbaz:1:b"; var fields = fetcher.extractResponse_(fakeResponse); G_Assert(z, fields["foo"] == "foo", "Bad parse: foo"); G_Assert(z, fields["bar"] == "bar", "Bad parse: bar"); G_Assert(z, fields["baz"] == "b", "Bad parse: baz"); G_Assert(z, !fields["yourmom"], "Bad parse: yourmom"); // Test re-keying by stubbing the fetcher's urlCrypto_ object. var calledRekey = false; var fakeManager = { maybeReKey: function() { calledRekey = true; } }; fetcher.urlCrypto_ = {}; fetcher.urlCrypto_.getManager = function() { return fakeManager; }; var rekeyText = "foo:1:bar\n" + PROT_TRFetcher.TRY_REKEYING_RESPONSE + ":1:1"; fetcher.onFetchComplete_(function() {}, rekeyText); G_Assert(z, calledRekey, "rekey didn't trigger call to maybeReKey()"); G_Debug(z, "PASSED"); } } #endif