forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			292 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			292 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const { XPCOMUtils } = ChromeUtils.importESModule(
 | |
|   "resource://gre/modules/XPCOMUtils.sys.mjs"
 | |
| );
 | |
| 
 | |
| // These tables have a different update URL (for v4).
 | |
| const TEST_TABLE_DATA_V4 = {
 | |
|   tableName: "test-phish-proto",
 | |
|   providerName: "google4",
 | |
|   updateUrl: "http://localhost:5555/safebrowsing/update?",
 | |
|   gethashUrl: "http://localhost:5555/safebrowsing/gethash-v4?",
 | |
| };
 | |
| 
 | |
| const PREF_NEXTUPDATETIME_V4 =
 | |
|   "browser.safebrowsing.provider.google4.nextupdatetime";
 | |
| const GETHASH_PATH = "/safebrowsing/gethash-v4";
 | |
| 
 | |
| // The protobuf binary represention of gethash response:
 | |
| // minimumWaitDuration : 12 secs 10 nanosecs
 | |
| // negativeCacheDuration : 120 secs 9 nanosecs
 | |
| //
 | |
| // { CompleteHash, ThreatType, CacheDuration { secs, nanos } };
 | |
| // { nsCString("01234567890123456789012345678901"), SOCIAL_ENGINEERING_PUBLIC, { 8, 500 } },
 | |
| // { nsCString("12345678901234567890123456789012"), SOCIAL_ENGINEERING_PUBLIC, { 7, 100} },
 | |
| // { nsCString("23456789012345678901234567890123"), SOCIAL_ENGINEERING_PUBLIC, { 1, 20 } },
 | |
| 
 | |
| const GETHASH_RESPONSE_CONTENT =
 | |
|   "\x0A\x2D\x08\x02\x1A\x22\x0A\x20\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x2A\x05\x08\x08\x10\xF4\x03\x0A\x2C\x08\x02\x1A\x22\x0A\x20\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x2A\x04\x08\x07\x10\x64\x0A\x2C\x08\x02\x1A\x22\x0A\x20\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x2A\x04\x08\x01\x10\x14\x12\x04\x08\x0C\x10\x0A\x1A\x04\x08\x78\x10\x09";
 | |
| 
 | |
| // The protobuf binary represention of update response:
 | |
| //
 | |
| // [
 | |
| //   {
 | |
| //     'threat_type': 2, // SOCIAL_ENGINEERING_PUBLIC
 | |
| //     'response_type': 2, // FULL_UPDATE
 | |
| //     'new_client_state': 'sta\x00te', // NEW_CLIENT_STATE
 | |
| //     'checksum': { "sha256": CHECKSUM }, // CHECKSUM
 | |
| //     'additions': { 'compression_type': RAW,
 | |
| //                    'prefix_size': 4,
 | |
| //                    'raw_hashes': "00000001000000020000000300000004"}
 | |
| //   }
 | |
| // ]
 | |
| //
 | |
| const UPDATE_RESPONSE_CONTENT =
 | |
|   "\x0A\x4A\x08\x02\x20\x02\x2A\x18\x08\x01\x12\x14\x08\x04\x12\x10\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x3A\x06\x73\x74\x61\x00\x74\x65\x42\x22\x0A\x20\x30\x67\xC7\x2C\x5E\x50\x1C\x31\xE3\xFE\xCA\x73\xF0\x47\xDC\x34\x1A\x95\x63\x99\xEC\x70\x5E\x0A\xEE\x9E\xFB\x17\xA1\x55\x35\x78\x12\x08\x08\x08\x10\x80\x94\xEB\xDC\x03";
 | |
| const UPDATE_PATH = "/safebrowsing/update";
 | |
| 
 | |
| let gListManager = Cc["@mozilla.org/url-classifier/listmanager;1"].getService(
 | |
|   Ci.nsIUrlListManager
 | |
| );
 | |
| 
 | |
| let gCompleter = Cc["@mozilla.org/url-classifier/hashcompleter;1"].getService(
 | |
|   Ci.nsIUrlClassifierHashCompleter
 | |
| );
 | |
| 
 | |
| XPCOMUtils.defineLazyServiceGetter(
 | |
|   this,
 | |
|   "gUrlUtil",
 | |
|   "@mozilla.org/url-classifier/utils;1",
 | |
|   "nsIUrlClassifierUtils"
 | |
| );
 | |
| 
 | |
| // Handles request for TEST_TABLE_DATA_V4.
 | |
| let gHttpServV4 = null;
 | |
| 
 | |
| const NEW_CLIENT_STATE = "sta\0te";
 | |
| const CHECKSUM =
 | |
|   "\x30\x67\xc7\x2c\x5e\x50\x1c\x31\xe3\xfe\xca\x73\xf0\x47\xdc\x34\x1a\x95\x63\x99\xec\x70\x5e\x0a\xee\x9e\xfb\x17\xa1\x55\x35\x78";
 | |
| 
 | |
| Services.prefs.setBoolPref("browser.safebrowsing.debug", true);
 | |
| 
 | |
| // The "\xFF\xFF" is to generate a base64 string with "/".
 | |
| Services.prefs.setCharPref("browser.safebrowsing.id", "Firefox\xFF\xFF");
 | |
| 
 | |
| // Register tables.
 | |
| gListManager.registerTable(
 | |
|   TEST_TABLE_DATA_V4.tableName,
 | |
|   TEST_TABLE_DATA_V4.providerName,
 | |
|   TEST_TABLE_DATA_V4.updateUrl,
 | |
|   TEST_TABLE_DATA_V4.gethashUrl
 | |
| );
 | |
| 
 | |
| // This is unfortunately needed since v4 gethash request
 | |
| // requires the threat type (table name) as well as the
 | |
| // state it's associated with. We have to run the update once
 | |
| // to have the state written.
 | |
| add_test(function test_update_v4() {
 | |
|   gListManager.disableUpdate(TEST_TABLE_DATA_V4.tableName);
 | |
|   gListManager.enableUpdate(TEST_TABLE_DATA_V4.tableName);
 | |
| 
 | |
|   // Force table update.
 | |
|   Services.prefs.setCharPref(PREF_NEXTUPDATETIME_V4, "1");
 | |
|   gListManager.maybeToggleUpdateChecking();
 | |
| });
 | |
| 
 | |
| add_test(function test_getHashRequestV4() {
 | |
|   let request = gUrlUtil.makeFindFullHashRequestV4(
 | |
|     [TEST_TABLE_DATA_V4.tableName],
 | |
|     [btoa(NEW_CLIENT_STATE)],
 | |
|     [btoa("0123"), btoa("1234567"), btoa("1111")].sort()
 | |
|   );
 | |
|   registerHandlerGethashV4("&$req=" + request);
 | |
|   let completeFinishedCnt = 0;
 | |
| 
 | |
|   gCompleter.complete(
 | |
|     "0123",
 | |
|     TEST_TABLE_DATA_V4.gethashUrl,
 | |
|     TEST_TABLE_DATA_V4.tableName,
 | |
|     {
 | |
|       completionV4(hash, table, duration, fullhashes) {
 | |
|         equal(hash, "0123");
 | |
|         equal(table, TEST_TABLE_DATA_V4.tableName);
 | |
|         equal(duration, 120);
 | |
|         equal(fullhashes.length, 1);
 | |
| 
 | |
|         let match = fullhashes
 | |
|           .QueryInterface(Ci.nsIArray)
 | |
|           .queryElementAt(0, Ci.nsIFullHashMatch);
 | |
| 
 | |
|         equal(match.fullHash, "01234567890123456789012345678901");
 | |
|         equal(match.cacheDuration, 8);
 | |
|         info("completion: " + match.fullHash + ", " + table);
 | |
|       },
 | |
| 
 | |
|       completionFinished(status) {
 | |
|         equal(status, Cr.NS_OK);
 | |
|         completeFinishedCnt++;
 | |
|         if (3 === completeFinishedCnt) {
 | |
|           run_next_test();
 | |
|         }
 | |
|       },
 | |
|     }
 | |
|   );
 | |
| 
 | |
|   gCompleter.complete(
 | |
|     "1234567",
 | |
|     TEST_TABLE_DATA_V4.gethashUrl,
 | |
|     TEST_TABLE_DATA_V4.tableName,
 | |
|     {
 | |
|       completionV4(hash, table, duration, fullhashes) {
 | |
|         equal(hash, "1234567");
 | |
|         equal(table, TEST_TABLE_DATA_V4.tableName);
 | |
|         equal(duration, 120);
 | |
|         equal(fullhashes.length, 1);
 | |
| 
 | |
|         let match = fullhashes
 | |
|           .QueryInterface(Ci.nsIArray)
 | |
|           .queryElementAt(0, Ci.nsIFullHashMatch);
 | |
| 
 | |
|         equal(match.fullHash, "12345678901234567890123456789012");
 | |
|         equal(match.cacheDuration, 7);
 | |
|         info("completion: " + match.fullHash + ", " + table);
 | |
|       },
 | |
| 
 | |
|       completionFinished(status) {
 | |
|         equal(status, Cr.NS_OK);
 | |
|         completeFinishedCnt++;
 | |
|         if (3 === completeFinishedCnt) {
 | |
|           run_next_test();
 | |
|         }
 | |
|       },
 | |
|     }
 | |
|   );
 | |
| 
 | |
|   gCompleter.complete(
 | |
|     "1111",
 | |
|     TEST_TABLE_DATA_V4.gethashUrl,
 | |
|     TEST_TABLE_DATA_V4.tableName,
 | |
|     {
 | |
|       completionV4(hash, table, duration, fullhashes) {
 | |
|         equal(hash, "1111");
 | |
|         equal(table, TEST_TABLE_DATA_V4.tableName);
 | |
|         equal(duration, 120);
 | |
|         equal(fullhashes.length, 0);
 | |
|       },
 | |
| 
 | |
|       completionFinished(status) {
 | |
|         equal(status, Cr.NS_OK);
 | |
|         completeFinishedCnt++;
 | |
|         if (3 === completeFinishedCnt) {
 | |
|           run_next_test();
 | |
|         }
 | |
|       },
 | |
|     }
 | |
|   );
 | |
| });
 | |
| 
 | |
| add_test(function test_minWaitDuration() {
 | |
|   let failedComplete = function() {
 | |
|     gCompleter.complete(
 | |
|       "0123",
 | |
|       TEST_TABLE_DATA_V4.gethashUrl,
 | |
|       TEST_TABLE_DATA_V4.tableName,
 | |
|       {
 | |
|         completionFinished(status) {
 | |
|           equal(status, Cr.NS_ERROR_ABORT);
 | |
|         },
 | |
|       }
 | |
|     );
 | |
|   };
 | |
| 
 | |
|   let successComplete = function() {
 | |
|     gCompleter.complete(
 | |
|       "1234567",
 | |
|       TEST_TABLE_DATA_V4.gethashUrl,
 | |
|       TEST_TABLE_DATA_V4.tableName,
 | |
|       {
 | |
|         completionV4(hash, table, duration, fullhashes) {
 | |
|           equal(hash, "1234567");
 | |
|           equal(table, TEST_TABLE_DATA_V4.tableName);
 | |
|           equal(fullhashes.length, 1);
 | |
| 
 | |
|           let match = fullhashes
 | |
|             .QueryInterface(Ci.nsIArray)
 | |
|             .queryElementAt(0, Ci.nsIFullHashMatch);
 | |
| 
 | |
|           equal(match.fullHash, "12345678901234567890123456789012");
 | |
|           equal(match.cacheDuration, 7);
 | |
|           info("completion: " + match.fullHash + ", " + table);
 | |
|         },
 | |
| 
 | |
|         completionFinished(status) {
 | |
|           equal(status, Cr.NS_OK);
 | |
|           run_next_test();
 | |
|         },
 | |
|       }
 | |
|     );
 | |
|   };
 | |
| 
 | |
|   let request = gUrlUtil.makeFindFullHashRequestV4(
 | |
|     [TEST_TABLE_DATA_V4.tableName],
 | |
|     [btoa(NEW_CLIENT_STATE)],
 | |
|     [btoa("1234567")]
 | |
|   );
 | |
|   registerHandlerGethashV4("&$req=" + request);
 | |
| 
 | |
|   // The last gethash response contained a min wait duration 12 secs 10 nano
 | |
|   // So subsequent requests can happen only after the min wait duration
 | |
|   do_timeout(1000, failedComplete);
 | |
|   do_timeout(2000, failedComplete);
 | |
|   do_timeout(4000, failedComplete);
 | |
|   do_timeout(13000, successComplete);
 | |
| });
 | |
| 
 | |
| function registerHandlerGethashV4(aExpectedQuery) {
 | |
|   gHttpServV4.registerPathHandler(GETHASH_PATH, null);
 | |
|   // V4 gethash handler.
 | |
|   gHttpServV4.registerPathHandler(GETHASH_PATH, function(request, response) {
 | |
|     equal(request.queryString, aExpectedQuery);
 | |
| 
 | |
|     response.setStatusLine(request.httpVersion, 200, "OK");
 | |
|     response.bodyOutputStream.write(
 | |
|       GETHASH_RESPONSE_CONTENT,
 | |
|       GETHASH_RESPONSE_CONTENT.length
 | |
|     );
 | |
|   });
 | |
| }
 | |
| 
 | |
| function registerHandlerUpdateV4() {
 | |
|   // Update handler. Will respond a valid state to be verified in the
 | |
|   // gethash handler.
 | |
|   gHttpServV4.registerPathHandler(UPDATE_PATH, function(request, response) {
 | |
|     response.setHeader(
 | |
|       "Content-Type",
 | |
|       "application/vnd.google.safebrowsing-update",
 | |
|       false
 | |
|     );
 | |
|     response.setStatusLine(request.httpVersion, 200, "OK");
 | |
|     response.bodyOutputStream.write(
 | |
|       UPDATE_RESPONSE_CONTENT,
 | |
|       UPDATE_RESPONSE_CONTENT.length
 | |
|     );
 | |
| 
 | |
|     waitUntilMetaDataSaved(NEW_CLIENT_STATE, CHECKSUM, () => {
 | |
|       run_next_test();
 | |
|     });
 | |
|   });
 | |
| }
 | |
| 
 | |
| function run_test() {
 | |
|   throwOnUpdateErrors();
 | |
| 
 | |
|   gHttpServV4 = new HttpServer();
 | |
|   gHttpServV4.registerDirectory("/", do_get_cwd());
 | |
| 
 | |
|   registerHandlerUpdateV4();
 | |
|   gHttpServV4.start(5555);
 | |
|   run_next_test();
 | |
| }
 | |
| 
 | |
| registerCleanupFunction(function() {
 | |
|   stopThrowingOnUpdateErrors();
 | |
| });
 | 
