-
-
Notifications
You must be signed in to change notification settings - Fork 171
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
server: tweak token generation to add checksum
- Loading branch information
1 parent
91e5529
commit 1af02e2
Showing
2 changed files
with
27 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,46 @@ | ||
import hashlib | ||
import hmac | ||
import secrets | ||
import string | ||
import zlib | ||
|
||
|
||
def _crc32_to_base62(number: int) -> str: | ||
characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | ||
base = len(characters) | ||
encoded = "" | ||
while number: | ||
number, remainder = divmod(number, base) | ||
encoded = characters[remainder] + encoded | ||
return encoded.zfill(6) # Ensure the checksum is 6 characters long | ||
|
||
|
||
def get_token_hash(token: str, *, secret: str) -> str: | ||
hash = hmac.new(secret.encode("ascii"), token.encode("ascii"), hashlib.sha256) | ||
return hash.hexdigest() | ||
|
||
|
||
def generate_token(*, prefix: str = "", nbytes: int | None = None) -> str: | ||
return f"{prefix}{secrets.token_urlsafe(nbytes)}" | ||
def generate_token(*, prefix: str = "") -> str: | ||
# Generate a high entropy random token | ||
token = "".join( | ||
secrets.choice(string.ascii_letters + string.digits) for _ in range(37) | ||
) | ||
|
||
# Calculate a 32-bit CRC checksum | ||
checksum = zlib.crc32(token.encode("utf-8")) & 0xFFFFFFFF | ||
checksum_base62 = _crc32_to_base62(checksum) | ||
|
||
# Concatenate the prefix, token, and checksum | ||
return f"{prefix}{token}{checksum_base62}" | ||
|
||
|
||
def generate_token_hash_pair( | ||
*, secret: str, prefix: str = "", nbytes: int | None = None | ||
) -> tuple[str, str]: | ||
def generate_token_hash_pair(*, secret: str, prefix: str = "") -> tuple[str, str]: | ||
""" | ||
Generate a token suitable for sensitive values | ||
like magic link tokens. | ||
Returns both the actual value and its HMAC-SHA256 hash. | ||
Only the latter shall be stored in database. | ||
""" | ||
token = generate_token(prefix=prefix, nbytes=nbytes) | ||
token = generate_token(prefix=prefix) | ||
return token, get_token_hash(token, secret=secret) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters