From bd98a4eea43ab0d63112f15f2ea3e2aa6c12f7c7 Mon Sep 17 00:00:00 2001 From: sdb9696 Date: Tue, 19 Mar 2024 07:45:25 +0000 Subject: [PATCH 1/5] Add ruff pre-commit hook --- .pre-commit-config.yaml | 23 +-- docs/source/conf.py | 2 +- firebase_messaging/__init__.py | 2 +- firebase_messaging/fcm.py | 2 +- firebase_messaging/fcmpushclient.py | 23 +-- firebase_messaging/gcm.py | 1 - .../proto/android_checkin_pb2.py | 1 - firebase_messaging/proto/checkin_pb2.py | 3 - firebase_messaging/proto/mcs_pb2.py | 1 - pyproject.toml | 39 ++++ tests/conftest.py | 76 ++++---- tests/fakes.py | 61 +++--- tests/test_fcmpushclient.py | 179 +++++++++++------- 13 files changed, 242 insertions(+), 171 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 617c11d..6913dd6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,26 +4,13 @@ repos: hooks: - id: poetry-check -- repo: https://github.com/python/black - rev: 23.3.0 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.3 hooks: - - id: black - files: firebase_messaging + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format -- repo: https://github.com/pycqa/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - #files: firebase_messaging -- repo: local - hooks: - - id: pylint - name: pylint - entry: pylint - language: system - types: [python] - require_serial: true - files: firebase_messaging diff --git a/docs/source/conf.py b/docs/source/conf.py index f6ca0a2..b30df1c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -32,5 +32,5 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = "sphinx_rtd_theme" -autodoc_member_order = 'bysource' +autodoc_member_order = "bysource" # html_static_path = ["_static"] diff --git a/firebase_messaging/__init__.py b/firebase_messaging/__init__.py index 5673c3f..3797f54 100644 --- a/firebase_messaging/__init__.py +++ b/firebase_messaging/__init__.py @@ -1,3 +1,3 @@ -from .fcmpushclient import FcmPushClientConfig, FcmPushClient, FcmPushClientRunState +from .fcmpushclient import FcmPushClient, FcmPushClientConfig, FcmPushClientRunState __all__ = ["FcmPushClientConfig", "FcmPushClient", "FcmPushClientRunState"] diff --git a/firebase_messaging/fcm.py b/firebase_messaging/fcm.py index 7fca068..f13155f 100644 --- a/firebase_messaging/fcm.py +++ b/firebase_messaging/fcm.py @@ -48,7 +48,7 @@ def fcm_register(sender_id, token, retries=5, log_debug_verbose=False): } data = { "authorized_entity": sender_id, - "endpoint": "{}/{}".format(FCM_SEND_URL, token), + "endpoint": f"{FCM_SEND_URL}/{token}", "encryption_key": keys["public"], "encryption_auth": keys["secret"], } diff --git a/firebase_messaging/fcmpushclient.py b/firebase_messaging/fcmpushclient.py index 56e2db7..d425ccc 100644 --- a/firebase_messaging/fcmpushclient.py +++ b/firebase_messaging/fcmpushclient.py @@ -6,11 +6,13 @@ import time import traceback from base64 import urlsafe_b64decode -from ssl import SSLError -from threading import Thread -from typing import Any, Callable, Optional, List +from contextlib import suppress as contextlib_suppress from dataclasses import dataclass from enum import Enum +from ssl import SSLError +from threading import Thread +from typing import Any, Callable, List, Optional + from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.serialization import load_der_private_key from google.protobuf.json_format import MessageToJson @@ -36,7 +38,6 @@ SelectiveAck, ) - _logger = logging.getLogger(__name__) @@ -250,10 +251,8 @@ def _encode_varint32(x): @staticmethod def _make_packet(msg, include_version): tag = MCS_MESSAGE_TAG[type(msg)] - if include_version: - header = bytearray([MCS_VERSION, tag]) - else: - header = bytearray([tag]) + + header = bytearray([MCS_VERSION, tag]) if include_version else bytearray([tag]) payload = msg.SerializeToString() buf = bytes(header) + FcmPushClient._encode_varint32(len(payload)) + payload @@ -271,7 +270,7 @@ async def _receive_msg(self): r = await self.reader.readexactly(2) version, tag = struct.unpack("BB", r) if version < MCS_VERSION and version != 38: - raise RuntimeError("protocol version {} unsupported".format(version)) + raise RuntimeError(f"protocol version {version} unsupported") self.first_message = False else: r = await self.reader.readexactly(1) @@ -371,7 +370,7 @@ def _app_data_by_key(self, p, key): if x.key == key: return x.value - raise RuntimeError("couldn't find in app_data {}".format(key)) + raise RuntimeError(f"couldn't find in app_data {key}") def _handle_data_message(self, callback, msg, obj): _logger.debug( @@ -394,10 +393,8 @@ def _handle_data_message(self, callback, msg, obj): decrypted = self._decrypt_raw_data( self.credentials, crypto_key, salt, msg.raw_data ) - try: + with contextlib_suppress((json.JSONDecodeError, ValueError)): decrypted_json = json.loads(decrypted.decode("utf-8")) - except (json.JSONDecodeError, ValueError): - pass ret_val = decrypted_json if decrypted_json else decrypted self._log_verbose( diff --git a/firebase_messaging/gcm.py b/firebase_messaging/gcm.py index a1a0052..4d803ec 100644 --- a/firebase_messaging/gcm.py +++ b/firebase_messaging/gcm.py @@ -3,7 +3,6 @@ from typing import Optional import requests - from google.protobuf.json_format import MessageToDict, MessageToJson from .const import GCM_CHECKIN_URL, GCM_REGISTER_URL, GCM_SERVER_KEY_B64 diff --git a/firebase_messaging/proto/android_checkin_pb2.py b/firebase_messaging/proto/android_checkin_pb2.py index 5644629..a4cf074 100644 --- a/firebase_messaging/proto/android_checkin_pb2.py +++ b/firebase_messaging/proto/android_checkin_pb2.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: android_checkin.proto """Generated protocol buffer code.""" diff --git a/firebase_messaging/proto/checkin_pb2.py b/firebase_messaging/proto/checkin_pb2.py index 18bffb0..0b5f980 100644 --- a/firebase_messaging/proto/checkin_pb2.py +++ b/firebase_messaging/proto/checkin_pb2.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: checkin.proto """Generated protocol buffer code.""" @@ -12,8 +11,6 @@ _sym_db = _symbol_database.Default() -from . import android_checkin_pb2 as android__checkin__pb2 - DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( b'\n\rcheckin.proto\x12\rcheckin_proto\x1a\x15\x61ndroid_checkin.proto"/\n\x10GservicesSetting\x12\x0c\n\x04name\x18\x01 \x02(\x0c\x12\r\n\x05value\x18\x02 \x02(\x0c"\xcb\x03\n\x15\x41ndroidCheckinRequest\x12\x0c\n\x04imei\x18\x01 \x01(\t\x12\x0c\n\x04meid\x18\n \x01(\t\x12\x10\n\x08mac_addr\x18\t \x03(\t\x12\x15\n\rmac_addr_type\x18\x13 \x03(\t\x12\x15\n\rserial_number\x18\x10 \x01(\t\x12\x0b\n\x03\x65sn\x18\x11 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\x03\x12\x12\n\nlogging_id\x18\x07 \x01(\x03\x12\x0e\n\x06\x64igest\x18\x03 \x01(\t\x12\x0e\n\x06locale\x18\x06 \x01(\t\x12\x33\n\x07\x63heckin\x18\x04 \x02(\x0b\x32".checkin_proto.AndroidCheckinProto\x12\x15\n\rdesired_build\x18\x05 \x01(\t\x12\x16\n\x0emarket_checkin\x18\x08 \x01(\t\x12\x16\n\x0e\x61\x63\x63ount_cookie\x18\x0b \x03(\t\x12\x11\n\ttime_zone\x18\x0c \x01(\t\x12\x16\n\x0esecurity_token\x18\r \x01(\x06\x12\x0f\n\x07version\x18\x0e \x01(\x05\x12\x10\n\x08ota_cert\x18\x0f \x03(\t\x12\x10\n\x08\x66ragment\x18\x14 \x01(\x05\x12\x11\n\tuser_name\x18\x15 \x01(\t\x12\x1a\n\x12user_serial_number\x18\x16 \x01(\x05"\x83\x02\n\x16\x41ndroidCheckinResponse\x12\x10\n\x08stats_ok\x18\x01 \x02(\x08\x12\x11\n\ttime_msec\x18\x03 \x01(\x03\x12\x0e\n\x06\x64igest\x18\x04 \x01(\t\x12\x15\n\rsettings_diff\x18\t \x01(\x08\x12\x16\n\x0e\x64\x65lete_setting\x18\n \x03(\t\x12\x30\n\x07setting\x18\x05 \x03(\x0b\x32\x1f.checkin_proto.GservicesSetting\x12\x11\n\tmarket_ok\x18\x06 \x01(\x08\x12\x12\n\nandroid_id\x18\x07 \x01(\x06\x12\x16\n\x0esecurity_token\x18\x08 \x01(\x06\x12\x14\n\x0cversion_info\x18\x0b \x01(\tB\x02H\x03' ) diff --git a/firebase_messaging/proto/mcs_pb2.py b/firebase_messaging/proto/mcs_pb2.py index 9abaafa..6b7fcc2 100644 --- a/firebase_messaging/proto/mcs_pb2.py +++ b/firebase_messaging/proto/mcs_pb2.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: mcs.proto """Generated protocol buffer code.""" diff --git a/pyproject.toml b/pyproject.toml index c105c5c..7723796 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,3 +84,42 @@ ignore-paths = ["firebase_messaging/proto", "firebase_messaging/decrypt.py", "te [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" + +[tool.ruff] +target-version = "py38" +exclude = [ + "firebase_messaging/proto/*" +] +select = [ + "E", # pycodestyle +# "D", # pydocstyle + "F", # pyflakes + "UP", # pyupgrade + "B", # flake8-bugbear + "SIM", # flake8-simplify + "I", # isort + "S", # bandit +] +ignore = [ + "D105", # Missing docstring in magic method + "D107", # Missing docstring in `__init__` +] + +[tool.ruff.pydocstyle] +convention = "pep257" + +[tool.ruff.per-file-ignores] +"tests/*.py" = [ + "D100", + "D101", + "D102", + "D103", + "D104", + "F401", + "S101", # allow asserts + "E501", # ignore line-too-longs +] +"docs/source/conf.py" = [ + "D100", + "D103", +] \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 63d1ec2..e11d798 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,21 +1,18 @@ """Test configuration for the Ring platform.""" -import pytest -import requests_mock -import threading -import os -import select -from unittest.mock import MagicMock, DEFAULT, Mock, patch import asyncio -import time +import json import logging -import ssl as ssl_lib -import socket +import os +import threading + +import pytest +import requests_mock from google.protobuf.json_format import Parse as JsonParse + +from firebase_messaging.fcmpushclient import FcmPushClient, FcmPushClientConfig +from firebase_messaging.proto.checkin_pb2 import AndroidCheckinResponse from firebase_messaging.proto.mcs_pb2 import LoginResponse -from firebase_messaging.proto.checkin_pb2 import * -from firebase_messaging.fcmpushclient import MCS_VERSION, MCS_MESSAGE_TAG, FcmPushClient, FcmPushClientConfig -from tests.fakes import * -import json +from tests.fakes import FakeMcsEndpoint def load_fixture(filename): @@ -23,44 +20,58 @@ def load_fixture(filename): path = os.path.join(os.path.dirname(__file__), "fixtures", filename) with open(path) as fdp: return fdp.read() - + + def load_fixture_as_dict(filename): """Load a fixture.""" return json.loads(load_fixture(filename)) + def load_fixture_as_msg(filename, msg_class): """Load a fixture.""" msg = msg_class() JsonParse(load_fixture(filename), msg) return msg - - + + @pytest.fixture() async def fake_mcs_endpoint(): - #async with McsEndpoint() as ep: - ep = FakeMcsEndpoint() + # async with McsEndpoint() as ep: + ep = FakeMcsEndpoint() yield ep - + ep.close() - + @pytest.fixture(params=[None, "loop"], ids=["loop_created", "loop_provided"]) async def logged_in_push_client(request, fake_mcs_endpoint, mocker, caplog): - clients = {} caplog.set_level(logging.DEBUG) listen_loop = asyncio.get_running_loop() if request.param else None - async def _logged_in_push_client(credentials, msg_callback, callback_obj = None, callback_loop=None, *, supress_disconnect=False, **config_kwargs): + async def _logged_in_push_client( + credentials, + msg_callback, + callback_obj=None, + callback_loop=None, + *, + supress_disconnect=False, + **config_kwargs, + ): config = FcmPushClientConfig(**config_kwargs) pr = FcmPushClient(credentials=credentials, config=config) pr.checkin(1234, 4321) cb_loop = asyncio.get_running_loop() if callback_loop else None - pr.start(msg_callback, callback_obj, listen_event_loop=listen_loop, callback_event_loop=cb_loop) + pr.start( + msg_callback, + callback_obj, + listen_event_loop=listen_loop, + callback_event_loop=cb_loop, + ) - msg = await fake_mcs_endpoint.get_message() + await fake_mcs_endpoint.get_message() lr = load_fixture_as_msg("login_response.json", LoginResponse) await fake_mcs_endpoint.put_message(lr) clients[pr] = supress_disconnect @@ -74,28 +85,29 @@ async def _logged_in_push_client(credentials, msg_callback, callback_obj = None, return pr yield _logged_in_push_client - + for k, v in clients.items(): if not v: k.stop() + # setting the fixture name to requests_mock allows other # tests to pull in request_mock and append uris @pytest.fixture(autouse=True, name="requests_mock") def requests_mock_fixture(): with requests_mock.Mocker() as mock: mock.post( - "https://android.clients.google.com/checkin", - content = load_fixture_as_msg("android_checkin_response.json", AndroidCheckinResponse).SerializeToString() + "https://android.clients.google.com/checkin", + content=load_fixture_as_msg( + "android_checkin_response.json", AndroidCheckinResponse + ).SerializeToString(), ) mock.post( - 'https://android.clients.google.com/c2dm/register3', + "https://android.clients.google.com/c2dm/register3", text=load_fixture("gcm_register_response.txt"), ) mock.post( - 'https://fcm.googleapis.com/fcm/connect/subscribe', + "https://fcm.googleapis.com/fcm/connect/subscribe", json=load_fixture_as_dict("fcm_register_response.json"), - - ) + ) yield mock - diff --git a/tests/fakes.py b/tests/fakes.py index 951a84f..eb9cbd4 100644 --- a/tests/fakes.py +++ b/tests/fakes.py @@ -1,19 +1,21 @@ +import asyncio import struct from unittest.mock import patch -import asyncio -from firebase_messaging.proto.mcs_pb2 import LoginResponse -from firebase_messaging.proto.checkin_pb2 import * -from firebase_messaging.fcmpushclient import MCS_VERSION, MCS_MESSAGE_TAG, FcmPushClient # When support for cpython older than 3.11 is dropped # async_timeout can be replaced with asyncio.timeout from async_timeout import timeout as asyncio_timeout -class FakeMcsEndpoint(): +from firebase_messaging.fcmpushclient import MCS_MESSAGE_TAG, MCS_VERSION, FcmPushClient +from firebase_messaging.proto.checkin_pb2 import AndroidCheckinResponse +from firebase_messaging.proto.mcs_pb2 import LoginResponse + +class FakeMcsEndpoint: def __init__(self): - - self.connection_mock = patch("asyncio.open_connection", side_effect = self.open_connection, autospec=True) + self.connection_mock = patch( + "asyncio.open_connection", side_effect=self.open_connection, autospec=True + ) self.connection_mock.start() self.client_loop = None @@ -25,7 +27,6 @@ def __init__(self): def close(self): self.connection_mock.stop() - async def open_connection(self, *_, **__): # Queues should be created on the loop that will be accessing them self.client_writer = self.FakeWriter() @@ -41,23 +42,27 @@ async def wait_for_connection(self, timeout=10): async def put_message(self, message): await self.wait_for_connection() if self.init_loop != self.client_loop: - asyncio.run_coroutine_threadsafe(self.client_reader.put_message(message), self.client_loop) + asyncio.run_coroutine_threadsafe( + self.client_reader.put_message(message), self.client_loop + ) else: await self.client_reader.put_message(message) - async def put_error(self, error): await self.wait_for_connection() if self.init_loop != self.client_loop: - asyncio.run_coroutine_threadsafe(self.client_reader.put_error(error), self.client_loop) + asyncio.run_coroutine_threadsafe( + self.client_reader.put_error(error), self.client_loop + ) else: await self.client_reader.put_error(error) - async def get_message(self): await self.wait_for_connection() if self.init_loop != self.client_loop: - fut = asyncio.run_coroutine_threadsafe(self.client_writer.get_message(), self.client_loop) + fut = asyncio.run_coroutine_threadsafe( + self.client_writer.get_message(), self.client_loop + ) return fut.result() else: return await self.client_writer.get_message() @@ -66,7 +71,6 @@ class FakeReader: def __init__(self): self.queue = asyncio.Queue() - async def readexactly(self, size): if size == 0: return b"" @@ -74,10 +78,10 @@ async def readexactly(self, size): if isinstance(val, BaseException): raise val else: - for i in range(1, size): + for _ in range(1, size): val += await self.queue.get() return val - + async def put_message(self, message): include_version = isinstance(message, LoginResponse) packet = FcmPushClient._make_packet(message, include_version) @@ -85,25 +89,22 @@ async def put_message(self, message): b = bytes([p]) await self.queue.put(b) - async def put_error(self, error): await self.queue.put(error) - class FakeWriter: def __init__(self): self.queue = asyncio.Queue() - self.buf = '' + self.buf = "" - def write(self, buffer): for i in buffer: b = bytes([i]) self.queue.put_nowait(b) - + async def drain(self): pass - + def close(self): pass @@ -111,26 +112,27 @@ async def wait_closed(self): pass async def get_bytes(self, size): - val = b'' - for i in range(size): + val = b"" + for _ in range(size): val += await self.queue.get() return val - - async def get_message(self, timeout = 2): + + async def get_message(self, timeout=2): async with asyncio_timeout(timeout): r = await self.get_bytes(1) (b,) = struct.unpack("B", r) - if b == MCS_VERSION: # first message + if b == MCS_VERSION: # first message r = await self.get_bytes(1) (b,) = struct.unpack("B", r) tag = b size = await self._read_varint32() msgstr = await self.get_bytes(size) - msg_class = next(iter([ c for c, t in MCS_MESSAGE_TAG.items() if t == tag ])) + msg_class = next( + iter([c for c, t in MCS_MESSAGE_TAG.items() if t == tag]) + ) msg = msg_class() msg.ParseFromString(msgstr) return msg - # protobuf variable length integers are encoded in base 128 # each byte contains 7 bits of the integer and the msb is set if there's @@ -146,4 +148,3 @@ async def _read_varint32(self): break shift += 7 return res - \ No newline at end of file diff --git a/tests/test_fcmpushclient.py b/tests/test_fcmpushclient.py index 24b486b..42fcc87 100644 --- a/tests/test_fcmpushclient.py +++ b/tests/test_fcmpushclient.py @@ -1,50 +1,66 @@ """The tests for the Ring platform.""" -import pytest -import logging import asyncio -import requests_mock -from unittest.mock import MagicMock -from firebase_messaging import FcmPushClient -from firebase_messaging.proto.mcs_pb2 import * -from tests.conftest import load_fixture_as_msg, load_fixture_as_dict -from http_ece import encrypt -from base64 import urlsafe_b64decode, standard_b64encode -from cryptography.hazmat.primitives.serialization import load_der_private_key +from base64 import standard_b64encode, urlsafe_b64decode + +import pytest from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.serialization import load_der_private_key +from http_ece import encrypt +from firebase_messaging import FcmPushClient +from firebase_messaging.proto.mcs_pb2 import ( + Close, + DataMessageStanza, + HeartbeatAck, + HeartbeatPing, + IqStanza, + LoginRequest, +) +from tests.conftest import load_fixture_as_dict, load_fixture_as_msg def test_register(requests_mock): pr = FcmPushClient(credentials=None) pr.checkin(1234, 4321) -async def test_no_disconnect(logged_in_push_client, fake_mcs_endpoint, mocker, caplog): - +async def test_no_disconnect(logged_in_push_client, fake_mcs_endpoint, mocker, caplog): pr = await logged_in_push_client(None, None, supress_disconnect=True) pr.__del__() await asyncio.sleep(0.1) - assert len([record for record in caplog.records if record.levelname == "ERROR"]) == 0 + assert ( + len([record for record in caplog.records if record.levelname == "ERROR"]) == 0 + ) - assert "FCMClient has shutdown" in [record.message for record in caplog.records if record.levelname == "INFO"] + assert "FCMClient has shutdown" in [ + record.message for record in caplog.records if record.levelname == "INFO" + ] async def test_login(logged_in_push_client, fake_mcs_endpoint, mocker, caplog): - - pr = await logged_in_push_client(None, None) + await logged_in_push_client(None, None) await asyncio.sleep(0.1) - assert len([record for record in caplog.records if record.levelname == "ERROR"]) == 0 - assert "Succesfully logged in to MCS endpoint" in [record.message for record in caplog.records if record.levelname == "INFO"] + assert ( + len([record for record in caplog.records if record.levelname == "ERROR"]) == 0 + ) + assert "Succesfully logged in to MCS endpoint" in [ + record.message for record in caplog.records if record.levelname == "INFO" + ] -@pytest.mark.parametrize("callback_loop", [None, "loop"], ids=["no_cb_loop_param", "cb_loop_param"]) -async def test_data_message_receive(logged_in_push_client, fake_mcs_endpoint, mocker, caplog, callback_loop): +@pytest.mark.parametrize( + "callback_loop", [None, "loop"], ids=["no_cb_loop_param", "cb_loop_param"] +) +async def test_data_message_receive( + logged_in_push_client, fake_mcs_endpoint, mocker, caplog, callback_loop +): notification = None persistent_id = None callback_obj = None cb_loop = None + def on_msg(ntf, psid, obj=None): nonlocal notification nonlocal persistent_id @@ -65,9 +81,11 @@ def on_msg(ntf, psid, obj=None): msg = await fake_mcs_endpoint.get_message() assert isinstance(msg, IqStanza) await asyncio.sleep(0.1) - assert len([record for record in caplog.records if record.levelname == "ERROR"]) == 0 - - assert notification == {'foo': 'bar'} + assert ( + len([record for record in caplog.records if record.levelname == "ERROR"]) == 0 + ) + + assert notification == {"foo": "bar"} assert persistent_id == dms.persistent_id assert obj == callback_obj @@ -75,36 +93,42 @@ def on_msg(ntf, psid, obj=None): assert cb_loop == asyncio.get_running_loop() else: assert cb_loop == pr.listen_event_loop - + async def test_connection_reset(logged_in_push_client, fake_mcs_endpoint, mocker): - #ConnectionResetError, TimeoutError, SSLError - pr = await logged_in_push_client(None, None, abort_on_sequential_error_count=3, reset_interval=0.1) + # ConnectionResetError, TimeoutError, SSLError + pr = await logged_in_push_client( + None, None, abort_on_sequential_error_count=3, reset_interval=0.1 + ) mocker.patch.object(FcmPushClient, "_reset", wraps=pr._reset) assert pr._reset.call_count == 0 - close = load_fixture_as_msg("close.json", Close) - - await fake_mcs_endpoint.put_error(ConnectionResetError()) - + + await fake_mcs_endpoint.put_error(ConnectionResetError()) + await asyncio.sleep(0.1) assert pr._reset.call_count == 1 - + msg = await fake_mcs_endpoint.get_message() assert isinstance(msg, LoginRequest) - -@pytest.mark.parametrize("error_count", [1,2,3,6]) -async def test_terminate(logged_in_push_client, fake_mcs_endpoint, mocker, error_count, caplog): - #ConnectionResetError, TimeoutError, SSLError - pr = await logged_in_push_client(None, None, abort_on_sequential_error_count=error_count, reset_interval=0) + + +@pytest.mark.parametrize("error_count", [1, 2, 3, 6]) +async def test_terminate( + logged_in_push_client, fake_mcs_endpoint, mocker, error_count, caplog +): + # ConnectionResetError, TimeoutError, SSLError + pr = await logged_in_push_client( + None, None, abort_on_sequential_error_count=error_count, reset_interval=0 + ) mocker.patch.object(FcmPushClient, "_reset", wraps=pr._reset) mocker.patch.object(FcmPushClient, "_terminate", wraps=pr._terminate) assert pr._reset.call_count == 0 - for i in range(1,error_count + 1): + for i in range(1, error_count + 1): await fake_mcs_endpoint.put_error(ConnectionResetError()) await asyncio.sleep(0.1) @@ -120,22 +144,22 @@ async def test_terminate(logged_in_push_client, fake_mcs_endpoint, mocker, error async def test_heartbeat_receive(logged_in_push_client, fake_mcs_endpoint, caplog): - - pr = await logged_in_push_client(None, None) + await logged_in_push_client(None, None) ping = load_fixture_as_msg("heartbeat_ping.json", HeartbeatPing) await fake_mcs_endpoint.put_message(ping) msg = await fake_mcs_endpoint.get_message() assert isinstance(msg, HeartbeatAck) - - assert len([record for record in caplog.records if record.levelname == "ERROR"]) == 0 -async def test_heartbeat_send(logged_in_push_client, fake_mcs_endpoint, mocker, caplog): + assert ( + len([record for record in caplog.records if record.levelname == "ERROR"]) == 0 + ) - pr : FcmPushClient = await logged_in_push_client(None, None) - ping = load_fixture_as_msg("heartbeat_ping.json", HeartbeatPing) +async def test_heartbeat_send(logged_in_push_client, fake_mcs_endpoint, mocker, caplog): + pr: FcmPushClient = await logged_in_push_client(None, None) + ack = load_fixture_as_msg("heartbeat_ack.json", HeartbeatAck) await pr._send_heartbeat() @@ -144,8 +168,18 @@ async def test_heartbeat_send(logged_in_push_client, fake_mcs_endpoint, mocker, await fake_mcs_endpoint.put_message(ack) await asyncio.sleep(0.1) assert isinstance(ping_msg, HeartbeatPing) - - assert len([record.message for record in caplog.records if record.levelname == "DEBUG" and "Received heartbeat ack" in record.message] ) == 1 + + assert ( + len( + [ + record.message + for record in caplog.records + if record.levelname == "DEBUG" + and "Received heartbeat ack" in record.message + ] + ) + == 1 + ) async def test_decrypt(): @@ -153,43 +187,50 @@ def get_app_data_by_key(msg, key): for x in msg.app_data: if x.key == key: return x.value - + def set_app_data_by_key(msg, key, value): for x in msg.app_data: if x.key == key: x.value = value - + dms = load_fixture_as_msg("data_message_stanza.json", DataMessageStanza) credentials = load_fixture_as_dict("credentials.json") raw_data = b'{ "foo" : "bar" }' salt_str = get_app_data_by_key(dms, "encryption")[5:] salt = urlsafe_b64decode(salt_str.encode("ascii")) - # Random key pair - sender_pub = 'BAGEFtID7WlmwzQ9pbjdRYAhfPe7Z8lA3ZGIPUh0SE3ikoY2PIrWUP0rmhpE4Kl8ImgMUDjKWrz0WmtLxORIHuw' - - sender_pri_der = urlsafe_b64decode('MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgwSUpDfIqdJG3XVkn7t1GExHuW3gsqD4-J525w-rnCIihRANCAAQBhBbSA-1pZsM0PaW43UWAIXz3u2fJQN2RiD1IdEhN4pKGNjyK1lD9K5oaROCpfCJoDFA4ylq89FprS8TkSB7s'.encode("ascii") + b"========") - sender_privkey = load_der_private_key( - sender_pri_der, password=None, backend=default_backend() - ) + sender_pub = "BAGEFtID7WlmwzQ9pbjdRYAhfPe7Z8lA3ZGIPUh0SE3ikoY2PIrWUP0rmhpE4Kl8ImgMUDjKWrz0WmtLxORIHuw" - sender_sec = urlsafe_b64decode(credentials["keys"]["secret"].encode("ascii") + b"========") - receiver_pub_key = urlsafe_b64decode(credentials["keys"]["public"].encode("ascii") + b"=") - raw_data_encrypted = encrypt( - raw_data, - salt=salt, - private_key=sender_privkey, - dh=receiver_pub_key, - version="aesgcm", - auth_secret=sender_sec, + sender_pri_der = urlsafe_b64decode( + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgwSUpDfIqdJG3XVkn7t1GExHuW3gsqD4-J525w-rnCIihRANCAAQBhBbSA-1pZsM0PaW43UWAIXz3u2fJQN2RiD1IdEhN4pKGNjyK1lD9K5oaROCpfCJoDFA4ylq89FprS8TkSB7s".encode( + "ascii" ) - b64encode = standard_b64encode(raw_data_encrypted) + + b"========" + ) + sender_privkey = load_der_private_key( + sender_pri_der, password=None, backend=default_backend() + ) + + sender_sec = urlsafe_b64decode( + credentials["keys"]["secret"].encode("ascii") + b"========" + ) + receiver_pub_key = urlsafe_b64decode( + credentials["keys"]["public"].encode("ascii") + b"=" + ) + raw_data_encrypted = encrypt( + raw_data, + salt=salt, + private_key=sender_privkey, + dh=receiver_pub_key, + version="aesgcm", + auth_secret=sender_sec, + ) + set_app_data_by_key(dms, "crypto-key", "dh=" + sender_pub) - raw_data_decrypted = FcmPushClient._decrypt_raw_data(credentials, sender_pub + "=", salt_str, raw_data_encrypted) + raw_data_decrypted = FcmPushClient._decrypt_raw_data( + credentials, sender_pub + "=", salt_str, raw_data_encrypted + ) assert raw_data_decrypted == raw_data - - - From ae3bc8821c1ca16fc6da00af0f0655851f6f848f Mon Sep 17 00:00:00 2001 From: sdb9696 Date: Tue, 19 Mar 2024 09:26:59 +0000 Subject: [PATCH 2/5] Add typing --- .pre-commit-config.yaml | 20 +- firebase_messaging/fcmpushclient.py | 35 +- firebase_messaging/gcm.py | 15 +- .../proto/android_checkin_pb2.py | 36 +- .../proto/android_checkin_pb2.pyi | 187 +++++ firebase_messaging/proto/checkin_pb2.pyi | 275 +++++++ firebase_messaging/proto/mcs_pb2.pyi | 700 ++++++++++++++++++ firebase_messaging/py.typed | 0 poetry.lock | 230 +----- pyproject.toml | 19 +- 10 files changed, 1239 insertions(+), 278 deletions(-) create mode 100644 firebase_messaging/proto/android_checkin_pb2.pyi create mode 100644 firebase_messaging/proto/checkin_pb2.pyi create mode 100644 firebase_messaging/proto/mcs_pb2.pyi create mode 100644 firebase_messaging/py.typed diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6913dd6..87910ee 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,8 +1,8 @@ repos: -- repo: https://github.com/python-poetry/poetry - rev: 1.6.0 - hooks: - - id: poetry-check +- repo: https://github.com/python-poetry/poetry + rev: 1.6.0 + hooks: + - id: poetry-check - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.1.3 @@ -11,6 +11,18 @@ repos: args: [--fix, --exit-non-zero-on-fix] - id: ruff-format +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.9.0 + hooks: + - id: mypy + args: ["--install-types", "--non-interactive", "--ignore-missing-imports"] + additional_dependencies: [types-protobuf] + exclude: | + (?x)^( + docs/.*| + firebase_messaging/proto/.*py$ + )$ + diff --git a/firebase_messaging/fcmpushclient.py b/firebase_messaging/fcmpushclient.py index d425ccc..735be95 100644 --- a/firebase_messaging/fcmpushclient.py +++ b/firebase_messaging/fcmpushclient.py @@ -11,7 +11,7 @@ from enum import Enum from ssl import SSLError from threading import Thread -from typing import Any, Callable, List, Optional +from typing import Any, Callable, Dict, List, Optional from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.serialization import load_der_private_key @@ -118,7 +118,7 @@ def __init__( self, *, credentials: Optional[dict] = None, - credentials_updated_callback: Optional[Callable[[str], None]] = None, + credentials_updated_callback: Optional[Callable[[Dict[str, Any]], None]] = None, received_persistent_ids: Optional[List[str]] = None, config: Optional[FcmPushClientConfig] = None, ): @@ -133,8 +133,8 @@ def __init__( self.reader = None self.writer = None self.do_listen = False - self.sequential_error_counters = {} - self.log_warn_counters = {} + self.sequential_error_counters: Dict[ErrorType, int] = {} + self.log_warn_counters: Dict[str, int] = {} # reset variables self.input_stream_id = 0 @@ -146,12 +146,12 @@ def __init__( self.run_state: FcmPushClientRunState = FcmPushClientRunState.CREATED self.tasks = None - self.listen_event_loop = None - self.callback_event_loop = None - self.fcm_thread = None + self.listen_event_loop: Optional[asyncio.AbstractEventLoop] = None + self.callback_event_loop: Optional[asyncio.AbstractEventLoop] = None + self.fcm_thread: Optional[Thread] = None - self.app_id = None - self.sender_id = None + self.app_id: Optional[str] = None + self.sender_id: Optional[int] = None self.reset_lock = None self.stopping_lock = None @@ -789,9 +789,9 @@ def start( callback: Optional[Callable[[dict, str, Optional[Any]], None]], obj: Any = None, *, - listen_event_loop: asyncio.AbstractEventLoop = None, - callback_event_loop: asyncio.AbstractEventLoop = None, - ): + listen_event_loop: Optional[asyncio.AbstractEventLoop] = None, + callback_event_loop: Optional[asyncio.AbstractEventLoop] = None, + ) -> None: """Connect to FCM and start listening for push messages on a seperate service thread. @@ -857,10 +857,10 @@ async def _stop_connection(self): self.fcm_thread = None self.listen_event_loop = None - def is_started(self): + def is_started(self) -> bool: return self.run_state == FcmPushClientRunState.STARTED - def stop(self): + def stop(self) -> None: """Disconnects from FCM and shuts down the service thread.""" if self.fcm_thread: if ( @@ -914,14 +914,15 @@ async def _send_data_message(self, raw_data, persistent_id): dms.data = raw_data # Not supported yet - def send_message(self, raw_data, persistent_id): + def send_message(self, raw_data, persistent_id) -> None: """Not implemented, does nothing atm.""" if self.fcm_thread: asyncio.run_coroutine_threadsafe( - self._send_data_message(raw_data, persistent_id), self.listen_event_loop + self._send_data_message(raw_data, persistent_id), + self.listen_event_loop, # type: ignore[arg-type] ) else: - self.listen_event_loop.create_task( + self.listen_event_loop.create_task( # type: ignore[union-attr] self._send_data_message(raw_data, persistent_id) ) diff --git a/firebase_messaging/gcm.py b/firebase_messaging/gcm.py index 4d803ec..1162696 100644 --- a/firebase_messaging/gcm.py +++ b/firebase_messaging/gcm.py @@ -1,16 +1,17 @@ import logging import time -from typing import Optional +from typing import Optional, Union import requests from google.protobuf.json_format import MessageToDict, MessageToJson from .const import GCM_CHECKIN_URL, GCM_REGISTER_URL, GCM_SERVER_KEY_B64 -from .proto.android_checkin_pb2 import ( # pylint: disable=no-name-in-module +from .proto.android_checkin_pb2 import ( + DEVICE_CHROME_BROWSER, AndroidCheckinProto, ChromeBuildProto, ) -from .proto.checkin_pb2 import ( # pylint: disable=no-name-in-module +from .proto.checkin_pb2 import ( AndroidCheckinRequest, AndroidCheckinResponse, ) @@ -22,12 +23,12 @@ def _get_checkin_payload( android_id: Optional[int] = None, security_token: Optional[int] = None ): chrome = ChromeBuildProto() - chrome.platform = 3 + chrome.platform = ChromeBuildProto.Platform.PLATFORM_LINUX # 3 chrome.chrome_version = "63.0.3234.0" - chrome.channel = 1 + chrome.channel = ChromeBuildProto.Channel.CHANNEL_STABLE # 1 checkin = AndroidCheckinProto() - checkin.type = 3 + checkin.type = DEVICE_CHROME_BROWSER # 3 checkin.chrome_build.CopyFrom(chrome) payload = AndroidCheckinRequest() @@ -131,7 +132,7 @@ def gcm_register(app_id: str, retries=5, log_debug_verbose=False): _logger.debug("GCM Registration request: %s", body) auth = "AidLogin {}:{}".format(chk["androidId"], chk["securityToken"]) - last_error = None + last_error: Optional[Union[str, Exception]] = None for try_num in range(retries): try: resp = requests.post( diff --git a/firebase_messaging/proto/android_checkin_pb2.py b/firebase_messaging/proto/android_checkin_pb2.py index a4cf074..d66c0a6 100644 --- a/firebase_messaging/proto/android_checkin_pb2.py +++ b/firebase_messaging/proto/android_checkin_pb2.py @@ -1,34 +1,34 @@ +# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! -# source: android_checkin.proto +# source: firebase_messaging/proto/android_checkin.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database from google.protobuf.internal import builder as _builder - # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\x15\x61ndroid_checkin.proto\x12\rcheckin_proto"\x8a\x03\n\x10\x43hromeBuildProto\x12:\n\x08platform\x18\x01 \x01(\x0e\x32(.checkin_proto.ChromeBuildProto.Platform\x12\x16\n\x0e\x63hrome_version\x18\x02 \x01(\t\x12\x38\n\x07\x63hannel\x18\x03 \x01(\x0e\x32\'.checkin_proto.ChromeBuildProto.Channel"}\n\x08Platform\x12\x10\n\x0cPLATFORM_WIN\x10\x01\x12\x10\n\x0cPLATFORM_MAC\x10\x02\x12\x12\n\x0ePLATFORM_LINUX\x10\x03\x12\x11\n\rPLATFORM_CROS\x10\x04\x12\x10\n\x0cPLATFORM_IOS\x10\x05\x12\x14\n\x10PLATFORM_ANDROID\x10\x06"i\n\x07\x43hannel\x12\x12\n\x0e\x43HANNEL_STABLE\x10\x01\x12\x10\n\x0c\x43HANNEL_BETA\x10\x02\x12\x0f\n\x0b\x43HANNEL_DEV\x10\x03\x12\x12\n\x0e\x43HANNEL_CANARY\x10\x04\x12\x13\n\x0f\x43HANNEL_UNKNOWN\x10\x05"\xf6\x01\n\x13\x41ndroidCheckinProto\x12\x19\n\x11last_checkin_msec\x18\x02 \x01(\x03\x12\x15\n\rcell_operator\x18\x06 \x01(\t\x12\x14\n\x0csim_operator\x18\x07 \x01(\t\x12\x0f\n\x07roaming\x18\x08 \x01(\t\x12\x13\n\x0buser_number\x18\t \x01(\x05\x12:\n\x04type\x18\x0c \x01(\x0e\x32\x19.checkin_proto.DeviceType:\x11\x44\x45VICE_ANDROID_OS\x12\x35\n\x0c\x63hrome_build\x18\r \x01(\x0b\x32\x1f.checkin_proto.ChromeBuildProto*g\n\nDeviceType\x12\x15\n\x11\x44\x45VICE_ANDROID_OS\x10\x01\x12\x11\n\rDEVICE_IOS_OS\x10\x02\x12\x19\n\x15\x44\x45VICE_CHROME_BROWSER\x10\x03\x12\x14\n\x10\x44\x45VICE_CHROME_OS\x10\x04\x42\x02H\x03' -) + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n.firebase_messaging/proto/android_checkin.proto\x12\rcheckin_proto\"\x8a\x03\n\x10\x43hromeBuildProto\x12:\n\x08platform\x18\x01 \x01(\x0e\x32(.checkin_proto.ChromeBuildProto.Platform\x12\x16\n\x0e\x63hrome_version\x18\x02 \x01(\t\x12\x38\n\x07\x63hannel\x18\x03 \x01(\x0e\x32\'.checkin_proto.ChromeBuildProto.Channel\"}\n\x08Platform\x12\x10\n\x0cPLATFORM_WIN\x10\x01\x12\x10\n\x0cPLATFORM_MAC\x10\x02\x12\x12\n\x0ePLATFORM_LINUX\x10\x03\x12\x11\n\rPLATFORM_CROS\x10\x04\x12\x10\n\x0cPLATFORM_IOS\x10\x05\x12\x14\n\x10PLATFORM_ANDROID\x10\x06\"i\n\x07\x43hannel\x12\x12\n\x0e\x43HANNEL_STABLE\x10\x01\x12\x10\n\x0c\x43HANNEL_BETA\x10\x02\x12\x0f\n\x0b\x43HANNEL_DEV\x10\x03\x12\x12\n\x0e\x43HANNEL_CANARY\x10\x04\x12\x13\n\x0f\x43HANNEL_UNKNOWN\x10\x05\"\xf6\x01\n\x13\x41ndroidCheckinProto\x12\x19\n\x11last_checkin_msec\x18\x02 \x01(\x03\x12\x15\n\rcell_operator\x18\x06 \x01(\t\x12\x14\n\x0csim_operator\x18\x07 \x01(\t\x12\x0f\n\x07roaming\x18\x08 \x01(\t\x12\x13\n\x0buser_number\x18\t \x01(\x05\x12:\n\x04type\x18\x0c \x01(\x0e\x32\x19.checkin_proto.DeviceType:\x11\x44\x45VICE_ANDROID_OS\x12\x35\n\x0c\x63hrome_build\x18\r \x01(\x0b\x32\x1f.checkin_proto.ChromeBuildProto*g\n\nDeviceType\x12\x15\n\x11\x44\x45VICE_ANDROID_OS\x10\x01\x12\x11\n\rDEVICE_IOS_OS\x10\x02\x12\x19\n\x15\x44\x45VICE_CHROME_BROWSER\x10\x03\x12\x14\n\x10\x44\x45VICE_CHROME_OS\x10\x04\x42\x02H\x03') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "android_checkin_pb2", _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'firebase_messaging.proto.android_checkin_pb2', _globals) if _descriptor._USE_C_DESCRIPTORS == False: - _globals["DESCRIPTOR"]._options = None - _globals["DESCRIPTOR"]._serialized_options = b"H\003" - _globals["_DEVICETYPE"]._serialized_start = 686 - _globals["_DEVICETYPE"]._serialized_end = 789 - _globals["_CHROMEBUILDPROTO"]._serialized_start = 41 - _globals["_CHROMEBUILDPROTO"]._serialized_end = 435 - _globals["_CHROMEBUILDPROTO_PLATFORM"]._serialized_start = 203 - _globals["_CHROMEBUILDPROTO_PLATFORM"]._serialized_end = 328 - _globals["_CHROMEBUILDPROTO_CHANNEL"]._serialized_start = 330 - _globals["_CHROMEBUILDPROTO_CHANNEL"]._serialized_end = 435 - _globals["_ANDROIDCHECKINPROTO"]._serialized_start = 438 - _globals["_ANDROIDCHECKINPROTO"]._serialized_end = 684 + _globals['DESCRIPTOR']._options = None + _globals['DESCRIPTOR']._serialized_options = b'H\003' + _globals['_DEVICETYPE']._serialized_start=711 + _globals['_DEVICETYPE']._serialized_end=814 + _globals['_CHROMEBUILDPROTO']._serialized_start=66 + _globals['_CHROMEBUILDPROTO']._serialized_end=460 + _globals['_CHROMEBUILDPROTO_PLATFORM']._serialized_start=228 + _globals['_CHROMEBUILDPROTO_PLATFORM']._serialized_end=353 + _globals['_CHROMEBUILDPROTO_CHANNEL']._serialized_start=355 + _globals['_CHROMEBUILDPROTO_CHANNEL']._serialized_end=460 + _globals['_ANDROIDCHECKINPROTO']._serialized_start=463 + _globals['_ANDROIDCHECKINPROTO']._serialized_end=709 # @@protoc_insertion_point(module_scope) diff --git a/firebase_messaging/proto/android_checkin_pb2.pyi b/firebase_messaging/proto/android_checkin_pb2.pyi new file mode 100644 index 0000000..3823be7 --- /dev/null +++ b/firebase_messaging/proto/android_checkin_pb2.pyi @@ -0,0 +1,187 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +Copyright 2014 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. + +Logging information for Android "checkin" events (automatic, periodic +requests made by Android devices to the server). +""" +import builtins +import google.protobuf.descriptor +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _DeviceType: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _DeviceTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_DeviceType.ValueType], builtins.type): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + DEVICE_ANDROID_OS: _DeviceType.ValueType # 1 + """Android Device""" + DEVICE_IOS_OS: _DeviceType.ValueType # 2 + """Apple IOS device""" + DEVICE_CHROME_BROWSER: _DeviceType.ValueType # 3 + """Chrome browser - Not Chrome OS. No hardware records.""" + DEVICE_CHROME_OS: _DeviceType.ValueType # 4 + """Chrome OS""" + +class DeviceType(_DeviceType, metaclass=_DeviceTypeEnumTypeWrapper): + """enum values correspond to the type of device. + Used in the AndroidCheckinProto and Device proto. + """ + +DEVICE_ANDROID_OS: DeviceType.ValueType # 1 +"""Android Device""" +DEVICE_IOS_OS: DeviceType.ValueType # 2 +"""Apple IOS device""" +DEVICE_CHROME_BROWSER: DeviceType.ValueType # 3 +"""Chrome browser - Not Chrome OS. No hardware records.""" +DEVICE_CHROME_OS: DeviceType.ValueType # 4 +"""Chrome OS""" +global___DeviceType = DeviceType + +@typing_extensions.final +class ChromeBuildProto(google.protobuf.message.Message): + """Build characteristics unique to the Chrome browser, and Chrome OS""" + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + class _Platform: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + + class _PlatformEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[ChromeBuildProto._Platform.ValueType], builtins.type): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PLATFORM_WIN: ChromeBuildProto._Platform.ValueType # 1 + PLATFORM_MAC: ChromeBuildProto._Platform.ValueType # 2 + PLATFORM_LINUX: ChromeBuildProto._Platform.ValueType # 3 + PLATFORM_CROS: ChromeBuildProto._Platform.ValueType # 4 + PLATFORM_IOS: ChromeBuildProto._Platform.ValueType # 5 + PLATFORM_ANDROID: ChromeBuildProto._Platform.ValueType # 6 + """Just a placeholder. Likely don't need it due to the presence of the + Android GCM on phone/tablet devices. + """ + + class Platform(_Platform, metaclass=_PlatformEnumTypeWrapper): ... + PLATFORM_WIN: ChromeBuildProto.Platform.ValueType # 1 + PLATFORM_MAC: ChromeBuildProto.Platform.ValueType # 2 + PLATFORM_LINUX: ChromeBuildProto.Platform.ValueType # 3 + PLATFORM_CROS: ChromeBuildProto.Platform.ValueType # 4 + PLATFORM_IOS: ChromeBuildProto.Platform.ValueType # 5 + PLATFORM_ANDROID: ChromeBuildProto.Platform.ValueType # 6 + """Just a placeholder. Likely don't need it due to the presence of the + Android GCM on phone/tablet devices. + """ + + class _Channel: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + + class _ChannelEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[ChromeBuildProto._Channel.ValueType], builtins.type): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + CHANNEL_STABLE: ChromeBuildProto._Channel.ValueType # 1 + CHANNEL_BETA: ChromeBuildProto._Channel.ValueType # 2 + CHANNEL_DEV: ChromeBuildProto._Channel.ValueType # 3 + CHANNEL_CANARY: ChromeBuildProto._Channel.ValueType # 4 + CHANNEL_UNKNOWN: ChromeBuildProto._Channel.ValueType # 5 + """for tip of tree or custom builds""" + + class Channel(_Channel, metaclass=_ChannelEnumTypeWrapper): ... + CHANNEL_STABLE: ChromeBuildProto.Channel.ValueType # 1 + CHANNEL_BETA: ChromeBuildProto.Channel.ValueType # 2 + CHANNEL_DEV: ChromeBuildProto.Channel.ValueType # 3 + CHANNEL_CANARY: ChromeBuildProto.Channel.ValueType # 4 + CHANNEL_UNKNOWN: ChromeBuildProto.Channel.ValueType # 5 + """for tip of tree or custom builds""" + + PLATFORM_FIELD_NUMBER: builtins.int + CHROME_VERSION_FIELD_NUMBER: builtins.int + CHANNEL_FIELD_NUMBER: builtins.int + platform: global___ChromeBuildProto.Platform.ValueType + """The platform of the device.""" + chrome_version: builtins.str + """The Chrome instance's version.""" + channel: global___ChromeBuildProto.Channel.ValueType + """The Channel (build type) of Chrome.""" + def __init__( + self, + *, + platform: global___ChromeBuildProto.Platform.ValueType | None = ..., + chrome_version: builtins.str | None = ..., + channel: global___ChromeBuildProto.Channel.ValueType | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["channel", b"channel", "chrome_version", b"chrome_version", "platform", b"platform"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["channel", b"channel", "chrome_version", b"chrome_version", "platform", b"platform"]) -> None: ... + +global___ChromeBuildProto = ChromeBuildProto + +@typing_extensions.final +class AndroidCheckinProto(google.protobuf.message.Message): + """Information sent by the device in a "checkin" request.""" + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + LAST_CHECKIN_MSEC_FIELD_NUMBER: builtins.int + CELL_OPERATOR_FIELD_NUMBER: builtins.int + SIM_OPERATOR_FIELD_NUMBER: builtins.int + ROAMING_FIELD_NUMBER: builtins.int + USER_NUMBER_FIELD_NUMBER: builtins.int + TYPE_FIELD_NUMBER: builtins.int + CHROME_BUILD_FIELD_NUMBER: builtins.int + last_checkin_msec: builtins.int + """Miliseconds since the Unix epoch of the device's last successful checkin.""" + cell_operator: builtins.str + """The current MCC+MNC of the mobile device's current cell.""" + sim_operator: builtins.str + """The MCC+MNC of the SIM card (different from operator if the + device is roaming, for instance). + """ + roaming: builtins.str + """The device's current roaming state (reported starting in eclair builds). + Currently one of "{,not}mobile-{,not}roaming", if it is present at all. + """ + user_number: builtins.int + """For devices supporting multiple user profiles (which may be + supported starting in jellybean), the ordinal number of the + profile that is checking in. This is 0 for the primary profile + (which can't be changed without wiping the device), and 1,2,3,... + for additional profiles (which can be added and deleted freely). + """ + type: global___DeviceType.ValueType + """Class of device. Indicates the type of build proto + (IosBuildProto/ChromeBuildProto/AndroidBuildProto) + That is included in this proto + """ + @property + def chrome_build(self) -> global___ChromeBuildProto: + """For devices running MCS on Chrome, build-specific characteristics + of the browser. There are no hardware aspects (except for ChromeOS). + This will only be populated for Chrome builds/ChromeOS devices + """ + def __init__( + self, + *, + last_checkin_msec: builtins.int | None = ..., + cell_operator: builtins.str | None = ..., + sim_operator: builtins.str | None = ..., + roaming: builtins.str | None = ..., + user_number: builtins.int | None = ..., + type: global___DeviceType.ValueType | None = ..., + chrome_build: global___ChromeBuildProto | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["cell_operator", b"cell_operator", "chrome_build", b"chrome_build", "last_checkin_msec", b"last_checkin_msec", "roaming", b"roaming", "sim_operator", b"sim_operator", "type", b"type", "user_number", b"user_number"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["cell_operator", b"cell_operator", "chrome_build", b"chrome_build", "last_checkin_msec", b"last_checkin_msec", "roaming", b"roaming", "sim_operator", b"sim_operator", "type", b"type", "user_number", b"user_number"]) -> None: ... + +global___AndroidCheckinProto = AndroidCheckinProto diff --git a/firebase_messaging/proto/checkin_pb2.pyi b/firebase_messaging/proto/checkin_pb2.pyi new file mode 100644 index 0000000..45879df --- /dev/null +++ b/firebase_messaging/proto/checkin_pb2.pyi @@ -0,0 +1,275 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +Copyright 2014 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. + +Request and reply to the "checkin server" devices poll every few hours. +""" +import android_checkin_pb2 +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.message +import sys + +if sys.version_info >= (3, 8): + import typing as typing_extensions +else: + import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +@typing_extensions.final +class GservicesSetting(google.protobuf.message.Message): + """A concrete name/value pair sent to the device's Gservices database.""" + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + NAME_FIELD_NUMBER: builtins.int + VALUE_FIELD_NUMBER: builtins.int + name: builtins.bytes + value: builtins.bytes + def __init__( + self, + *, + name: builtins.bytes | None = ..., + value: builtins.bytes | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["name", b"name", "value", b"value"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["name", b"name", "value", b"value"]) -> None: ... + +global___GservicesSetting = GservicesSetting + +@typing_extensions.final +class AndroidCheckinRequest(google.protobuf.message.Message): + """Devices send this every few hours to tell us how they're doing.""" + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + IMEI_FIELD_NUMBER: builtins.int + MEID_FIELD_NUMBER: builtins.int + MAC_ADDR_FIELD_NUMBER: builtins.int + MAC_ADDR_TYPE_FIELD_NUMBER: builtins.int + SERIAL_NUMBER_FIELD_NUMBER: builtins.int + ESN_FIELD_NUMBER: builtins.int + ID_FIELD_NUMBER: builtins.int + LOGGING_ID_FIELD_NUMBER: builtins.int + DIGEST_FIELD_NUMBER: builtins.int + LOCALE_FIELD_NUMBER: builtins.int + CHECKIN_FIELD_NUMBER: builtins.int + DESIRED_BUILD_FIELD_NUMBER: builtins.int + MARKET_CHECKIN_FIELD_NUMBER: builtins.int + ACCOUNT_COOKIE_FIELD_NUMBER: builtins.int + TIME_ZONE_FIELD_NUMBER: builtins.int + SECURITY_TOKEN_FIELD_NUMBER: builtins.int + VERSION_FIELD_NUMBER: builtins.int + OTA_CERT_FIELD_NUMBER: builtins.int + FRAGMENT_FIELD_NUMBER: builtins.int + USER_NAME_FIELD_NUMBER: builtins.int + USER_SERIAL_NUMBER_FIELD_NUMBER: builtins.int + imei: builtins.str + """IMEI (used by GSM phones) is sent and stored as 15 decimal + digits; the 15th is a check digit. + IMEI, reported but not logged. + """ + meid: builtins.str + """MEID (used by CDMA phones) is sent and stored as 14 hexadecimal + digits (no check digit). + MEID, reported but not logged. + """ + @property + def mac_addr(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: + """MAC address (used by non-phone devices). 12 hexadecimal digits; + no separators (eg "0016E6513AC2", not "00:16:E6:51:3A:C2"). + MAC address, reported but not logged. + """ + @property + def mac_addr_type(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: + """An array parallel to mac_addr, describing the type of interface. + Currently accepted values: "wifi", "ethernet", "bluetooth". If + not present, "wifi" is assumed. + """ + serial_number: builtins.str + """Serial number (a manufacturer-defined unique hardware + identifier). Alphanumeric, case-insensitive. + """ + esn: builtins.str + """Older CDMA networks use an ESN (8 hex digits) instead of an MEID. + ESN, reported but not logged + """ + id: builtins.int + """Android device ID, not logged""" + logging_id: builtins.int + """Pseudonymous logging ID for Sawmill""" + digest: builtins.str + """Digest of device provisioning, not logged.""" + locale: builtins.str + """Current locale in standard (xx_XX) format""" + @property + def checkin(self) -> android_checkin_pb2.AndroidCheckinProto: ... + desired_build: builtins.str + """DEPRECATED, see AndroidCheckinProto.requested_group""" + market_checkin: builtins.str + """Blob of data from the Market app to be passed to Market API server""" + @property + def account_cookie(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: + """SID cookies of any google accounts stored on the phone. Not logged.""" + time_zone: builtins.str + """Time zone. Not currently logged.""" + security_token: builtins.int + """Security token used to validate the checkin request. + Required for android IDs issued to Froyo+ devices, not for legacy IDs. + """ + version: builtins.int + """Version of checkin protocol. + + There are currently two versions: + + - version field missing: android IDs are assigned based on + hardware identifiers. unsecured in the sense that you can + "unregister" someone's phone by sending a registration request + with their IMEI/MEID/MAC. + + - version=2: android IDs are assigned randomly. The device is + sent a security token that must be included in all future + checkins for that android id. + + - version=3: same as version 2, but the 'fragment' field is + provided, and the device understands incremental updates to the + gservices table (ie, only returning the keys whose values have + changed.) + + (version=1 was skipped to avoid confusion with the "missing" + version field that is effectively version 1.) + """ + @property + def ota_cert(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: + """OTA certs accepted by device (base-64 SHA-1 of cert files). Not + logged. + """ + fragment: builtins.int + """Honeycomb and newer devices send configuration data with their checkin. + optional DeviceConfigurationProto device_configuration = 18; + + A single CheckinTask on the device may lead to multiple checkin + requests if there is too much log data to upload in a single + request. For version 3 and up, this field will be filled in with + the number of the request, starting with 0. + """ + user_name: builtins.str + """For devices supporting multiple users, the name of the current + profile (they all check in independently, just as if they were + multiple physical devices). This may not be set, even if the + device is using multiuser. (checkin.user_number should be set to + the ordinal of the user.) + """ + user_serial_number: builtins.int + """For devices supporting multiple user profiles, the serial number + for the user checking in. Not logged. May not be set, even if + the device supportes multiuser. checkin.user_number is the + ordinal of the user (0, 1, 2, ...), which may be reused if users + are deleted and re-created. user_serial_number is never reused + (unless the device is wiped). + """ + def __init__( + self, + *, + imei: builtins.str | None = ..., + meid: builtins.str | None = ..., + mac_addr: collections.abc.Iterable[builtins.str] | None = ..., + mac_addr_type: collections.abc.Iterable[builtins.str] | None = ..., + serial_number: builtins.str | None = ..., + esn: builtins.str | None = ..., + id: builtins.int | None = ..., + logging_id: builtins.int | None = ..., + digest: builtins.str | None = ..., + locale: builtins.str | None = ..., + checkin: android_checkin_pb2.AndroidCheckinProto | None = ..., + desired_build: builtins.str | None = ..., + market_checkin: builtins.str | None = ..., + account_cookie: collections.abc.Iterable[builtins.str] | None = ..., + time_zone: builtins.str | None = ..., + security_token: builtins.int | None = ..., + version: builtins.int | None = ..., + ota_cert: collections.abc.Iterable[builtins.str] | None = ..., + fragment: builtins.int | None = ..., + user_name: builtins.str | None = ..., + user_serial_number: builtins.int | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["checkin", b"checkin", "desired_build", b"desired_build", "digest", b"digest", "esn", b"esn", "fragment", b"fragment", "id", b"id", "imei", b"imei", "locale", b"locale", "logging_id", b"logging_id", "market_checkin", b"market_checkin", "meid", b"meid", "security_token", b"security_token", "serial_number", b"serial_number", "time_zone", b"time_zone", "user_name", b"user_name", "user_serial_number", b"user_serial_number", "version", b"version"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["account_cookie", b"account_cookie", "checkin", b"checkin", "desired_build", b"desired_build", "digest", b"digest", "esn", b"esn", "fragment", b"fragment", "id", b"id", "imei", b"imei", "locale", b"locale", "logging_id", b"logging_id", "mac_addr", b"mac_addr", "mac_addr_type", b"mac_addr_type", "market_checkin", b"market_checkin", "meid", b"meid", "ota_cert", b"ota_cert", "security_token", b"security_token", "serial_number", b"serial_number", "time_zone", b"time_zone", "user_name", b"user_name", "user_serial_number", b"user_serial_number", "version", b"version"]) -> None: ... + +global___AndroidCheckinRequest = AndroidCheckinRequest + +@typing_extensions.final +class AndroidCheckinResponse(google.protobuf.message.Message): + """The response to the device.""" + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + STATS_OK_FIELD_NUMBER: builtins.int + TIME_MSEC_FIELD_NUMBER: builtins.int + DIGEST_FIELD_NUMBER: builtins.int + SETTINGS_DIFF_FIELD_NUMBER: builtins.int + DELETE_SETTING_FIELD_NUMBER: builtins.int + SETTING_FIELD_NUMBER: builtins.int + MARKET_OK_FIELD_NUMBER: builtins.int + ANDROID_ID_FIELD_NUMBER: builtins.int + SECURITY_TOKEN_FIELD_NUMBER: builtins.int + VERSION_INFO_FIELD_NUMBER: builtins.int + stats_ok: builtins.bool + """Whether statistics were recorded properly.""" + time_msec: builtins.int + """Time of day from server (Java epoch).""" + digest: builtins.str + """repeated AndroidIntentProto intent = 2; + + Provisioning is sent if the request included an obsolete digest. + + For version <= 2, 'digest' contains the digest that should be + sent back to the server on the next checkin, and 'setting' + contains the entire gservices table (which replaces the entire + current table on the device). + + for version >= 3, 'digest' will be absent. If 'settings_diff' + is false, then 'setting' contains the entire table, as in version + 2. If 'settings_diff' is true, then 'delete_setting' contains + the keys to delete, and 'setting' contains only keys to be added + or for which the value has changed. All other keys in the + current table should be left untouched. If 'settings_diff' is + absent, don't touch the existing gservices table. + """ + settings_diff: builtins.bool + @property + def delete_setting(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... + @property + def setting(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___GservicesSetting]: ... + market_ok: builtins.bool + """If Market got the market_checkin data OK.""" + android_id: builtins.int + """From the request, or newly assigned""" + security_token: builtins.int + """The associated security token""" + version_info: builtins.str + """NEXT TAG: 12""" + def __init__( + self, + *, + stats_ok: builtins.bool | None = ..., + time_msec: builtins.int | None = ..., + digest: builtins.str | None = ..., + settings_diff: builtins.bool | None = ..., + delete_setting: collections.abc.Iterable[builtins.str] | None = ..., + setting: collections.abc.Iterable[global___GservicesSetting] | None = ..., + market_ok: builtins.bool | None = ..., + android_id: builtins.int | None = ..., + security_token: builtins.int | None = ..., + version_info: builtins.str | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["android_id", b"android_id", "digest", b"digest", "market_ok", b"market_ok", "security_token", b"security_token", "settings_diff", b"settings_diff", "stats_ok", b"stats_ok", "time_msec", b"time_msec", "version_info", b"version_info"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["android_id", b"android_id", "delete_setting", b"delete_setting", "digest", b"digest", "market_ok", b"market_ok", "security_token", b"security_token", "setting", b"setting", "settings_diff", b"settings_diff", "stats_ok", b"stats_ok", "time_msec", b"time_msec", "version_info", b"version_info"]) -> None: ... + +global___AndroidCheckinResponse = AndroidCheckinResponse diff --git a/firebase_messaging/proto/mcs_pb2.pyi b/firebase_messaging/proto/mcs_pb2.pyi new file mode 100644 index 0000000..d2e2995 --- /dev/null +++ b/firebase_messaging/proto/mcs_pb2.pyi @@ -0,0 +1,700 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +Copyright 2013 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. + +MCS protocol for communication between Chrome client and Mobile Connection +Server . +""" +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +@typing_extensions.final +class HeartbeatPing(google.protobuf.message.Message): + """ + Common fields/comments: + + stream_id: no longer sent by server, each side keeps a counter + last_stream_id_received: sent only if a packet was received since last time + a last_stream was sent + status: new bitmask including the 'idle' as bit 0. + + * + TAG: 0 + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + STREAM_ID_FIELD_NUMBER: builtins.int + LAST_STREAM_ID_RECEIVED_FIELD_NUMBER: builtins.int + STATUS_FIELD_NUMBER: builtins.int + stream_id: builtins.int + last_stream_id_received: builtins.int + status: builtins.int + def __init__( + self, + *, + stream_id: builtins.int | None = ..., + last_stream_id_received: builtins.int | None = ..., + status: builtins.int | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["last_stream_id_received", b"last_stream_id_received", "status", b"status", "stream_id", b"stream_id"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["last_stream_id_received", b"last_stream_id_received", "status", b"status", "stream_id", b"stream_id"]) -> None: ... + +global___HeartbeatPing = HeartbeatPing + +@typing_extensions.final +class HeartbeatAck(google.protobuf.message.Message): + """* + TAG: 1 + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + STREAM_ID_FIELD_NUMBER: builtins.int + LAST_STREAM_ID_RECEIVED_FIELD_NUMBER: builtins.int + STATUS_FIELD_NUMBER: builtins.int + stream_id: builtins.int + last_stream_id_received: builtins.int + status: builtins.int + def __init__( + self, + *, + stream_id: builtins.int | None = ..., + last_stream_id_received: builtins.int | None = ..., + status: builtins.int | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["last_stream_id_received", b"last_stream_id_received", "status", b"status", "stream_id", b"stream_id"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["last_stream_id_received", b"last_stream_id_received", "status", b"status", "stream_id", b"stream_id"]) -> None: ... + +global___HeartbeatAck = HeartbeatAck + +@typing_extensions.final +class ErrorInfo(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + CODE_FIELD_NUMBER: builtins.int + MESSAGE_FIELD_NUMBER: builtins.int + TYPE_FIELD_NUMBER: builtins.int + EXTENSION_FIELD_NUMBER: builtins.int + code: builtins.int + message: builtins.str + type: builtins.str + @property + def extension(self) -> global___Extension: ... + def __init__( + self, + *, + code: builtins.int | None = ..., + message: builtins.str | None = ..., + type: builtins.str | None = ..., + extension: global___Extension | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["code", b"code", "extension", b"extension", "message", b"message", "type", b"type"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["code", b"code", "extension", b"extension", "message", b"message", "type", b"type"]) -> None: ... + +global___ErrorInfo = ErrorInfo + +@typing_extensions.final +class Setting(google.protobuf.message.Message): + """MobileSettings class. + "u:f", "u:b", "u:s" - multi user devices reporting foreground, background + and stopped users. + hbping: heatbeat ping interval + rmq2v: include explicit stream IDs + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + NAME_FIELD_NUMBER: builtins.int + VALUE_FIELD_NUMBER: builtins.int + name: builtins.str + value: builtins.str + def __init__( + self, + *, + name: builtins.str | None = ..., + value: builtins.str | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["name", b"name", "value", b"value"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["name", b"name", "value", b"value"]) -> None: ... + +global___Setting = Setting + +@typing_extensions.final +class HeartbeatStat(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + IP_FIELD_NUMBER: builtins.int + TIMEOUT_FIELD_NUMBER: builtins.int + INTERVAL_MS_FIELD_NUMBER: builtins.int + ip: builtins.str + timeout: builtins.bool + interval_ms: builtins.int + def __init__( + self, + *, + ip: builtins.str | None = ..., + timeout: builtins.bool | None = ..., + interval_ms: builtins.int | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["interval_ms", b"interval_ms", "ip", b"ip", "timeout", b"timeout"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["interval_ms", b"interval_ms", "ip", b"ip", "timeout", b"timeout"]) -> None: ... + +global___HeartbeatStat = HeartbeatStat + +@typing_extensions.final +class HeartbeatConfig(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + UPLOAD_STAT_FIELD_NUMBER: builtins.int + IP_FIELD_NUMBER: builtins.int + INTERVAL_MS_FIELD_NUMBER: builtins.int + upload_stat: builtins.bool + ip: builtins.str + interval_ms: builtins.int + def __init__( + self, + *, + upload_stat: builtins.bool | None = ..., + ip: builtins.str | None = ..., + interval_ms: builtins.int | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["interval_ms", b"interval_ms", "ip", b"ip", "upload_stat", b"upload_stat"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["interval_ms", b"interval_ms", "ip", b"ip", "upload_stat", b"upload_stat"]) -> None: ... + +global___HeartbeatConfig = HeartbeatConfig + +@typing_extensions.final +class ClientEvent(google.protobuf.message.Message): + """ClientEvents are used to inform the server of failed and successful + connections. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + class _Type: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + + class _TypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[ClientEvent._Type.ValueType], builtins.type): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + UNKNOWN: ClientEvent._Type.ValueType # 0 + DISCARDED_EVENTS: ClientEvent._Type.ValueType # 1 + """Count of discarded events if the buffer filled up and was trimmed.""" + FAILED_CONNECTION: ClientEvent._Type.ValueType # 2 + """Failed connection event: the connection failed to be established or we + had a login error. + """ + SUCCESSFUL_CONNECTION: ClientEvent._Type.ValueType # 3 + """Successful connection event: information about the last successful + connection, including the time at which it was established. + """ + + class Type(_Type, metaclass=_TypeEnumTypeWrapper): ... + UNKNOWN: ClientEvent.Type.ValueType # 0 + DISCARDED_EVENTS: ClientEvent.Type.ValueType # 1 + """Count of discarded events if the buffer filled up and was trimmed.""" + FAILED_CONNECTION: ClientEvent.Type.ValueType # 2 + """Failed connection event: the connection failed to be established or we + had a login error. + """ + SUCCESSFUL_CONNECTION: ClientEvent.Type.ValueType # 3 + """Successful connection event: information about the last successful + connection, including the time at which it was established. + """ + + TYPE_FIELD_NUMBER: builtins.int + NUMBER_DISCARDED_EVENTS_FIELD_NUMBER: builtins.int + NETWORK_TYPE_FIELD_NUMBER: builtins.int + TIME_CONNECTION_STARTED_MS_FIELD_NUMBER: builtins.int + TIME_CONNECTION_ENDED_MS_FIELD_NUMBER: builtins.int + ERROR_CODE_FIELD_NUMBER: builtins.int + TIME_CONNECTION_ESTABLISHED_MS_FIELD_NUMBER: builtins.int + type: global___ClientEvent.Type.ValueType + """Common fields [1-99]""" + number_discarded_events: builtins.int + """Fields for DISCARDED_EVENTS messages [100-199]""" + network_type: builtins.int + """Fields for FAILED_CONNECTION and SUCCESSFUL_CONNECTION messages [200-299] + Network type is a value in net::NetworkChangeNotifier::ConnectionType. + """ + time_connection_started_ms: builtins.int + time_connection_ended_ms: builtins.int + error_code: builtins.int + """Error code should be a net::Error value.""" + time_connection_established_ms: builtins.int + """Fields for SUCCESSFUL_CONNECTION messages [300-399]""" + def __init__( + self, + *, + type: global___ClientEvent.Type.ValueType | None = ..., + number_discarded_events: builtins.int | None = ..., + network_type: builtins.int | None = ..., + time_connection_started_ms: builtins.int | None = ..., + time_connection_ended_ms: builtins.int | None = ..., + error_code: builtins.int | None = ..., + time_connection_established_ms: builtins.int | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["error_code", b"error_code", "network_type", b"network_type", "number_discarded_events", b"number_discarded_events", "time_connection_ended_ms", b"time_connection_ended_ms", "time_connection_established_ms", b"time_connection_established_ms", "time_connection_started_ms", b"time_connection_started_ms", "type", b"type"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["error_code", b"error_code", "network_type", b"network_type", "number_discarded_events", b"number_discarded_events", "time_connection_ended_ms", b"time_connection_ended_ms", "time_connection_established_ms", b"time_connection_established_ms", "time_connection_started_ms", b"time_connection_started_ms", "type", b"type"]) -> None: ... + +global___ClientEvent = ClientEvent + +@typing_extensions.final +class LoginRequest(google.protobuf.message.Message): + """* + TAG: 2 + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + class _AuthService: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + + class _AuthServiceEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[LoginRequest._AuthService.ValueType], builtins.type): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + ANDROID_ID: LoginRequest._AuthService.ValueType # 2 + + class AuthService(_AuthService, metaclass=_AuthServiceEnumTypeWrapper): ... + ANDROID_ID: LoginRequest.AuthService.ValueType # 2 + + ID_FIELD_NUMBER: builtins.int + DOMAIN_FIELD_NUMBER: builtins.int + USER_FIELD_NUMBER: builtins.int + RESOURCE_FIELD_NUMBER: builtins.int + AUTH_TOKEN_FIELD_NUMBER: builtins.int + DEVICE_ID_FIELD_NUMBER: builtins.int + LAST_RMQ_ID_FIELD_NUMBER: builtins.int + SETTING_FIELD_NUMBER: builtins.int + RECEIVED_PERSISTENT_ID_FIELD_NUMBER: builtins.int + ADAPTIVE_HEARTBEAT_FIELD_NUMBER: builtins.int + HEARTBEAT_STAT_FIELD_NUMBER: builtins.int + USE_RMQ2_FIELD_NUMBER: builtins.int + ACCOUNT_ID_FIELD_NUMBER: builtins.int + AUTH_SERVICE_FIELD_NUMBER: builtins.int + NETWORK_TYPE_FIELD_NUMBER: builtins.int + STATUS_FIELD_NUMBER: builtins.int + CLIENT_EVENT_FIELD_NUMBER: builtins.int + id: builtins.str + """Must be present ( proto required ), may be empty""" + domain: builtins.str + """string. + mcs.android.com. + """ + user: builtins.str + """Decimal android ID""" + resource: builtins.str + auth_token: builtins.str + """Secret""" + device_id: builtins.str + """Format is: android-HEX_DEVICE_ID + The user is the decimal value. + """ + last_rmq_id: builtins.int + """RMQ1 - no longer used""" + @property + def setting(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Setting]: ... + @property + def received_persistent_id(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: + """optional int32 compress = 9;""" + adaptive_heartbeat: builtins.bool + """Replaced by "rmq2v" setting + optional bool include_stream_ids = 11; + """ + @property + def heartbeat_stat(self) -> global___HeartbeatStat: ... + use_rmq2: builtins.bool + """Must be true.""" + account_id: builtins.int + auth_service: global___LoginRequest.AuthService.ValueType + """ANDROID_ID = 2""" + network_type: builtins.int + status: builtins.int + @property + def client_event(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___ClientEvent]: + """Events recorded on the client after the last successful connection.""" + def __init__( + self, + *, + id: builtins.str | None = ..., + domain: builtins.str | None = ..., + user: builtins.str | None = ..., + resource: builtins.str | None = ..., + auth_token: builtins.str | None = ..., + device_id: builtins.str | None = ..., + last_rmq_id: builtins.int | None = ..., + setting: collections.abc.Iterable[global___Setting] | None = ..., + received_persistent_id: collections.abc.Iterable[builtins.str] | None = ..., + adaptive_heartbeat: builtins.bool | None = ..., + heartbeat_stat: global___HeartbeatStat | None = ..., + use_rmq2: builtins.bool | None = ..., + account_id: builtins.int | None = ..., + auth_service: global___LoginRequest.AuthService.ValueType | None = ..., + network_type: builtins.int | None = ..., + status: builtins.int | None = ..., + client_event: collections.abc.Iterable[global___ClientEvent] | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["account_id", b"account_id", "adaptive_heartbeat", b"adaptive_heartbeat", "auth_service", b"auth_service", "auth_token", b"auth_token", "device_id", b"device_id", "domain", b"domain", "heartbeat_stat", b"heartbeat_stat", "id", b"id", "last_rmq_id", b"last_rmq_id", "network_type", b"network_type", "resource", b"resource", "status", b"status", "use_rmq2", b"use_rmq2", "user", b"user"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["account_id", b"account_id", "adaptive_heartbeat", b"adaptive_heartbeat", "auth_service", b"auth_service", "auth_token", b"auth_token", "client_event", b"client_event", "device_id", b"device_id", "domain", b"domain", "heartbeat_stat", b"heartbeat_stat", "id", b"id", "last_rmq_id", b"last_rmq_id", "network_type", b"network_type", "received_persistent_id", b"received_persistent_id", "resource", b"resource", "setting", b"setting", "status", b"status", "use_rmq2", b"use_rmq2", "user", b"user"]) -> None: ... + +global___LoginRequest = LoginRequest + +@typing_extensions.final +class LoginResponse(google.protobuf.message.Message): + """* + TAG: 3 + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + ID_FIELD_NUMBER: builtins.int + JID_FIELD_NUMBER: builtins.int + ERROR_FIELD_NUMBER: builtins.int + SETTING_FIELD_NUMBER: builtins.int + STREAM_ID_FIELD_NUMBER: builtins.int + LAST_STREAM_ID_RECEIVED_FIELD_NUMBER: builtins.int + HEARTBEAT_CONFIG_FIELD_NUMBER: builtins.int + SERVER_TIMESTAMP_FIELD_NUMBER: builtins.int + id: builtins.str + jid: builtins.str + """Not used.""" + @property + def error(self) -> global___ErrorInfo: + """Null if login was ok.""" + @property + def setting(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Setting]: ... + stream_id: builtins.int + last_stream_id_received: builtins.int + """Should be "1" """ + @property + def heartbeat_config(self) -> global___HeartbeatConfig: ... + server_timestamp: builtins.int + """used by the client to synchronize with the server timestamp.""" + def __init__( + self, + *, + id: builtins.str | None = ..., + jid: builtins.str | None = ..., + error: global___ErrorInfo | None = ..., + setting: collections.abc.Iterable[global___Setting] | None = ..., + stream_id: builtins.int | None = ..., + last_stream_id_received: builtins.int | None = ..., + heartbeat_config: global___HeartbeatConfig | None = ..., + server_timestamp: builtins.int | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["error", b"error", "heartbeat_config", b"heartbeat_config", "id", b"id", "jid", b"jid", "last_stream_id_received", b"last_stream_id_received", "server_timestamp", b"server_timestamp", "stream_id", b"stream_id"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["error", b"error", "heartbeat_config", b"heartbeat_config", "id", b"id", "jid", b"jid", "last_stream_id_received", b"last_stream_id_received", "server_timestamp", b"server_timestamp", "setting", b"setting", "stream_id", b"stream_id"]) -> None: ... + +global___LoginResponse = LoginResponse + +@typing_extensions.final +class StreamErrorStanza(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + TYPE_FIELD_NUMBER: builtins.int + TEXT_FIELD_NUMBER: builtins.int + type: builtins.str + text: builtins.str + def __init__( + self, + *, + type: builtins.str | None = ..., + text: builtins.str | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["text", b"text", "type", b"type"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["text", b"text", "type", b"type"]) -> None: ... + +global___StreamErrorStanza = StreamErrorStanza + +@typing_extensions.final +class Close(google.protobuf.message.Message): + """* + TAG: 4 + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__( + self, + ) -> None: ... + +global___Close = Close + +@typing_extensions.final +class Extension(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + ID_FIELD_NUMBER: builtins.int + DATA_FIELD_NUMBER: builtins.int + id: builtins.int + """12: SelectiveAck + 13: StreamAck + """ + data: builtins.bytes + def __init__( + self, + *, + id: builtins.int | None = ..., + data: builtins.bytes | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["data", b"data", "id", b"id"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["data", b"data", "id", b"id"]) -> None: ... + +global___Extension = Extension + +@typing_extensions.final +class IqStanza(google.protobuf.message.Message): + """* + TAG: 7 + IqRequest must contain a single extension. IqResponse may contain 0 or 1 + extensions. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + class _IqType: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + + class _IqTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[IqStanza._IqType.ValueType], builtins.type): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + GET: IqStanza._IqType.ValueType # 0 + SET: IqStanza._IqType.ValueType # 1 + RESULT: IqStanza._IqType.ValueType # 2 + IQ_ERROR: IqStanza._IqType.ValueType # 3 + + class IqType(_IqType, metaclass=_IqTypeEnumTypeWrapper): ... + GET: IqStanza.IqType.ValueType # 0 + SET: IqStanza.IqType.ValueType # 1 + RESULT: IqStanza.IqType.ValueType # 2 + IQ_ERROR: IqStanza.IqType.ValueType # 3 + + RMQ_ID_FIELD_NUMBER: builtins.int + TYPE_FIELD_NUMBER: builtins.int + ID_FIELD_NUMBER: builtins.int + FROM_FIELD_NUMBER: builtins.int + TO_FIELD_NUMBER: builtins.int + ERROR_FIELD_NUMBER: builtins.int + EXTENSION_FIELD_NUMBER: builtins.int + PERSISTENT_ID_FIELD_NUMBER: builtins.int + STREAM_ID_FIELD_NUMBER: builtins.int + LAST_STREAM_ID_RECEIVED_FIELD_NUMBER: builtins.int + ACCOUNT_ID_FIELD_NUMBER: builtins.int + STATUS_FIELD_NUMBER: builtins.int + rmq_id: builtins.int + type: global___IqStanza.IqType.ValueType + id: builtins.str + to: builtins.str + @property + def error(self) -> global___ErrorInfo: ... + @property + def extension(self) -> global___Extension: + """Only field used in the 38+ protocol (besides common last_stream_id_received, status, rmq_id)""" + persistent_id: builtins.str + stream_id: builtins.int + last_stream_id_received: builtins.int + account_id: builtins.int + status: builtins.int + def __init__( + self, + *, + rmq_id: builtins.int | None = ..., + type: global___IqStanza.IqType.ValueType | None = ..., + id: builtins.str | None = ..., + to: builtins.str | None = ..., + error: global___ErrorInfo | None = ..., + extension: global___Extension | None = ..., + persistent_id: builtins.str | None = ..., + stream_id: builtins.int | None = ..., + last_stream_id_received: builtins.int | None = ..., + account_id: builtins.int | None = ..., + status: builtins.int | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["account_id", b"account_id", "error", b"error", "extension", b"extension", "from", b"from", "id", b"id", "last_stream_id_received", b"last_stream_id_received", "persistent_id", b"persistent_id", "rmq_id", b"rmq_id", "status", b"status", "stream_id", b"stream_id", "to", b"to", "type", b"type"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["account_id", b"account_id", "error", b"error", "extension", b"extension", "from", b"from", "id", b"id", "last_stream_id_received", b"last_stream_id_received", "persistent_id", b"persistent_id", "rmq_id", b"rmq_id", "status", b"status", "stream_id", b"stream_id", "to", b"to", "type", b"type"]) -> None: ... + +global___IqStanza = IqStanza + +@typing_extensions.final +class AppData(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + KEY_FIELD_NUMBER: builtins.int + VALUE_FIELD_NUMBER: builtins.int + key: builtins.str + value: builtins.str + def __init__( + self, + *, + key: builtins.str | None = ..., + value: builtins.str | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"]) -> None: ... + +global___AppData = AppData + +@typing_extensions.final +class DataMessageStanza(google.protobuf.message.Message): + """* + TAG: 8 + Not used. + optional int64 rmq_id = 1; + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + ID_FIELD_NUMBER: builtins.int + FROM_FIELD_NUMBER: builtins.int + TO_FIELD_NUMBER: builtins.int + CATEGORY_FIELD_NUMBER: builtins.int + TOKEN_FIELD_NUMBER: builtins.int + APP_DATA_FIELD_NUMBER: builtins.int + FROM_TRUSTED_SERVER_FIELD_NUMBER: builtins.int + PERSISTENT_ID_FIELD_NUMBER: builtins.int + STREAM_ID_FIELD_NUMBER: builtins.int + LAST_STREAM_ID_RECEIVED_FIELD_NUMBER: builtins.int + REG_ID_FIELD_NUMBER: builtins.int + DEVICE_USER_ID_FIELD_NUMBER: builtins.int + TTL_FIELD_NUMBER: builtins.int + SENT_FIELD_NUMBER: builtins.int + QUEUED_FIELD_NUMBER: builtins.int + STATUS_FIELD_NUMBER: builtins.int + RAW_DATA_FIELD_NUMBER: builtins.int + IMMEDIATE_ACK_FIELD_NUMBER: builtins.int + id: builtins.str + """This is the message ID, set by client, DMP.9 (message_id)""" + to: builtins.str + """Part of DMRequest - also the key in DataMessageProto.""" + category: builtins.str + """Package name. DMP.2""" + token: builtins.str + """The collapsed key, DMP.3""" + @property + def app_data(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___AppData]: + """User data + GOOGLE. prefixed special entries, DMP.4""" + from_trusted_server: builtins.bool + """Not used.""" + persistent_id: builtins.str + """Part of the ACK protocol, returned in DataMessageResponse on server side. + It's part of the key of DMP. + """ + stream_id: builtins.int + """In-stream ack. Increments on each message sent - a bit redundant + Not used in DMP/DMR. + """ + last_stream_id_received: builtins.int + reg_id: builtins.str + """Not used. + optional string permission = 12; + + Sent by the device shortly after registration. + """ + device_user_id: builtins.int + """Not used. + optional string pkg_signature = 14; + Not used. + optional string client_id = 15; + + serial number of the target user, DMP.8 + It is the 'serial number' according to user manager. + """ + ttl: builtins.int + """Time to live, in seconds.""" + sent: builtins.int + """Timestamp ( according to client ) when message was sent by app, in seconds""" + queued: builtins.int + """How long has the message been queued before the flush, in seconds. + This is needed to account for the time difference between server and + client: server should adjust 'sent' based on its 'receive' time. + """ + status: builtins.int + raw_data: builtins.bytes + """Optional field containing the binary payload of the message.""" + immediate_ack: builtins.bool + """Not used. + How long the message was delayed before it was sent, in seconds. + optional int32 actual_delay = 23; + + If set the server requests immediate ack. Used for important messages and + for testing. + """ + def __init__( + self, + *, + id: builtins.str | None = ..., + to: builtins.str | None = ..., + category: builtins.str | None = ..., + token: builtins.str | None = ..., + app_data: collections.abc.Iterable[global___AppData] | None = ..., + from_trusted_server: builtins.bool | None = ..., + persistent_id: builtins.str | None = ..., + stream_id: builtins.int | None = ..., + last_stream_id_received: builtins.int | None = ..., + reg_id: builtins.str | None = ..., + device_user_id: builtins.int | None = ..., + ttl: builtins.int | None = ..., + sent: builtins.int | None = ..., + queued: builtins.int | None = ..., + status: builtins.int | None = ..., + raw_data: builtins.bytes | None = ..., + immediate_ack: builtins.bool | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["category", b"category", "device_user_id", b"device_user_id", "from", b"from", "from_trusted_server", b"from_trusted_server", "id", b"id", "immediate_ack", b"immediate_ack", "last_stream_id_received", b"last_stream_id_received", "persistent_id", b"persistent_id", "queued", b"queued", "raw_data", b"raw_data", "reg_id", b"reg_id", "sent", b"sent", "status", b"status", "stream_id", b"stream_id", "to", b"to", "token", b"token", "ttl", b"ttl"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["app_data", b"app_data", "category", b"category", "device_user_id", b"device_user_id", "from", b"from", "from_trusted_server", b"from_trusted_server", "id", b"id", "immediate_ack", b"immediate_ack", "last_stream_id_received", b"last_stream_id_received", "persistent_id", b"persistent_id", "queued", b"queued", "raw_data", b"raw_data", "reg_id", b"reg_id", "sent", b"sent", "status", b"status", "stream_id", b"stream_id", "to", b"to", "token", b"token", "ttl", b"ttl"]) -> None: ... + +global___DataMessageStanza = DataMessageStanza + +@typing_extensions.final +class StreamAck(google.protobuf.message.Message): + """* + Included in IQ with ID 13, sent from client or server after 10 unconfirmed + messages. + No last_streamid_received required. This is included within an IqStanza, + which includes the last_stream_id_received. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__( + self, + ) -> None: ... + +global___StreamAck = StreamAck + +@typing_extensions.final +class SelectiveAck(google.protobuf.message.Message): + """* + Included in IQ sent after LoginResponse from server with ID 12. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + ID_FIELD_NUMBER: builtins.int + @property + def id(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... + def __init__( + self, + *, + id: collections.abc.Iterable[builtins.str] | None = ..., + ) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["id", b"id"]) -> None: ... + +global___SelectiveAck = SelectiveAck diff --git a/firebase_messaging/py.typed b/firebase_messaging/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/poetry.lock b/poetry.lock index e5b843e..97c21a9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -11,20 +11,6 @@ files = [ {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, ] -[[package]] -name = "astroid" -version = "3.0.1" -description = "An abstract syntax tree for Python with inference support." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "astroid-3.0.1-py3-none-any.whl", hash = "sha256:7d5895c9825e18079c5aeac0572bc2e4c83205c95d416e0b4fee8bc361d2d9ca"}, - {file = "astroid-3.0.1.tar.gz", hash = "sha256:86b0bb7d7da0be1a7c4aedb7974e391b32d4ed89e33de6ed6902b4b15c97577e"}, -] - -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} - [[package]] name = "async-timeout" version = "4.0.3" @@ -54,48 +40,6 @@ setuptools = {version = "*", markers = "python_version >= \"3.12\""} [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] -[[package]] -name = "black" -version = "23.10.1" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-23.10.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:ec3f8e6234c4e46ff9e16d9ae96f4ef69fa328bb4ad08198c8cee45bb1f08c69"}, - {file = "black-23.10.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:1b917a2aa020ca600483a7b340c165970b26e9029067f019e3755b56e8dd5916"}, - {file = "black-23.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c74de4c77b849e6359c6f01987e94873c707098322b91490d24296f66d067dc"}, - {file = "black-23.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:7b4d10b0f016616a0d93d24a448100adf1699712fb7a4efd0e2c32bbb219b173"}, - {file = "black-23.10.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b15b75fc53a2fbcac8a87d3e20f69874d161beef13954747e053bca7a1ce53a0"}, - {file = "black-23.10.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:e293e4c2f4a992b980032bbd62df07c1bcff82d6964d6c9496f2cd726e246ace"}, - {file = "black-23.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d56124b7a61d092cb52cce34182a5280e160e6aff3137172a68c2c2c4b76bcb"}, - {file = "black-23.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:3f157a8945a7b2d424da3335f7ace89c14a3b0625e6593d21139c2d8214d55ce"}, - {file = "black-23.10.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:cfcce6f0a384d0da692119f2d72d79ed07c7159879d0bb1bb32d2e443382bf3a"}, - {file = "black-23.10.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:33d40f5b06be80c1bbce17b173cda17994fbad096ce60eb22054da021bf933d1"}, - {file = "black-23.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840015166dbdfbc47992871325799fd2dc0dcf9395e401ada6d88fe11498abad"}, - {file = "black-23.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:037e9b4664cafda5f025a1728c50a9e9aedb99a759c89f760bd83730e76ba884"}, - {file = "black-23.10.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:7cb5936e686e782fddb1c73f8aa6f459e1ad38a6a7b0e54b403f1f05a1507ee9"}, - {file = "black-23.10.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:7670242e90dc129c539e9ca17665e39a146a761e681805c54fbd86015c7c84f7"}, - {file = "black-23.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed45ac9a613fb52dad3b61c8dea2ec9510bf3108d4db88422bacc7d1ba1243d"}, - {file = "black-23.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:6d23d7822140e3fef190734216cefb262521789367fbdc0b3f22af6744058982"}, - {file = "black-23.10.1-py3-none-any.whl", hash = "sha256:d431e6739f727bb2e0495df64a6c7a5310758e87505f5f8cde9ff6c0f2d7e4fe"}, - {file = "black-23.10.1.tar.gz", hash = "sha256:1f8ce316753428ff68749c65a5f7844631aa18c8679dfd3ca9dc1a289979c258"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "cachetools" version = "5.3.2" @@ -303,20 +247,6 @@ files = [ {file = "charset_normalizer-3.3.1-py3-none-any.whl", hash = "sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708"}, ] -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - [[package]] name = "colorama" version = "0.4.6" @@ -440,20 +370,6 @@ ssh = ["bcrypt (>=3.1.5)"] test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] -[[package]] -name = "dill" -version = "0.3.7" -description = "serialize all of Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"}, - {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"}, -] - -[package.extras] -graph = ["objgraph (>=1.7.2)"] - [[package]] name = "distlib" version = "0.3.7" @@ -506,22 +422,6 @@ docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1 testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] typing = ["typing-extensions (>=4.7.1)"] -[[package]] -name = "flake8" -version = "5.0.4" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, - {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.9.0,<2.10.0" -pyflakes = ">=2.5.0,<2.6.0" - [[package]] name = "http-ece" version = "1.1.0" @@ -601,23 +501,6 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "isort" -version = "5.12.0" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, -] - -[package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - [[package]] name = "jinja2" version = "3.1.2" @@ -705,26 +588,19 @@ files = [ ] [[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" +name = "mypy-protobuf" +version = "3.5.0" +description = "Generate mypy stub files from protobuf specs" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, + {file = "mypy-protobuf-3.5.0.tar.gz", hash = "sha256:21f270da0a9792a9dac76b0df463c027e561664ab6973c59be4e4d064dfe67dc"}, + {file = "mypy_protobuf-3.5.0-py3-none-any.whl", hash = "sha256:0d0548c6b9a6faf14ce1a9ce2831c403a5c1f2a9363e85b1e2c51d5d57aa8393"}, ] -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] +[package.dependencies] +protobuf = ">=4.23.4" +types-protobuf = ">=4.23.0.2" [[package]] name = "nodeenv" @@ -751,17 +627,6 @@ files = [ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] -[[package]] -name = "pathspec" -version = "0.11.2" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, -] - [[package]] name = "platformdirs" version = "3.11.0" @@ -832,17 +697,6 @@ files = [ {file = "protobuf-4.24.3.tar.gz", hash = "sha256:12e9ad2ec079b833176d2921be2cb24281fa591f0b119b208b788adc48c2561d"}, ] -[[package]] -name = "pycodestyle" -version = "2.9.1" -description = "Python style guide checker" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, - {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, -] - [[package]] name = "pycparser" version = "2.21" @@ -854,17 +708,6 @@ files = [ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] -[[package]] -name = "pyflakes" -version = "2.5.0" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, - {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, -] - [[package]] name = "pygments" version = "2.16.1" @@ -879,36 +722,6 @@ files = [ [package.extras] plugins = ["importlib-metadata"] -[[package]] -name = "pylint" -version = "3.0.2" -description = "python code static checker" -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "pylint-3.0.2-py3-none-any.whl", hash = "sha256:60ed5f3a9ff8b61839ff0348b3624ceeb9e6c2a92c514d81c9cc273da3b6bcda"}, - {file = "pylint-3.0.2.tar.gz", hash = "sha256:0d4c286ef6d2f66c8bfb527a7f8a629009e42c99707dec821a03e1b51a4c1496"}, -] - -[package.dependencies] -astroid = ">=3.0.1,<=3.1.0-dev0" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = [ - {version = ">=0.2", markers = "python_version < \"3.11\""}, - {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, -] -isort = ">=4.2.5,<6" -mccabe = ">=0.6,<0.8" -platformdirs = ">=2.2.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -tomlkit = ">=0.10.1" -typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} - -[package.extras] -spelling = ["pyenchant (>=3.2,<4.0)"] -testutils = ["gitpython (>3)"] - [[package]] name = "pyproject-api" version = "1.6.1" @@ -1338,17 +1151,6 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -[[package]] -name = "tomlkit" -version = "0.12.1" -description = "Style preserving TOML library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"}, - {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, -] - [[package]] name = "tox" version = "4.11.3" @@ -1377,14 +1179,14 @@ docs = ["furo (>=2023.8.19)", "sphinx (>=7.2.4)", "sphinx-argparse-cli (>=1.11.1 testing = ["build[virtualenv] (>=0.10)", "covdefaults (>=2.3)", "detect-test-pollution (>=1.1.1)", "devpi-process (>=1)", "diff-cover (>=7.7)", "distlib (>=0.3.7)", "flaky (>=3.7)", "hatch-vcs (>=0.3)", "hatchling (>=1.18)", "psutil (>=5.9.5)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-xdist (>=3.3.1)", "re-assert (>=1.1)", "time-machine (>=2.12)", "wheel (>=0.41.2)"] [[package]] -name = "typing-extensions" -version = "4.8.0" -description = "Backported and Experimental Type Hints for Python 3.8+" +name = "types-protobuf" +version = "4.24.0.20240311" +description = "Typing stubs for protobuf" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, + {file = "types-protobuf-4.24.0.20240311.tar.gz", hash = "sha256:c80426f9fb9b21aee514691e96ab32a5cd694a82e2ac07964b352c3e7e0182bc"}, + {file = "types_protobuf-4.24.0.20240311-py3-none-any.whl", hash = "sha256:8e039486df058141cb221ab99f88c5878c08cca4376db1d84f63279860aa09cd"}, ] [[package]] @@ -1445,4 +1247,4 @@ docs = ["sphinx", "sphinx-autodoc-typehints", "sphinx-rtd-theme"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "95fd53845413d360006e3300ece5a0279e3166ecd60009c4ca1d5f4d9c97a342" +content-hash = "deb646aa3cc11606127d064f6592574c262033925ea9c48cec4c38089ed54cec" diff --git a/pyproject.toml b/pyproject.toml index 7723796..683bb09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,18 +43,15 @@ sphinx-autodoc-typehints = {version = "^1.24.0", optional = true} docs = ["sphinx", "sphinx-rtd-theme", "sphinx-autodoc-typehints"] [tool.poetry.group.dev.dependencies] -flake8 = "*" pre-commit = "*" tox = "*" -black = "*" -pylint = "*" -isort = "*" pytest = "*" pytest-mock = "*" requests-mock = "*" pytest-asyncio = "*" pytest-cov = "*" async-timeout = ">=3.0.0" +mypy-protobuf = "^3.5.0" [tool.pytest.ini_options] testpaths = "tests" @@ -67,20 +64,6 @@ omit = [ "firebase_messaging/decrypt.py*" ] -[tool.isort] -profile = "black" -known_first_party = "firebase_messaging" -known_third_party = ["asyncclick", "setuptools"] - -[tool.pylint] -disable = ["missing-module-docstring", "missing-function-docstring", -"missing-class-docstring", -"broad-exception-caught", -"consider-using-f-string", -] -overgeneral-exceptions = ["builtins.Exception"] -ignore-paths = ["firebase_messaging/proto", "firebase_messaging/decrypt.py", "tests"] - [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" From d83d0ffc15ecea6395a0296173b840271d28afe4 Mon Sep 17 00:00:00 2001 From: sdb9696 Date: Tue, 19 Mar 2024 09:29:19 +0000 Subject: [PATCH 3/5] Bump version to 0.2.1 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 683bb09..5b01a0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "firebase-messaging" -version = "0.2.0" +version = "0.2.1" description = "FCM/GCM push notification client" authors = ["sdb9696 "] license = "MIT" From 1bf36259cd508bf6a58dc9f16138294aef235068 Mon Sep 17 00:00:00 2001 From: sdb9696 Date: Tue, 19 Mar 2024 09:33:22 +0000 Subject: [PATCH 4/5] Fix broken proto file --- .../proto/android_checkin_pb2.py | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/firebase_messaging/proto/android_checkin_pb2.py b/firebase_messaging/proto/android_checkin_pb2.py index d66c0a6..6e59426 100644 --- a/firebase_messaging/proto/android_checkin_pb2.py +++ b/firebase_messaging/proto/android_checkin_pb2.py @@ -1,34 +1,35 @@ # -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! -# source: firebase_messaging/proto/android_checkin.proto +# source: android_checkin.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database from google.protobuf.internal import builder as _builder + # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n.firebase_messaging/proto/android_checkin.proto\x12\rcheckin_proto\"\x8a\x03\n\x10\x43hromeBuildProto\x12:\n\x08platform\x18\x01 \x01(\x0e\x32(.checkin_proto.ChromeBuildProto.Platform\x12\x16\n\x0e\x63hrome_version\x18\x02 \x01(\t\x12\x38\n\x07\x63hannel\x18\x03 \x01(\x0e\x32\'.checkin_proto.ChromeBuildProto.Channel\"}\n\x08Platform\x12\x10\n\x0cPLATFORM_WIN\x10\x01\x12\x10\n\x0cPLATFORM_MAC\x10\x02\x12\x12\n\x0ePLATFORM_LINUX\x10\x03\x12\x11\n\rPLATFORM_CROS\x10\x04\x12\x10\n\x0cPLATFORM_IOS\x10\x05\x12\x14\n\x10PLATFORM_ANDROID\x10\x06\"i\n\x07\x43hannel\x12\x12\n\x0e\x43HANNEL_STABLE\x10\x01\x12\x10\n\x0c\x43HANNEL_BETA\x10\x02\x12\x0f\n\x0b\x43HANNEL_DEV\x10\x03\x12\x12\n\x0e\x43HANNEL_CANARY\x10\x04\x12\x13\n\x0f\x43HANNEL_UNKNOWN\x10\x05\"\xf6\x01\n\x13\x41ndroidCheckinProto\x12\x19\n\x11last_checkin_msec\x18\x02 \x01(\x03\x12\x15\n\rcell_operator\x18\x06 \x01(\t\x12\x14\n\x0csim_operator\x18\x07 \x01(\t\x12\x0f\n\x07roaming\x18\x08 \x01(\t\x12\x13\n\x0buser_number\x18\t \x01(\x05\x12:\n\x04type\x18\x0c \x01(\x0e\x32\x19.checkin_proto.DeviceType:\x11\x44\x45VICE_ANDROID_OS\x12\x35\n\x0c\x63hrome_build\x18\r \x01(\x0b\x32\x1f.checkin_proto.ChromeBuildProto*g\n\nDeviceType\x12\x15\n\x11\x44\x45VICE_ANDROID_OS\x10\x01\x12\x11\n\rDEVICE_IOS_OS\x10\x02\x12\x19\n\x15\x44\x45VICE_CHROME_BROWSER\x10\x03\x12\x14\n\x10\x44\x45VICE_CHROME_OS\x10\x04\x42\x02H\x03') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x15\x61ndroid_checkin.proto\x12\rcheckin_proto"\x8a\x03\n\x10\x43hromeBuildProto\x12:\n\x08platform\x18\x01 \x01(\x0e\x32(.checkin_proto.ChromeBuildProto.Platform\x12\x16\n\x0e\x63hrome_version\x18\x02 \x01(\t\x12\x38\n\x07\x63hannel\x18\x03 \x01(\x0e\x32\'.checkin_proto.ChromeBuildProto.Channel"}\n\x08Platform\x12\x10\n\x0cPLATFORM_WIN\x10\x01\x12\x10\n\x0cPLATFORM_MAC\x10\x02\x12\x12\n\x0ePLATFORM_LINUX\x10\x03\x12\x11\n\rPLATFORM_CROS\x10\x04\x12\x10\n\x0cPLATFORM_IOS\x10\x05\x12\x14\n\x10PLATFORM_ANDROID\x10\x06"i\n\x07\x43hannel\x12\x12\n\x0e\x43HANNEL_STABLE\x10\x01\x12\x10\n\x0c\x43HANNEL_BETA\x10\x02\x12\x0f\n\x0b\x43HANNEL_DEV\x10\x03\x12\x12\n\x0e\x43HANNEL_CANARY\x10\x04\x12\x13\n\x0f\x43HANNEL_UNKNOWN\x10\x05"\xf6\x01\n\x13\x41ndroidCheckinProto\x12\x19\n\x11last_checkin_msec\x18\x02 \x01(\x03\x12\x15\n\rcell_operator\x18\x06 \x01(\t\x12\x14\n\x0csim_operator\x18\x07 \x01(\t\x12\x0f\n\x07roaming\x18\x08 \x01(\t\x12\x13\n\x0buser_number\x18\t \x01(\x05\x12:\n\x04type\x18\x0c \x01(\x0e\x32\x19.checkin_proto.DeviceType:\x11\x44\x45VICE_ANDROID_OS\x12\x35\n\x0c\x63hrome_build\x18\r \x01(\x0b\x32\x1f.checkin_proto.ChromeBuildProto*g\n\nDeviceType\x12\x15\n\x11\x44\x45VICE_ANDROID_OS\x10\x01\x12\x11\n\rDEVICE_IOS_OS\x10\x02\x12\x19\n\x15\x44\x45VICE_CHROME_BROWSER\x10\x03\x12\x14\n\x10\x44\x45VICE_CHROME_OS\x10\x04\x42\x02H\x03' +) _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'firebase_messaging.proto.android_checkin_pb2', _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "android_checkin_pb2", _globals) if _descriptor._USE_C_DESCRIPTORS == False: - _globals['DESCRIPTOR']._options = None - _globals['DESCRIPTOR']._serialized_options = b'H\003' - _globals['_DEVICETYPE']._serialized_start=711 - _globals['_DEVICETYPE']._serialized_end=814 - _globals['_CHROMEBUILDPROTO']._serialized_start=66 - _globals['_CHROMEBUILDPROTO']._serialized_end=460 - _globals['_CHROMEBUILDPROTO_PLATFORM']._serialized_start=228 - _globals['_CHROMEBUILDPROTO_PLATFORM']._serialized_end=353 - _globals['_CHROMEBUILDPROTO_CHANNEL']._serialized_start=355 - _globals['_CHROMEBUILDPROTO_CHANNEL']._serialized_end=460 - _globals['_ANDROIDCHECKINPROTO']._serialized_start=463 - _globals['_ANDROIDCHECKINPROTO']._serialized_end=709 -# @@protoc_insertion_point(module_scope) + _globals["DESCRIPTOR"]._options = None + _globals["DESCRIPTOR"]._serialized_options = b"H\003" + _globals["_DEVICETYPE"]._serialized_start = 686 + _globals["_DEVICETYPE"]._serialized_end = 789 + _globals["_CHROMEBUILDPROTO"]._serialized_start = 41 + _globals["_CHROMEBUILDPROTO"]._serialized_end = 435 + _globals["_CHROMEBUILDPROTO_PLATFORM"]._serialized_start = 203 + _globals["_CHROMEBUILDPROTO_PLATFORM"]._serialized_end = 328 + _globals["_CHROMEBUILDPROTO_CHANNEL"]._serialized_start = 330 + _globals["_CHROMEBUILDPROTO_CHANNEL"]._serialized_end = 435 + _globals["_ANDROIDCHECKINPROTO"]._serialized_start = 438 + _globals["_ANDROIDCHECKINPROTO"]._serialized_end = 684 +# @@protoc_insertion_point(module_scope) \ No newline at end of file From 5d4685b9be3b66c3bff38ae6b4049094ba116ffb Mon Sep 17 00:00:00 2001 From: sdb9696 Date: Tue, 19 Mar 2024 11:51:48 +0000 Subject: [PATCH 5/5] Fix cryptography warning in key generation --- firebase_messaging/fcm.py | 2 +- firebase_messaging/gcm.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/firebase_messaging/fcm.py b/firebase_messaging/fcm.py index f13155f..612950e 100644 --- a/firebase_messaging/fcm.py +++ b/firebase_messaging/fcm.py @@ -26,7 +26,7 @@ def fcm_register(sender_id, token, retries=5, log_debug_verbose=False): # first byte of public key is skipped for some reason # maybe it's always zero - private_key = ec.generate_private_key(ec.SECP256R1) + private_key = ec.generate_private_key(ec.SECP256R1()) public_key = private_key.public_key() serialized_private = private_key.private_bytes( diff --git a/firebase_messaging/gcm.py b/firebase_messaging/gcm.py index 1162696..d62c378 100644 --- a/firebase_messaging/gcm.py +++ b/firebase_messaging/gcm.py @@ -73,6 +73,7 @@ def gcm_check_in( ) if resp.status_code == 200: acir = AndroidCheckinResponse() + break else: _logger.warning( "GCM checkin failed on attempt %s out of %s with status: %s, %s",