Skip to content

Commit 498c0d8

Browse files
committed
core fastcomments sso - untested
1 parent 2e6bc2d commit 498c0d8

File tree

8 files changed

+153
-0
lines changed

8 files changed

+153
-0
lines changed

core/examples/secure_sso.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def main():
2+
pass

core/examples/simple_sso.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def main():
2+
pass

core/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
hmac
2+
hashlib

core/sso/fastcomments_sso.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import re
2+
from core.sso import secure_sso_user_data
3+
from core.sso import secure_sso_payload
4+
import time
5+
6+
from core.sso.helpers import create_verification_hash
7+
from core.sso.secure_sso_payload import SecureSSOPayload
8+
from core.sso.secure_sso_user_data import SecureSSOUserData
9+
from core.sso.simple_sso_user_data import SimpleSSOUserData
10+
from core.sso import simple_sso_user_data
11+
12+
13+
class FastCommentsSSO:
14+
def __init__(self, secure_sso_payload, simple_sso_user_data, login_url: str | None = None, logout_url: str | None = None):
15+
self.secure_sso_payload = secure_sso_payload
16+
self.simple_sso_user_data = simple_sso_user_data
17+
self.login_url = login_url
18+
self.logout_url = logout_url
19+
20+
@classmethod
21+
def new_secure(cls, api_key: str, secure_sso_user_data: SecureSSOUserData):
22+
timestamp = int(time.time())
23+
24+
user_data_str = secure_sso_user_data.as_json_base64()
25+
hash = create_verification_hash(api_key, timestamp, user_data_str)
26+
27+
payload = SecureSSOPayload(user_data_str, hash, timestamp)
28+
return cls(secure_sso_payload = payload, simple_sso_user_data = None)
29+
30+
@classmethod
31+
def new_simple(cls, simple_sso_user_data: SimpleSSOUserData):
32+
return cls(secure_sso_payload = None, simple_sso_user_data = simple_sso_user_data)
33+
34+
@classmethod
35+
def new_secure_with_urls(
36+
cls, secure_sso_payload: SecureSSOPayload,
37+
login_url: str,
38+
logout_url: str,
39+
):
40+
return cls(secure_sso_payload, None, login_url, logout_url)
41+
42+
def create_token(self):
43+
if self.secure_sso_payload:
44+
return self.secure_sso_payload.toJSON()
45+
elif self.simple_sso_user_data:
46+
return self.simple_sso_user_data.toJSON()
47+
else:
48+
raise ValueError("No user data provided")
49+
50+
def reset_token(self):
51+
self.cached_token = None
52+
53+
def prepare_to_send(self):
54+
if self.cached_token:
55+
return self.cached_token
56+
57+
self.cached_token = self.create_token()
58+
return self.cached_token
59+
60+
def set_secure_sso_payload(self, secure_sso_payload: SecureSSOPayload):
61+
self.secure_sso_payload = secure_sso_payload
62+
self.simple_sso_user_data = None
63+
self.reset_token()
64+
65+
def set_simple_sso_user_data(self, simple_sso_user_data: SimpleSSOUserData):
66+
self.simple_sso_user_data = simple_sso_user_data
67+
self.secure_sso_payload = None
68+
self.reset_token()

core/sso/helpers.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import hmac
2+
import hashlib
3+
4+
class CreateHashError(Exception):
5+
"""Error occurred during hash creation."""
6+
pass
7+
8+
def create_verification_hash(api_key: str, timestamp: int, user_data_json_base64: str):
9+
try:
10+
# Create message string by concatenating timestamp and base64 data
11+
message_str = f"{timestamp}{user_data_json_base64}"
12+
13+
# Create HMAC using SHA256 hash function
14+
mac = hmac.new(
15+
key=api_key.encode('utf-8'),
16+
msg=message_str.encode('utf-8'),
17+
digestmod=hashlib.sha256
18+
)
19+
20+
# Get digest as bytes then convert to hex
21+
bytes_result = mac.digest()
22+
return get_bytes_as_hex(bytes_result)
23+
24+
except Exception as e:
25+
raise CreateHashError(f"Failed to create verification hash: {str(e)}")
26+
27+
def get_bytes_as_hex(bytes_data: bytes) -> str:
28+
return ''.join(f'{b:02x}' for b in bytes_data)

core/sso/secure_sso_payload.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import json
2+
3+
class SecureSSOPayload:
4+
def __init__(self, user_data_json_base64: str, verification_hash: str, timestamp: int):
5+
self.user_data_json_base64 = user_data_json_base64
6+
self.verification_hash = verification_hash
7+
self.timestamp = timestamp
8+
9+
def toJSON(self):
10+
return json.dumps(
11+
self,
12+
default=lambda o: o.__dict__,
13+
sort_keys=True,
14+
indent=4)

core/sso/secure_sso_user_data.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import json
2+
import base64
3+
4+
class SecureSSOUserData:
5+
def __init__(self, user_id: str, email: str, username: str, avatar: str):
6+
self.user_id = user_id
7+
self.email = email
8+
self.username = username
9+
self.avatar = avatar
10+
11+
def toJSON(self):
12+
return json.dumps(
13+
self,
14+
default=lambda o: o.__dict__,
15+
sort_keys=True,
16+
indent=4)
17+
18+
def as_json_base64(self) -> str:
19+
json_str = self.toJSON()
20+
json_bytes = json_str.encode("utf-8")
21+
22+
result = base64.b64encode(json_bytes)
23+
return result.decode("utf-8")

core/sso/simple_sso_user_data.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import json
2+
3+
class SimpleSSOUserData:
4+
def __init__(self, user_id: str, email: str, avatar: str):
5+
self.user_id = user_id
6+
self.email = email
7+
self.avatar = avatar
8+
9+
def toJSON(self):
10+
return json.dumps(
11+
self,
12+
default=lambda o: o.__dict__,
13+
sort_keys=True,
14+
indent=4)

0 commit comments

Comments
 (0)