libtimed 0.6.0__tar.gz → 0.6.2__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.
- {libtimed-0.6.0 → libtimed-0.6.2}/PKG-INFO +1 -1
- {libtimed-0.6.0 → libtimed-0.6.2}/pyproject.toml +1 -1
- {libtimed-0.6.0 → libtimed-0.6.2}/src/libtimed/models.py +2 -2
- {libtimed-0.6.0 → libtimed-0.6.2}/src/libtimed/oidc.py +36 -2
- {libtimed-0.6.0 → libtimed-0.6.2}/src/libtimed/transforms.py +15 -5
- {libtimed-0.6.0 → libtimed-0.6.2}/LICENSE +0 -0
- {libtimed-0.6.0 → libtimed-0.6.2}/README.md +0 -0
- {libtimed-0.6.0 → libtimed-0.6.2}/src/libtimed/__init__.py +0 -0
|
@@ -263,8 +263,8 @@ class Activities(BaseModel):
|
|
|
263
263
|
]
|
|
264
264
|
|
|
265
265
|
attributes = [
|
|
266
|
-
("from-time", datetime.now().time(), transforms.Time),
|
|
267
|
-
("to-time", None, transforms.Time),
|
|
266
|
+
("from-time", datetime.now().time(), transforms.Time(True)),
|
|
267
|
+
("to-time", None, transforms.Time(True)),
|
|
268
268
|
("transferred", False, transforms.Type(bool)),
|
|
269
269
|
COMMENT,
|
|
270
270
|
DATE,
|
|
@@ -4,6 +4,7 @@ import base64
|
|
|
4
4
|
import datetime
|
|
5
5
|
import http.server
|
|
6
6
|
import json
|
|
7
|
+
import time
|
|
7
8
|
import webbrowser
|
|
8
9
|
from urllib.parse import urlparse
|
|
9
10
|
|
|
@@ -41,18 +42,20 @@ class OIDCHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
|
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
class OIDCClient:
|
|
44
|
-
def __init__(self, client_id, sso_url, sso_realm, auth_path):
|
|
45
|
+
def __init__(self, client_id, sso_url, sso_realm, auth_path, use_device_flow=False):
|
|
45
46
|
self.client_id = client_id
|
|
46
47
|
self.sso_url = sso_url
|
|
47
48
|
self.sso_realm = sso_realm
|
|
48
49
|
self.auth_path = auth_path
|
|
50
|
+
self.use_device_flow = use_device_flow
|
|
49
51
|
|
|
50
52
|
def autoconfig(self):
|
|
51
53
|
data = requests.get(
|
|
52
|
-
f"{self.sso_url}/
|
|
54
|
+
f"{self.sso_url}/realms/{self.sso_realm}/.well-known/openid-configuration"
|
|
53
55
|
).json()
|
|
54
56
|
self.authorization_endpoint = data["authorization_endpoint"]
|
|
55
57
|
self.token_endpoint = data["token_endpoint"]
|
|
58
|
+
self.device_endpoint = data["device_authorization_endpoint"]
|
|
56
59
|
|
|
57
60
|
def start_browser_flow(self):
|
|
58
61
|
# construct the authorization request
|
|
@@ -74,6 +77,29 @@ class OIDCClient:
|
|
|
74
77
|
self.code = code
|
|
75
78
|
return True
|
|
76
79
|
|
|
80
|
+
def start_device_flow(self):
|
|
81
|
+
# construct the authorization request
|
|
82
|
+
auth_data = requests.post(self.device_endpoint, data={"client_id": self.client_id}).json()
|
|
83
|
+
verification_uri_complete = auth_data["verification_uri_complete"]
|
|
84
|
+
verification_uri = auth_data["verification_uri"]
|
|
85
|
+
device_code = auth_data["device_code"]
|
|
86
|
+
user_code = auth_data["user_code"]
|
|
87
|
+
|
|
88
|
+
# open the browser to the authorization URL
|
|
89
|
+
webbrowser.open_new(verification_uri_complete)
|
|
90
|
+
# print manual instructions
|
|
91
|
+
print(f"Please visit {verification_uri} and enter the code {user_code}")
|
|
92
|
+
time.sleep(5)
|
|
93
|
+
|
|
94
|
+
resp = {}
|
|
95
|
+
while "access_token" not in resp:
|
|
96
|
+
resp = requests.post(self.token_endpoint, data={"client_id": self.client_id, "grant_type": "urn:ietf:params:oauth:grant-type:device_code", "device_code": device_code}).json()
|
|
97
|
+
print(resp)
|
|
98
|
+
time.sleep(5)
|
|
99
|
+
access_token = resp["access_token"]
|
|
100
|
+
return access_token
|
|
101
|
+
|
|
102
|
+
|
|
77
103
|
def get_token(self):
|
|
78
104
|
# construct the token request
|
|
79
105
|
token_request = {
|
|
@@ -113,9 +139,11 @@ class OIDCClient:
|
|
|
113
139
|
return now.timestamp() < expires_at
|
|
114
140
|
|
|
115
141
|
def keyring_get(self):
|
|
142
|
+
return []
|
|
116
143
|
return keyring.get_password("system", "libtimed_token_" + self.client_id)
|
|
117
144
|
|
|
118
145
|
def keyring_set(self, token):
|
|
146
|
+
return True
|
|
119
147
|
keyring.set_password("system", "libtimed_token_" + self.client_id, token)
|
|
120
148
|
|
|
121
149
|
def authorize(self):
|
|
@@ -124,6 +152,12 @@ class OIDCClient:
|
|
|
124
152
|
return cached_token
|
|
125
153
|
|
|
126
154
|
self.autoconfig()
|
|
155
|
+
if self.use_device_flow:
|
|
156
|
+
if token:= self.start_device_flow():
|
|
157
|
+
self.keyring_set(token)
|
|
158
|
+
return token
|
|
159
|
+
return False
|
|
160
|
+
|
|
127
161
|
if self.start_browser_flow():
|
|
128
162
|
token = self.get_token()
|
|
129
163
|
if not token:
|
|
@@ -153,8 +153,17 @@ class Time(BaseTransform):
|
|
|
153
153
|
|
|
154
154
|
"""Transform for times."""
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
def __init__(self, return_datetime: bool = False):
|
|
157
|
+
# return_datetime will be removed at some point
|
|
158
|
+
# it defaults to True to maintain backwards compatibility
|
|
159
|
+
self.return_datetime = return_datetime
|
|
160
|
+
|
|
161
|
+
def _return_value(self, value: datetime):
|
|
162
|
+
if self.return_datetime:
|
|
163
|
+
return value
|
|
164
|
+
return value.time()
|
|
165
|
+
|
|
166
|
+
def serialize(self, value: time | str, **_) -> str | None:
|
|
158
167
|
if isinstance(value, str):
|
|
159
168
|
try:
|
|
160
169
|
value = datetime.strptime(value, TIME_FORMAT).time()
|
|
@@ -165,9 +174,10 @@ class Time(BaseTransform):
|
|
|
165
174
|
|
|
166
175
|
return value.strftime(TIME_FORMAT) if value else None
|
|
167
176
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
177
|
+
def deserialize(self, value) -> time | datetime | None:
|
|
178
|
+
return (
|
|
179
|
+
self._return_value(datetime.strptime(value, "%H:%M:%S")) if value else None
|
|
180
|
+
)
|
|
171
181
|
|
|
172
182
|
|
|
173
183
|
class Enum(BaseTransform):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|