def upload_passwords_data(passdata, assertion, kB): """ Upload the passdata passwords to the Firefox Account :param passdata: The list of formated Firefox compatible password data :param assertion: :param kB: :return: """ # Connect to sync. xcs = hexlify(hashlib.sha256(kB).digest()[:16]) client = SyncClient(assertion, xcs) # Fetch /crypto/keys. raw_sync_key = fxa.crypto.derive_key(kB, "oldsync", 64) root_key_bundle = KeyBundle( raw_sync_key[:32], raw_sync_key[32:], ) keys_bso = client.get_record("crypto", "keys") keys = root_key_bundle.decrypt_bso(keys_bso) default_key_bundle = KeyBundle( base64.b64decode(keys["default"][0]), base64.b64decode(keys["default"][1]), ) for data in tqdm(passdata): encrypted_data = default_key_bundle.encrypt_bso(data) assert default_key_bundle.decrypt_bso(encrypted_data) == data client.put_record("passwords", encrypted_data) logging.debug("Synced password records: %d" % len(client.get_records("passwords"))) logging.info("Done!")
def get_client_and_key(username, password): fxa_client = FxAClient() pickle_filename = username + '.pickle' prev_session = None try: prev_session = pickle.load(open(pickle_filename, 'rb')) except Exception: pass if prev_session: session = FxASession(fxa_client, username, quick_stretch_password(username, password), prev_session.uid, prev_session.token) session.keys = prev_session.keys session.check_session_status() else: session = fxa_client.login(username, password, keys=True) session.fetch_keys() pickle.dump(session, open(pickle_filename, 'wb')) bid_assertion_args = get_browserid_assertion(session) client = SyncClient(*bid_assertion_args) sync_keys = KeyBundle.fromMasterKey( session.keys[1], b"identity.mozilla.com/picl/v1/oldsync") # Fetch the sync bundle keys out of storage. # They're encrypted with the account-level key. keys = decrypt_payload(client.get_record('crypto', 'keys')['payload'], sync_keys) # There's some provision for using separate key bundles # for separate collections # but I haven't bothered digging through to see what that's about because # it doesn't seem to be in use, at least on my account. if keys["collections"]: raise RuntimeError("no support for per-collection key bundles") bulk_keys = KeyBundle(base64.b64decode(keys["default"][0]), base64.b64decode(keys["default"][1])) return (client, bulk_keys)
class ClientHTTPCallsTest(unittest.TestCase): def setUp(self): super(ClientHTTPCallsTest, self).setUp() self.client = SyncClient( hashalg=mock.sentinel.hashalg, id=mock.sentinel.id, key=mock.sentinel.key, uid=mock.sentinel.uid, api_endpoint=mock.sentinel.api_endpoint ) # Mock the request method of the client, since we'll use # it to make sure the correct requests are made. self.client._request = mock.MagicMock() def test_info_collection(self): self.client.info_collections() self.client._request.assert_called_with('get', '/info/collections') def test_info_collection_can_receive_requests_parameters(self): self.client.info_collections(headers=mock.sentinel.headers) self.client._request.assert_called_with('get', '/info/collections', headers=mock.sentinel.headers) def test_info_quota(self): self.client.info_quota() self.client._request.assert_called_with('get', '/info/quota') def test_info_quota_can_receive_requests_parameters(self): self.client.info_quota(headers=mock.sentinel.headers) self.client._request.assert_called_with('get', '/info/quota', headers=mock.sentinel.headers) def test_collection_usage(self): self.client.get_collection_usage() self.client._request.assert_called_with( 'get', '/info/collection_usage') def test_collection_usage_can_receive_requests_parameters(self): self.client.get_collection_usage(headers=mock.sentinel.headers) self.client._request.assert_called_with( 'get', '/info/collection_usage', headers=mock.sentinel.headers) def test_collection_counts(self): self.client.get_collection_counts() self.client._request.assert_called_with( 'get', '/info/collection_counts') def test_collection_counts_can_receive_requests_parameters(self): self.client.get_collection_counts(headers=mock.sentinel.headers) self.client._request.assert_called_with( 'get', '/info/collection_counts', headers=mock.sentinel.headers) def test_delete_all_records(self): self.client.delete_all_records() self.client._request.assert_called_with( 'delete', '/') def test_delete_all_records_can_receive_requests_parameters(self): self.client.delete_all_records(headers=mock.sentinel.headers) self.client._request.assert_called_with( 'delete', '/', headers=mock.sentinel.headers) def test_get_records_sets_full_by_default(self): self.client.get_records('mycollection') self.client._request.assert_called_with( 'get', '/storage/mycollection', params={'full': True}) def test_get_records_lowers_the_collection_name(self): self.client.get_records('myCollection') self.client._request.assert_called_with( 'get', '/storage/mycollection', params={'full': True}) def test_get_records_handles_ids(self): self.client.get_records('myCollection', ids=(1, 3)) self.client._request.assert_called_with( 'get', '/storage/mycollection', params={'full': True, 'ids': '1,3'}) def test_get_records_handles_full(self): self.client.get_records('mycollection', full=False) self.client._request.assert_called_with( 'get', '/storage/mycollection', params={}) def test_get_records_handles_newer(self): self.client.get_records('mycollection', newer='newer') self.client._request.assert_called_with( 'get', '/storage/mycollection', params={'newer': 'newer', 'full': True}) def test_get_records_handles_limit(self): self.client.get_records('mycollection', limit='limit') self.client._request.assert_called_with( 'get', '/storage/mycollection', params={'limit': 'limit', 'full': True}) def test_get_records_handles_offset(self): self.client.get_records('mycollection', offset='offset') self.client._request.assert_called_with( 'get', '/storage/mycollection', params={'offset': 'offset', 'full': True}) def test_get_records_handles_sort_by_newest(self): self.client.get_records('mycollection', sort='newest') self.client._request.assert_called_with( 'get', '/storage/mycollection', params={'sort': 'newest', 'full': True}) def test_get_records_handles_sort_by_oldest(self): self.client.get_records('mycollection', sort='oldest') self.client._request.assert_called_with( 'get', '/storage/mycollection', params={'sort': 'oldest', 'full': True}) def test_get_records_handles_sort_by_index(self): self.client.get_records('mycollection', sort='index') self.client._request.assert_called_with( 'get', '/storage/mycollection', params={'sort': 'index', 'full': True}) def test_get_records_ignore_sort_by_invalid(self): self.client.get_records('mycollection', sort='invalid') self.client._request.assert_called_with( 'get', '/storage/mycollection', params={'full': True}) def test_get_record(self): self.client.get_record('myCollection', 1234) self.client._request.assert_called_with( 'get', '/storage/mycollection/1234') def test_get_record_can_receive_requests_parameters(self): self.client.get_record('myCollection', 1234, headers=mock.sentinel.headers) self.client._request.assert_called_with( 'get', '/storage/mycollection/1234', headers=mock.sentinel.headers) def test_delete_record(self): self.client.delete_record('myCollection', 1234) self.client._request.assert_called_with( 'delete', '/storage/mycollection/1234') def test_delete_record_can_receive_requests_parameters(self): self.client.delete_record('myCollection', 1234, headers=mock.sentinel.headers) self.client._request.assert_called_with( 'delete', '/storage/mycollection/1234', headers=mock.sentinel.headers) def test_put_record(self): record = {'id': 1234, 'foo': 'bar'} self.client.put_record('myCollection', record) self.client._request.assert_called_with( 'put', '/storage/mycollection/1234', data='{"foo": "bar"}', headers={'Content-Type': 'application/json; charset=utf-8'}) def test_put_record_handle_json_string_parameter(self): record = '{"id": 1234, "foo": "bar"}' self.client.put_record('myCollection', record) self.client._request.assert_called_with( 'put', '/storage/mycollection/1234', data='{"foo": "bar"}', headers={'Content-Type': 'application/json; charset=utf-8'}) def test_put_record_can_receive_requests_parameters(self): record = {'id': 1234, 'foo': 'bar'} self.client.put_record('myCollection', record, headers={'Sentinel': 'true'}) self.client._request.assert_called_with( 'put', '/storage/mycollection/1234', data='{"foo": "bar"}', headers={'Content-Type': 'application/json; charset=utf-8', 'Sentinel': 'true'}) def test_put_record_doesnt_modify_the_passed_object(self): record = {'id': 1234, 'foo': 'bar'} self.client.put_record('myCollection', record) assert 'id' in record.keys() def test_post_records(self): # For now, this does nothing. records = [{'id': idx, 'foo': 'foo'} for idx in range(1, 10)] self.client.post_records("myCollection", records)