pyios-firebase 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. pyios_firebase/__init__.py +26 -0
  2. pyios_firebase/analytics/__init__.py +434 -0
  3. pyios_firebase/analytics/names.py +251 -0
  4. pyios_firebase/app_check/__init__.py +483 -0
  5. pyios_firebase/auth/__init__.py +131 -0
  6. pyios_firebase/auth/_apple_name_cache.py +97 -0
  7. pyios_firebase/auth/_common.py +121 -0
  8. pyios_firebase/auth/_ui.py +21 -0
  9. pyios_firebase/auth/apple.py +326 -0
  10. pyios_firebase/auth/auth.py +592 -0
  11. pyios_firebase/auth/credentials.py +551 -0
  12. pyios_firebase/auth/errors.py +321 -0
  13. pyios_firebase/auth/facebook.py +240 -0
  14. pyios_firebase/auth/google.py +167 -0
  15. pyios_firebase/auth/multi_factor.py +394 -0
  16. pyios_firebase/auth/results.py +361 -0
  17. pyios_firebase/auth/user.py +457 -0
  18. pyios_firebase/core/__init__.py +32 -0
  19. pyios_firebase/crashlytics/__init__.py +463 -0
  20. pyios_firebase/database/__init__.py +62 -0
  21. pyios_firebase/database/database.py +144 -0
  22. pyios_firebase/database/errors.py +80 -0
  23. pyios_firebase/database/query.py +569 -0
  24. pyios_firebase/database/reference.py +428 -0
  25. pyios_firebase/database/snapshot.py +218 -0
  26. pyios_firebase/database/values.py +271 -0
  27. pyios_firebase/firestore/__init__.py +59 -0
  28. pyios_firebase/firestore/_limits.py +48 -0
  29. pyios_firebase/firestore/_query_state.py +228 -0
  30. pyios_firebase/firestore/_write.py +18 -0
  31. pyios_firebase/firestore/aggregate.py +137 -0
  32. pyios_firebase/firestore/collection_reference.py +100 -0
  33. pyios_firebase/firestore/document_change.py +63 -0
  34. pyios_firebase/firestore/document_reference.py +229 -0
  35. pyios_firebase/firestore/document_snapshot.py +102 -0
  36. pyios_firebase/firestore/enums.py +66 -0
  37. pyios_firebase/firestore/field_value.py +94 -0
  38. pyios_firebase/firestore/filter.py +319 -0
  39. pyios_firebase/firestore/firestore.py +184 -0
  40. pyios_firebase/firestore/listener_registration.py +55 -0
  41. pyios_firebase/firestore/query.py +679 -0
  42. pyios_firebase/firestore/query_snapshot.py +103 -0
  43. pyios_firebase/firestore/snapshot_metadata.py +36 -0
  44. pyios_firebase/firestore/transaction.py +130 -0
  45. pyios_firebase/firestore/write_batch.py +125 -0
  46. pyios_firebase/functions/__init__.py +329 -0
  47. pyios_firebase/messaging/__init__.py +37 -0
  48. pyios_firebase/messaging/messaging.py +435 -0
  49. pyios_firebase/messaging/notifications.py +292 -0
  50. pyios_firebase/performance/__init__.py +486 -0
  51. pyios_firebase/py.typed +0 -0
  52. pyios_firebase/remote_config/__init__.py +660 -0
  53. pyios_firebase/storage/__init__.py +41 -0
  54. pyios_firebase/storage/errors.py +103 -0
  55. pyios_firebase/storage/metadata.py +202 -0
  56. pyios_firebase/storage/reference.py +402 -0
  57. pyios_firebase/storage/storage.py +120 -0
  58. pyios_firebase/storage/task.py +198 -0
  59. pyios_firebase/types.py +93 -0
  60. pyios_firebase/util.py +413 -0
  61. pyios_firebase-0.2.0.dist-info/METADATA +1969 -0
  62. pyios_firebase-0.2.0.dist-info/RECORD +65 -0
  63. pyios_firebase-0.2.0.dist-info/WHEEL +5 -0
  64. pyios_firebase-0.2.0.dist-info/licenses/LICENSE +21 -0
  65. pyios_firebase-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,483 @@
1
+ """Firebase App Check: prove requests come from your real app.
2
+
3
+ Choose a provider **before** ``core.configure()``::
4
+
5
+ from pyios_firebase import app_check, core
6
+
7
+ if app_check.running_in_simulator():
8
+ app_check.use_debug_provider() # register the debug token in the console
9
+ else:
10
+ app_check.use_app_attest_provider() # or use_device_check_provider()
11
+ core.configure()
12
+
13
+ Firestore, Functions, Storage, Auth and the other Firebase SDKs then attach App
14
+ Check tokens by themselves. For your own backend, get a token with
15
+ ``AppCheck.app_check().token(...)``.
16
+
17
+ Needs the ``FirebaseAppCheck`` framework. App Attest also needs the App Attest
18
+ capability (``com.apple.developer.devicecheck.appattest-environment``).
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ __all__ = (
24
+ "APP_CHECK_ERROR_DOMAIN",
25
+ "DEBUG_TOKEN_ENVIRONMENT_VARIABLE",
26
+ "AppCheck",
27
+ "AppCheckErrorCode",
28
+ "AppCheckProvider",
29
+ "AppCheckToken",
30
+ "AppCheckTokenListener",
31
+ "TokenCallback",
32
+ "initialize_debug_appcheck",
33
+ "running_in_simulator",
34
+ "use_app_attest_provider",
35
+ "use_custom_provider",
36
+ "use_debug_provider",
37
+ "use_device_check_provider",
38
+ "use_recaptcha_provider",
39
+ )
40
+
41
+ import os
42
+ from abc import ABC, abstractmethod
43
+ from collections.abc import Callable
44
+ from dataclasses import dataclass
45
+ from datetime import UTC, datetime
46
+ from typing import Any, ClassVar, Final, cast
47
+
48
+ from rubicon.objc import NSObject, objc_method
49
+ from rubicon.objc.runtime import objc_block, objc_id
50
+
51
+ from ..types import FirebaseError, ObjCObject
52
+ from ..util import (
53
+ error_from_pointer,
54
+ listener_block,
55
+ nsdate_to_datetime,
56
+ objc_class,
57
+ objc_instance,
58
+ objc_protocols,
59
+ one_shot_block,
60
+ )
61
+
62
+ APP_CHECK_ERROR_DOMAIN: Final = "com.firebase.appCheck"
63
+ """The ``error.domain`` of App Check errors."""
64
+ DEBUG_TOKEN_ENVIRONMENT_VARIABLE: Final = "FIRAAppCheckDebugToken"
65
+ """Set it (for example in CI) to make the debug provider use that token
66
+ instead of a random one. ``AppCheckDebugToken`` also works."""
67
+
68
+ _TOKEN_CHANGED: Final = "FIRAppCheckAppCheckTokenDidChangeNotification"
69
+ _TOKEN_KEY: Final = "FIRAppCheckTokenNotificationKey"
70
+ _PROVIDER_ERROR_DOMAIN: Final = "PyiOSFirebaseAppCheckProvider"
71
+
72
+
73
+ class AppCheckErrorCode:
74
+ """The ``error.code`` values of App Check errors (``FIRAppCheckErrorCode``)."""
75
+
76
+ UNKNOWN: Final = 0
77
+ SERVER_UNREACHABLE: Final = 1
78
+ """No network, or the App Check server did not answer."""
79
+ INVALID_CONFIGURATION: Final = 2
80
+ """The provider or the Firebase project is not set up right."""
81
+ KEYCHAIN: Final = 3
82
+ """The keychain could not store the token."""
83
+ UNSUPPORTED: Final = 4
84
+ """The provider does not work here (for example App Attest in the Simulator)."""
85
+
86
+
87
+ @dataclass(frozen=True)
88
+ class AppCheckToken:
89
+ """An App Check token."""
90
+
91
+ token: str
92
+ """The token: send it in the ``X-Firebase-AppCheck`` header to your backend."""
93
+ expiration_date: datetime
94
+ """When it expires (UTC)."""
95
+
96
+ @classmethod
97
+ def from_native(cls, native: ObjCObject) -> AppCheckToken:
98
+ """Copy a native ``FIRAppCheckToken``.
99
+
100
+ Args:
101
+ native: the ``FIRAppCheckToken``.
102
+ """
103
+ expiration = nsdate_to_datetime(native.expirationDate)
104
+ return cls(str(native.token), expiration or datetime.fromtimestamp(0, UTC))
105
+
106
+ def to_native(self) -> ObjCObject:
107
+ """Make the native ``FIRAppCheckToken``."""
108
+ date = objc_class("NSDate").dateWithTimeIntervalSince1970_(
109
+ self.expiration_date.timestamp()
110
+ )
111
+ return (
112
+ objc_class("FIRAppCheckToken")
113
+ .alloc()
114
+ .initWithToken_expirationDate_(self.token, date)
115
+ )
116
+
117
+
118
+ def running_in_simulator() -> bool:
119
+ """True in the iOS Simulator, where App Attest and DeviceCheck do not work
120
+ (use the debug provider there)."""
121
+ return "SIMULATOR_DEVICE_NAME" in os.environ or "SIMULATOR_UDID" in os.environ
122
+
123
+
124
+ def _before_configure() -> None:
125
+ if objc_class("FIRApp").defaultApp() is not None:
126
+ raise RuntimeError(
127
+ "set the App Check provider before core.configure(): "
128
+ "Firebase reads it once, when the app is configured"
129
+ )
130
+
131
+
132
+ def _set_factory(factory: ObjCObject) -> None:
133
+ _before_configure()
134
+ _factory_holder["factory"] = factory # Firebase keeps it too; this makes sure
135
+ objc_class("FIRAppCheck").setAppCheckProviderFactory_(factory)
136
+
137
+
138
+ _factory_holder: dict[str, ObjCObject] = {}
139
+
140
+
141
+ def use_debug_provider() -> None:
142
+ """Use the debug provider: for the Simulator, development and CI.
143
+
144
+ On first run it prints ``Firebase App Check debug token: '...'`` in the
145
+ Xcode console; add that token in the Firebase console (App Check, your app,
146
+ Manage debug tokens). In CI, set ``DEBUG_TOKEN_ENVIRONMENT_VARIABLE`` to a
147
+ registered token. Never ship it: anyone with the token passes App Check.
148
+
149
+ Raises:
150
+ RuntimeError: ``core.configure()`` was already called.
151
+ """
152
+ _set_factory(objc_class("FIRAppCheckDebugProviderFactory").alloc().init())
153
+
154
+
155
+ def initialize_debug_appcheck() -> None:
156
+ """The 0.1 name of ``use_debug_provider``."""
157
+ use_debug_provider()
158
+
159
+
160
+ def use_device_check_provider() -> None:
161
+ """Use Apple's DeviceCheck (the default provider). Works on real devices
162
+ with iOS 11+; not in the Simulator.
163
+
164
+ Raises:
165
+ RuntimeError: ``core.configure()`` was already called.
166
+ """
167
+ _set_factory(objc_class("FIRDeviceCheckProviderFactory").alloc().init())
168
+
169
+
170
+ def use_app_attest_provider() -> None:
171
+ """Use Apple's App Attest: the strongest attestation, on real devices with
172
+ iOS 14+. Needs the App Attest capability; not in the Simulator.
173
+
174
+ Raises:
175
+ RuntimeError: ``core.configure()`` was already called.
176
+ """
177
+ _set_factory(objc_class("FIRAppAttestProviderFactory").alloc().init())
178
+
179
+
180
+ def use_recaptcha_provider(site_key: str) -> None:
181
+ """Use reCAPTCHA Enterprise. Needs the reCAPTCHA Enterprise SDK in the app.
182
+
183
+ Args:
184
+ site_key: the reCAPTCHA Enterprise site key for iOS.
185
+
186
+ Raises:
187
+ RuntimeError: ``core.configure()`` was already called.
188
+ """
189
+ _set_factory(
190
+ objc_class("FIRRecaptchaProviderFactory").alloc().initWithSiteKey_(site_key)
191
+ )
192
+
193
+
194
+ # ---- custom providers, written in Python -----------------------------------------
195
+
196
+ TokenCallback = Callable[[AppCheckToken | None, str | None], None]
197
+ """``(token, None)`` or ``(None, error_message)``."""
198
+
199
+
200
+ class AppCheckProvider(ABC):
201
+ """A custom App Check provider, written in Python: for example tokens from
202
+ your own attestation service. Pass it to ``use_custom_provider``.
203
+
204
+ ::
205
+
206
+ class MyProvider(AppCheckProvider):
207
+ def get_token(self, callback):
208
+ my_service.fetch(lambda token, expires: callback(AppCheckToken(token, expires), None))
209
+
210
+ Firebase may call these methods on a background thread.
211
+ """
212
+
213
+ @abstractmethod
214
+ def get_token(self, callback: TokenCallback) -> None:
215
+ """Make a token, then call ``callback`` exactly once.
216
+
217
+ Args:
218
+ callback: call it with ``(AppCheckToken, None)``, or
219
+ ``(None, "what went wrong")``.
220
+ """
221
+
222
+ def get_limited_use_token(self, callback: TokenCallback) -> None:
223
+ """Make a single-use token (for replay protection). By default, the
224
+ same as ``get_token``.
225
+
226
+ Args:
227
+ callback: call it with ``(AppCheckToken, None)``, or
228
+ ``(None, "what went wrong")``.
229
+ """
230
+ self.get_token(callback)
231
+
232
+
233
+ def _answer(handler: Any) -> TokenCallback:
234
+ """A Python callback that answers Firebase's completion block once."""
235
+ state = {"done": False}
236
+
237
+ def callback(token: AppCheckToken | None, error: str | None) -> None:
238
+ if state["done"]:
239
+ return
240
+ state["done"] = True
241
+ if token is not None:
242
+ handler(token.to_native(), None)
243
+ return
244
+ nserror = objc_class("NSError").errorWithDomain_code_userInfo_(
245
+ _PROVIDER_ERROR_DOMAIN,
246
+ AppCheckErrorCode.UNKNOWN,
247
+ {"NSLocalizedDescription": error or "the App Check provider gave no token"},
248
+ )
249
+ handler(None, nserror)
250
+
251
+ return callback
252
+
253
+
254
+ # the Python providers, by the address of their Objective-C bridge
255
+ _providers: dict[int, AppCheckProvider] = {}
256
+
257
+
258
+ def _key(obj: ObjCObject) -> int:
259
+ return int(obj.ptr.value or 0)
260
+
261
+
262
+ def _bridge_call(bridge: ObjCObject, method: str, handler: Any) -> None:
263
+ """Run the Python provider's ``method`` for a call Firebase made on ``bridge``."""
264
+ callback = _answer(handler)
265
+ provider = _providers.get(_key(bridge))
266
+ if provider is None:
267
+ callback(None, "the App Check provider is gone")
268
+ return
269
+ try:
270
+ getattr(provider, method)(callback)
271
+ except Exception as e: # noqa: BLE001 - Firebase must always get an answer
272
+ callback(None, f"{type(e).__name__}: {e}")
273
+
274
+
275
+ class PyAppCheckProviderBridge( # type: ignore[call-arg] # Rubicon's class keyword
276
+ NSObject, protocols=objc_protocols("FIRAppCheckProvider")
277
+ ):
278
+ """Lets Firebase call a Python ``AppCheckProvider``.
279
+
280
+ Rubicon reads these methods' annotations to build their Objective-C
281
+ signatures: parameters must be annotated with ctypes types.
282
+ """
283
+
284
+ @objc_method
285
+ def getTokenWithCompletion_(self, handler: objc_block) -> None:
286
+ """Firebase asks for a token."""
287
+ _bridge_call(self, "get_token", handler)
288
+
289
+ @objc_method
290
+ def getLimitedUseTokenWithCompletion_(self, handler: objc_block) -> None:
291
+ """Firebase asks for a limited-use token."""
292
+ _bridge_call(self, "get_limited_use_token", handler)
293
+
294
+
295
+ class PyAppCheckProviderFactory( # type: ignore[call-arg] # Rubicon's class keyword
296
+ NSObject, protocols=objc_protocols("FIRAppCheckProviderFactory")
297
+ ):
298
+ """Lets Firebase ask Python for a provider for each Firebase app."""
299
+
300
+ @objc_method
301
+ def createProviderWithApp_(self, app: objc_id) -> objc_id:
302
+ """Firebase asks for the provider of ``app``."""
303
+ make = _factories.get(_key(self))
304
+ if make is None:
305
+ return cast("objc_id", None)
306
+ bridge = PyAppCheckProviderBridge.alloc().init()
307
+ _providers[_key(bridge)] = make(objc_instance(app))
308
+ _bridges.append(bridge) # Firebase holds it; keep the Python side alive too
309
+ return cast("objc_id", bridge)
310
+
311
+
312
+ _factories: dict[int, Callable[[ObjCObject], AppCheckProvider]] = {}
313
+ _bridges: list[ObjCObject] = []
314
+
315
+
316
+ def use_custom_provider(
317
+ provider: AppCheckProvider | Callable[[ObjCObject], AppCheckProvider],
318
+ ) -> None:
319
+ """Use a custom provider written in Python.
320
+
321
+ Args:
322
+ provider: an ``AppCheckProvider`` for every Firebase app, or a function
323
+ that gets the native ``FIRApp`` and returns the provider for it.
324
+
325
+ Raises:
326
+ RuntimeError: ``core.configure()`` was already called.
327
+ """
328
+ factory = PyAppCheckProviderFactory.alloc().init()
329
+ if isinstance(provider, AppCheckProvider):
330
+ instance = provider
331
+ _factories[_key(factory)] = lambda _app: instance
332
+ else:
333
+ _factories[_key(factory)] = provider
334
+ _set_factory(factory)
335
+
336
+
337
+ # ---- tokens ---------------------------------------------------------------------
338
+
339
+
340
+ class AppCheckTokenListener:
341
+ """Given back by ``AppCheck.add_token_listener``. Call ``remove()`` to stop.
342
+
343
+ Args:
344
+ observer: the native ``NSNotificationCenter`` observer.
345
+ release: releases the listener's callback block.
346
+ """
347
+
348
+ def __init__(self, observer: ObjCObject, release: Callable[[], None]) -> None:
349
+ self._observer: ObjCObject | None = observer
350
+ self._release = release
351
+
352
+ def remove(self) -> None:
353
+ """Stop the updates. Safe to call more than once."""
354
+ if self._observer is None:
355
+ return
356
+ objc_class("NSNotificationCenter").defaultCenter.removeObserver_(self._observer)
357
+ self._observer = None
358
+ self._release()
359
+
360
+
361
+ class AppCheck:
362
+ """App Check for the default Firebase app. Get it with ``AppCheck.app_check()``.
363
+
364
+ Args:
365
+ native: the native ``FIRAppCheck``.
366
+ """
367
+
368
+ _instance: ClassVar[AppCheck | None] = None
369
+
370
+ def __init__(self, native: ObjCObject) -> None:
371
+ self._native = native
372
+
373
+ @classmethod
374
+ def app_check(cls) -> AppCheck:
375
+ """The shared instance (after ``core.configure()``)."""
376
+ if cls._instance is None:
377
+ cls._instance = cls(objc_class("FIRAppCheck").appCheck())
378
+ return cls._instance
379
+
380
+ @property
381
+ def native(self) -> ObjCObject:
382
+ """The ``FIRAppCheck``."""
383
+ return self._native
384
+
385
+ @property
386
+ def is_token_auto_refresh_enabled(self) -> bool:
387
+ """Whether App Check refreshes the token before it expires (the default
388
+ comes from ``FirebaseAppCheckTokenAutoRefreshEnabled`` in Info.plist,
389
+ else Firebase's data collection setting)."""
390
+ value = self._native.isTokenAutoRefreshEnabled
391
+ return bool(value() if callable(value) else value)
392
+
393
+ @is_token_auto_refresh_enabled.setter
394
+ def is_token_auto_refresh_enabled(self, enabled: bool) -> None:
395
+ self._native.isTokenAutoRefreshEnabled = bool(enabled)
396
+
397
+ def token(
398
+ self,
399
+ callback: Callable[[AppCheckToken | None, FirebaseError | None], None],
400
+ force_refresh: bool = False,
401
+ ) -> None:
402
+ """Get an App Check token, for example to call your own backend.
403
+
404
+ The token is cached, also across app launches, until it is about to
405
+ expire: the provider is only asked again then, or with ``force_refresh``.
406
+
407
+ Args:
408
+ callback: gets ``(AppCheckToken, None)``, or ``(None, error)``.
409
+ force_refresh: get a new token even if the cached one is valid.
410
+ """
411
+
412
+ def done(token_ptr: Any, error_ptr: Any) -> None:
413
+ if error_ptr or not token_ptr:
414
+ callback(None, error_from_pointer(error_ptr))
415
+ return
416
+ callback(AppCheckToken.from_native(objc_instance(token_ptr)), None)
417
+
418
+ self._native.tokenForcingRefresh_completion_(
419
+ bool(force_refresh), one_shot_block(done, objc_id, objc_id)
420
+ )
421
+
422
+ def limited_use_token(
423
+ self, callback: Callable[[AppCheckToken | None, FirebaseError | None], None]
424
+ ) -> None:
425
+ """Get a limited-use (single-use) token, for backends with replay
426
+ protection. It is not cached and does not affect ``token``.
427
+
428
+ Args:
429
+ callback: gets ``(AppCheckToken, None)``, or ``(None, error)``.
430
+ """
431
+
432
+ def done(token_ptr: Any, error_ptr: Any) -> None:
433
+ if error_ptr or not token_ptr:
434
+ callback(None, error_from_pointer(error_ptr))
435
+ return
436
+ callback(AppCheckToken.from_native(objc_instance(token_ptr)), None)
437
+
438
+ self._native.limitedUseTokenWithCompletion_(
439
+ one_shot_block(done, objc_id, objc_id)
440
+ )
441
+
442
+ def add_token_listener(
443
+ self, listener: Callable[[str], None]
444
+ ) -> AppCheckTokenListener:
445
+ """Listen for new App Check tokens (each refresh), on the main thread.
446
+
447
+ Args:
448
+ listener: gets the new token string.
449
+
450
+ Returns:
451
+ An ``AppCheckTokenListener``. Call ``.remove()`` to stop.
452
+ """
453
+
454
+ def on_notification(notification_ptr: Any) -> None:
455
+ notification = objc_instance(notification_ptr)
456
+ user_info = notification.userInfo
457
+ token = None if user_info is None else user_info.objectForKey_(_TOKEN_KEY)
458
+ if token is not None:
459
+ listener(str(token))
460
+
461
+ block, release = listener_block(on_notification, objc_id)
462
+ observer = objc_class(
463
+ "NSNotificationCenter"
464
+ ).defaultCenter.addObserverForName_object_queue_usingBlock_(
465
+ _TOKEN_CHANGED, None, objc_class("NSOperationQueue").mainQueue, block
466
+ )
467
+ return AppCheckTokenListener(observer, release)
468
+
469
+ @staticmethod
470
+ def debug_token() -> str:
471
+ """The debug provider's token: the ``DEBUG_TOKEN_ENVIRONMENT_VARIABLE``
472
+ token if set, else this device's local one. Register it in the Firebase
473
+ console. Works whichever provider is in use (after ``core.configure()``).
474
+
475
+ Returns:
476
+ The token.
477
+ """
478
+ provider = (
479
+ objc_class("FIRAppCheckDebugProvider")
480
+ .alloc()
481
+ .initWithApp_(objc_class("FIRApp").defaultApp())
482
+ )
483
+ return str(provider.currentDebugToken())
@@ -0,0 +1,131 @@
1
+ """Firebase Authentication.
2
+
3
+ from pyios_firebase.auth import Auth
4
+
5
+ auth = Auth.auth()
6
+ auth.create_user_with_email_password("ada@example.com", "s3cret!", on_signed_in)
7
+ listener = auth.add_state_did_change_listener(lambda user: print("user:", user))
8
+
9
+ - ``Auth``: sign-in (email/password, email link, anonymous, custom token,
10
+ credentials, OAuth web flows), sign-out, listeners, password reset and
11
+ action codes, the emulator
12
+ - ``User``: profile, ID tokens and claims, account changes, email
13
+ verification, linking and re-authentication
14
+ - credentials: ``EmailAuthProvider``, ``GoogleAuthProvider``,
15
+ ``OAuthProvider`` (Apple, Microsoft, Yahoo, GitHub, OIDC, SAML),
16
+ ``PhoneAuthProvider``, ``FacebookAuthProvider``, ``GitHubAuthProvider``,
17
+ ``TwitterAuthProvider``, ``GameCenterAuthProvider``
18
+ - ``pyios_firebase.auth.google`` / ``pyios_firebase.auth.apple``: the Google and
19
+ Apple sign-in sheets
20
+ - multi-factor (``pyios_firebase.auth.multi_factor``): SMS and TOTP second factors
21
+ - ``AuthError`` / ``AuthErrorCode``: what failed
22
+
23
+ Needs the ``FirebaseAuth`` framework. Google sign-in also needs
24
+ ``GoogleSignIn``; Apple sign-in needs the ``com.apple.developer.applesignin``
25
+ entitlement.
26
+ """
27
+
28
+ from .auth import (
29
+ APNS_TOKEN_TYPE_PRODUCTION,
30
+ APNS_TOKEN_TYPE_SANDBOX,
31
+ APNS_TOKEN_TYPE_UNKNOWN,
32
+ Auth,
33
+ AuthStateListener,
34
+ )
35
+ from .credentials import (
36
+ AuthCredential,
37
+ EmailAuthProvider,
38
+ FacebookAuthProvider,
39
+ GameCenterAuthProvider,
40
+ GitHubAuthProvider,
41
+ GoogleAuthProvider,
42
+ OAuthCredential,
43
+ OAuthProvider,
44
+ PhoneAuthProvider,
45
+ TwitterAuthProvider,
46
+ )
47
+ from .errors import AUTH_ERROR_DOMAIN, AuthError, AuthErrorCode
48
+ from .multi_factor import (
49
+ PHONE_FACTOR_ID,
50
+ TOTP_FACTOR_ID,
51
+ MultiFactor,
52
+ MultiFactorAssertion,
53
+ MultiFactorInfo,
54
+ MultiFactorResolver,
55
+ MultiFactorSession,
56
+ PhoneMultiFactorGenerator,
57
+ PhoneMultiFactorInfo,
58
+ TOTPMultiFactorGenerator,
59
+ TOTPSecret,
60
+ )
61
+ from .results import (
62
+ ActionCodeInfo,
63
+ ActionCodeOperation,
64
+ ActionCodeSettings,
65
+ ActionCodeURL,
66
+ AdditionalUserInfo,
67
+ AuthDataResult,
68
+ IDTokenResult,
69
+ UserInfo,
70
+ UserMetadata,
71
+ )
72
+ from .user import UNSET, User
73
+
74
+ __all__ = (
75
+ "APNS_TOKEN_TYPE_PRODUCTION",
76
+ "APNS_TOKEN_TYPE_SANDBOX",
77
+ "APNS_TOKEN_TYPE_UNKNOWN",
78
+ "AUTH_ERROR_DOMAIN",
79
+ "PHONE_FACTOR_ID",
80
+ "TOTP_FACTOR_ID",
81
+ "UNSET",
82
+ "ActionCodeInfo",
83
+ "ActionCodeOperation",
84
+ "ActionCodeSettings",
85
+ "ActionCodeURL",
86
+ "AdditionalUserInfo",
87
+ "Auth",
88
+ "AuthCredential",
89
+ "AuthDataResult",
90
+ "AuthError",
91
+ "AuthErrorCode",
92
+ "AuthStateListener",
93
+ "EmailAuthProvider",
94
+ "FacebookAuthProvider",
95
+ "GameCenterAuthProvider",
96
+ "GitHubAuthProvider",
97
+ "GoogleAuthProvider",
98
+ "IDTokenResult",
99
+ "MultiFactor",
100
+ "MultiFactorAssertion",
101
+ "MultiFactorInfo",
102
+ "MultiFactorResolver",
103
+ "MultiFactorSession",
104
+ "OAuthCredential",
105
+ "OAuthProvider",
106
+ "PhoneAuthProvider",
107
+ "PhoneMultiFactorGenerator",
108
+ "PhoneMultiFactorInfo",
109
+ "TOTPMultiFactorGenerator",
110
+ "TOTPSecret",
111
+ "TwitterAuthProvider",
112
+ "User",
113
+ "UserInfo",
114
+ "UserMetadata",
115
+ "current_user",
116
+ "sign_out",
117
+ )
118
+
119
+
120
+ def current_user() -> User | None:
121
+ """The signed-in ``User``, or ``None``. Same as ``Auth.auth().current_user``."""
122
+ return Auth.auth().current_user
123
+
124
+
125
+ def sign_out() -> AuthError | None:
126
+ """Sign the current user out of Firebase. Same as ``Auth.auth().sign_out()``.
127
+
128
+ Returns:
129
+ ``None``, or the error.
130
+ """
131
+ return Auth.auth().sign_out()