empyrebase 2.3.2__tar.gz → 2.3.3__tar.gz
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.
- {empyrebase-2.3.2/empyrebase.egg-info → empyrebase-2.3.3}/PKG-INFO +19 -3
- {empyrebase-2.3.2 → empyrebase-2.3.3}/README.md +18 -2
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/empyrebase.py +1 -1
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/services/auth.py +93 -42
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/services/firestore.py +10 -3
- {empyrebase-2.3.2 → empyrebase-2.3.3/empyrebase.egg-info}/PKG-INFO +19 -3
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase.egg-info/top_level.txt +1 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/pyproject.toml +1 -1
- {empyrebase-2.3.2 → empyrebase-2.3.3}/setup.py +1 -1
- {empyrebase-2.3.2 → empyrebase-2.3.3}/LICENSE +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/MANIFEST.in +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/__init__.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/services/__init__.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/services/database.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/services/storage.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/types/__init__.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/types/closable_sseclient.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/types/firestore.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/types/keep_auth_session.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/types/private.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/types/pyre.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/types/pyre_response.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/types/sseclient.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/types/stream.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase/utils/__init__.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase.egg-info/SOURCES.txt +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase.egg-info/dependency_links.txt +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/empyrebase.egg-info/requires.txt +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/setup.cfg +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/tests/test_database.py +0 -0
- {empyrebase-2.3.2 → empyrebase-2.3.3}/tests/test_setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: empyrebase
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.3
|
|
4
4
|
Summary: A simple python wrapper for the Firebase API with current deps. Includes Realtime Database, Firestore, Authentication, and Storage.
|
|
5
5
|
Home-page: https://github.com/emrothenberg/empyrebase
|
|
6
6
|
Author: emrothenberg
|
|
@@ -35,8 +35,24 @@ Dynamic: license-file
|
|
|
35
35
|
# Empyrebase
|
|
36
36
|
|
|
37
37
|
A simple python wrapper for the [Firebase API](https://firebase.google.com). Supports Realtime DB, Firestore, Auth and Storage.
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
<p align="center">
|
|
39
|
+
<img src="images/empyrebase-logo.png" alt="Empyrebase logo" width="200"/>
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
<a href="https://pypi.org/project/empyrebase/">
|
|
44
|
+
<img src="https://img.shields.io/pypi/v/empyrebase.svg" alt="PyPI version">
|
|
45
|
+
</a>
|
|
46
|
+
<a href="https://pepy.tech/project/empyrebase">
|
|
47
|
+
<img src="https://pepy.tech/badge/empyrebase" alt="Downloads">
|
|
48
|
+
</a>
|
|
49
|
+
<a href="https://pypi.org/project/empyrebase/">
|
|
50
|
+
<img src="https://img.shields.io/pypi/pyversions/empyrebase.svg" alt="Python Versions">
|
|
51
|
+
</a>
|
|
52
|
+
<a href="https://github.com/emrothenberg/empyrebase/blob/master/LICENSE">
|
|
53
|
+
<img src="https://img.shields.io/pypi/l/empyrebase.svg" alt="License">
|
|
54
|
+
</a>
|
|
55
|
+
</p>
|
|
40
56
|
|
|
41
57
|
## Installation
|
|
42
58
|
|
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
# Empyrebase
|
|
2
2
|
|
|
3
3
|
A simple python wrapper for the [Firebase API](https://firebase.google.com). Supports Realtime DB, Firestore, Auth and Storage.
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
<p align="center">
|
|
5
|
+
<img src="images/empyrebase-logo.png" alt="Empyrebase logo" width="200"/>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://pypi.org/project/empyrebase/">
|
|
10
|
+
<img src="https://img.shields.io/pypi/v/empyrebase.svg" alt="PyPI version">
|
|
11
|
+
</a>
|
|
12
|
+
<a href="https://pepy.tech/project/empyrebase">
|
|
13
|
+
<img src="https://pepy.tech/badge/empyrebase" alt="Downloads">
|
|
14
|
+
</a>
|
|
15
|
+
<a href="https://pypi.org/project/empyrebase/">
|
|
16
|
+
<img src="https://img.shields.io/pypi/pyversions/empyrebase.svg" alt="Python Versions">
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://github.com/emrothenberg/empyrebase/blob/master/LICENSE">
|
|
19
|
+
<img src="https://img.shields.io/pypi/l/empyrebase.svg" alt="License">
|
|
20
|
+
</a>
|
|
21
|
+
</p>
|
|
6
22
|
|
|
7
23
|
## Installation
|
|
8
24
|
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import threading
|
|
3
|
+
from urllib.parse import urlencode, urlparse, parse_qs
|
|
4
|
+
from urllib.parse import unquote # if you still want to unquote()
|
|
1
5
|
import datetime
|
|
2
6
|
import json
|
|
3
7
|
import jwt as jwt
|
|
4
8
|
from empyrebase.utils import raise_detailed_error
|
|
5
9
|
import requests
|
|
6
10
|
from urllib.parse import unquote
|
|
7
|
-
from
|
|
11
|
+
from http import server
|
|
8
12
|
import webbrowser
|
|
9
13
|
|
|
10
14
|
|
|
@@ -27,56 +31,103 @@ class Auth:
|
|
|
27
31
|
self.current_user = request_object.json()
|
|
28
32
|
return request_object.json()
|
|
29
33
|
|
|
30
|
-
def get_google_oauth_token(self, client_id: str, client_secret: str,
|
|
34
|
+
def get_google_oauth_token(self, client_id: str, client_secret: str,
|
|
35
|
+
redirect_uri: str = "http://localhost:80",
|
|
36
|
+
scope: str = "email profile openid") -> str:
|
|
31
37
|
"""
|
|
32
|
-
|
|
38
|
+
Opens the user's browser, captures the authorization code automatically when using the
|
|
39
|
+
default localhost redirect, then exchanges it for a token. If a custom redirect_uri is
|
|
40
|
+
provided (non-localhost), falls back to manual paste for the code.
|
|
41
|
+
"""
|
|
42
|
+
def build_auth_url(_redirect_uri: str) -> str:
|
|
43
|
+
base = "https://accounts.google.com/o/oauth2/v2/auth"
|
|
44
|
+
q = {
|
|
45
|
+
"response_type": "code",
|
|
46
|
+
"client_id": client_id,
|
|
47
|
+
"redirect_uri": _redirect_uri,
|
|
48
|
+
"scope": scope,
|
|
49
|
+
"access_type": "offline",
|
|
50
|
+
"prompt": "consent",
|
|
51
|
+
}
|
|
52
|
+
return f"{base}?{urlencode(q)}"
|
|
33
53
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
is returned as a string.
|
|
54
|
+
code = None
|
|
55
|
+
used_redirect_uri = redirect_uri
|
|
37
56
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
57
|
+
if redirect_uri.strip().startswith("http://localhost"):
|
|
58
|
+
port = redirect_uri.strip().lower().replace(
|
|
59
|
+
"http://", "").split(":")[-1]
|
|
60
|
+
if port.startswith("localhost"):
|
|
61
|
+
raise ValueError(
|
|
62
|
+
"Invalid redirect_uri. If using localhost, please specify a port.")
|
|
63
|
+
if not port.isnumeric():
|
|
64
|
+
raise ValueError("Invalid redirect_uri. Port must be numeric.")
|
|
43
65
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
f"{
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
port = int(port)
|
|
67
|
+
sock = socket.socket()
|
|
68
|
+
sock.bind(("127.0.0.1", port))
|
|
69
|
+
sock.close()
|
|
70
|
+
|
|
71
|
+
used_redirect_uri = f"http://localhost{':' + str(port) if port != 80 else ''}"
|
|
72
|
+
|
|
73
|
+
class Handler(server.BaseHTTPRequestHandler):
|
|
74
|
+
def do_GET(self):
|
|
75
|
+
nonlocal code
|
|
76
|
+
qs = parse_qs(urlparse(self.path).query)
|
|
77
|
+
if "code" in qs:
|
|
78
|
+
code = qs["code"][0]
|
|
79
|
+
self.send_response(200)
|
|
80
|
+
self.send_header(
|
|
81
|
+
"Content-Type", "text/html; charset=utf-8")
|
|
82
|
+
self.end_headers()
|
|
83
|
+
self.wfile.write(
|
|
84
|
+
b"<html><body><h1>Authorised</h1>You can close this tab.</body></html>")
|
|
85
|
+
else:
|
|
86
|
+
self.send_response(400)
|
|
87
|
+
self.end_headers()
|
|
88
|
+
# stop server after first request
|
|
89
|
+
threading.Thread(target=httpd.shutdown,
|
|
90
|
+
daemon=True).start()
|
|
91
|
+
|
|
92
|
+
# silence default logging
|
|
93
|
+
def log_message(self, *_): pass
|
|
94
|
+
|
|
95
|
+
httpd = server.HTTPServer(("127.0.0.1", port), Handler)
|
|
96
|
+
t = threading.Thread(target=httpd.serve_forever, daemon=True)
|
|
97
|
+
t.start()
|
|
98
|
+
|
|
99
|
+
# open browser to Google's auth page targeting our local redirect
|
|
100
|
+
webbrowser.open(build_auth_url(used_redirect_uri))
|
|
101
|
+
|
|
102
|
+
# wait for code (with a reasonable timeout)
|
|
103
|
+
t.join(timeout=300) # 5 minutes max wait
|
|
104
|
+
|
|
105
|
+
if code is None:
|
|
106
|
+
raise RuntimeError(
|
|
107
|
+
"No authorization code received on the local redirect.")
|
|
108
|
+
else:
|
|
109
|
+
# CUSTOM redirect (not localhost): let the user paste the code
|
|
110
|
+
auth_url = build_auth_url(used_redirect_uri)
|
|
111
|
+
print("Visit this URL to sign in:")
|
|
112
|
+
print(auth_url)
|
|
113
|
+
webbrowser.open(auth_url)
|
|
114
|
+
code = input("Paste the code here: ").strip()
|
|
115
|
+
code = unquote(code)
|
|
116
|
+
|
|
117
|
+
# Exchange code for token
|
|
64
118
|
token_url = "https://oauth2.googleapis.com/token"
|
|
65
119
|
data = {
|
|
66
|
-
"code":
|
|
120
|
+
"code": code,
|
|
67
121
|
"client_id": client_id,
|
|
68
122
|
"client_secret": client_secret,
|
|
69
|
-
"redirect_uri":
|
|
70
|
-
"grant_type": "authorization_code"
|
|
123
|
+
"redirect_uri": used_redirect_uri,
|
|
124
|
+
"grant_type": "authorization_code",
|
|
71
125
|
}
|
|
72
|
-
|
|
73
|
-
raise_detailed_error(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return request_json.get("id_token", request_json.get("access_token"))
|
|
78
|
-
# Since the postBody parameters use id_token as a param name, I'll use id_token as a first choice
|
|
79
|
-
return request_json.get("id_token", request_json.get("access_token"))
|
|
126
|
+
r = requests.post(token_url, data=data)
|
|
127
|
+
raise_detailed_error(r)
|
|
128
|
+
j = r.json()
|
|
129
|
+
token = j.get("id_token", j.get("access_token"))
|
|
130
|
+
return token
|
|
80
131
|
|
|
81
132
|
def sign_in_with_oauth(self, oauth_token: str, provider_id: str = "google.com", request_uri: str = "http://localhost") -> dict:
|
|
82
133
|
"""
|
|
@@ -174,9 +174,16 @@ class Firestore:
|
|
|
174
174
|
|
|
175
175
|
if not document and not documents:
|
|
176
176
|
raise ValueError("Document path is required")
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
|
|
178
|
+
path_segments = document.strip("/").split("/")
|
|
179
|
+
if len(collections) == len(documents):
|
|
180
|
+
collections.extend(path_segments[0::2])
|
|
181
|
+
if len(path_segments) > 1:
|
|
182
|
+
documents.extend(path_segments[1::2])
|
|
183
|
+
else:
|
|
184
|
+
documents.extend(path_segments[0::2])
|
|
185
|
+
if len(path_segments) > 1:
|
|
186
|
+
collections.extend(path_segments[1::2])
|
|
180
187
|
|
|
181
188
|
if len(collections) != len(documents):
|
|
182
189
|
raise ValueError("Document ref must be an even child.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: empyrebase
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.3
|
|
4
4
|
Summary: A simple python wrapper for the Firebase API with current deps. Includes Realtime Database, Firestore, Authentication, and Storage.
|
|
5
5
|
Home-page: https://github.com/emrothenberg/empyrebase
|
|
6
6
|
Author: emrothenberg
|
|
@@ -35,8 +35,24 @@ Dynamic: license-file
|
|
|
35
35
|
# Empyrebase
|
|
36
36
|
|
|
37
37
|
A simple python wrapper for the [Firebase API](https://firebase.google.com). Supports Realtime DB, Firestore, Auth and Storage.
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
<p align="center">
|
|
39
|
+
<img src="images/empyrebase-logo.png" alt="Empyrebase logo" width="200"/>
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
<a href="https://pypi.org/project/empyrebase/">
|
|
44
|
+
<img src="https://img.shields.io/pypi/v/empyrebase.svg" alt="PyPI version">
|
|
45
|
+
</a>
|
|
46
|
+
<a href="https://pepy.tech/project/empyrebase">
|
|
47
|
+
<img src="https://pepy.tech/badge/empyrebase" alt="Downloads">
|
|
48
|
+
</a>
|
|
49
|
+
<a href="https://pypi.org/project/empyrebase/">
|
|
50
|
+
<img src="https://img.shields.io/pypi/pyversions/empyrebase.svg" alt="Python Versions">
|
|
51
|
+
</a>
|
|
52
|
+
<a href="https://github.com/emrothenberg/empyrebase/blob/master/LICENSE">
|
|
53
|
+
<img src="https://img.shields.io/pypi/l/empyrebase.svg" alt="License">
|
|
54
|
+
</a>
|
|
55
|
+
</p>
|
|
40
56
|
|
|
41
57
|
## Installation
|
|
42
58
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "empyrebase"
|
|
7
|
-
version = "2.3.
|
|
7
|
+
version = "2.3.3"
|
|
8
8
|
description = "A simple python wrapper for the Firebase API with current deps. Includes Realtime Database, Firestore, Authentication, and Storage."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -5,7 +5,7 @@ with open('README.md') as f:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name='empyrebase',
|
|
8
|
-
version='2.3.
|
|
8
|
+
version='2.3.3',
|
|
9
9
|
url='https://github.com/emrothenberg/empyrebase',
|
|
10
10
|
description="A simple python wrapper for the Firebase API with current deps. Includes Realtime Database, Firestore, Authentication, and Storage.",
|
|
11
11
|
long_description=long_description,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|