IEEE.org     |     IEEE Xplore Digital Library     |     IEEE Standards     |     IEEE Spectrum     |     More Sites

Verified Commit b945905f authored by Emi Simpson's avatar Emi Simpson
Browse files

[api] Add expiration times to Session objects

parent 7b02a104
Pipeline #1087 passed with stage
in 49 seconds
......@@ -62,6 +62,8 @@
### Session
* **token:** `str` (18 bytes b64) - An authentication token that can be used for future logins
* **expires:** `int` (valid epoch millis) - The moment that the session token is set to expire
* **user:** `User` - The user who just logged in (equivilent to a call to `/whoami`)
### Errors
......
......@@ -236,7 +236,7 @@ class AuthModule:
_add_query_param(
callback_url,
'token',
b64encode(token).decode('ASCII'))),
b64encode(token.token).decode('ASCII'))),
on_error=lambda _: (
nullify_session,
_add_query_param(
......
from typing import Collection, Literal, Optional, TypedDict
from mystic import coordination, queries
from mystic.queries import SessionTokenInfo
from mystic.types import Backend, UserID, ProjectID, SourceID, Url
from mystic.sources import SOURCE_PROCESSORS
......@@ -270,6 +271,11 @@ class Session(TypedDict):
length is guaranteed to be exactly 24 characters.
"""
expires: int
"""
The time at which this session will expire, in epoch millis
"""
user: User
"""
Information about the currently authenticated user
......@@ -277,9 +283,9 @@ class Session(TypedDict):
Equivilent to a call to /whoami
"""
def create_session(token: bytes, user: User) -> Session:
def create_session(token: SessionTokenInfo, user: User) -> Session:
"""
A shorthand for creating a :class:`Session` from an unencoded session token
"""
from base64 import b64encode
return Session(token=b64encode(token).decode('ASCII'), user=user)
return Session(token=b64encode(token.token).decode('ASCII'), expires=token.expires, user=user)
......@@ -1117,6 +1117,20 @@ class GetSources(NamedTuple):
for source in results.all()
])
class SessionTokenInfo(NamedTuple):
"""
Some simple information about a session
"""
token: bytes
"""
The token bytes themselves, exactly eighteen of them
"""
expires: int
"""
The exact millisecond the token will expire, in epoch millis
"""
class CreateSession(NamedTuple):
"""
A :class:`Query` to create a new session for a given user
......@@ -1124,7 +1138,9 @@ class CreateSession(NamedTuple):
By default, the session will be marked to expire in one week, although this can be
overriden using the :attr:`lifespan` parameter.
If successful, this will produce exactly an exactly 18-byte session token.
If successful, this will produce exactly an exactly 18-byte session token and the
timestamp it can be expected to expire (as epoch millis).
If the user with the provided ID does not exist, then this returns None
"""
user_id: UserID
......@@ -1149,10 +1165,10 @@ class CreateSession(NamedTuple):
return QueryRequest('''
INSERT INTO sessions (token, user_id, expires)
VALUES (%s, %s, CURRENT_TIMESTAMP + INTERVAL %s MINUTE)
RETURNING token;
RETURNING token, UNIX_TIMESTAMP(expires) * 1000;
''', (randbytes(18), self.user_id, self.lifespan))
def handle_results(self, results: QueryResult | SqlIntegrityError) -> Finished[bytes] | Unfinished[bytes, None] | Error[None]:
def handle_results(self, results: QueryResult | SqlIntegrityError) -> Finished[SessionTokenInfo] | Unfinished[SessionTokenInfo, None] | Error[None]:
if isinstance(results, SqlIntegrityError):
match results.error_code:
case SqlErrorCode.DUP_ENTRY:
......@@ -1164,11 +1180,12 @@ class CreateSession(NamedTuple):
case unknown:
raise Exception(f'Unexpected sql error: {unknown}')
else:
records = results.next()
assert records is not None, 'This statement is expect to always produce one record'
token: bytes = records[0]
record: Tuple[bytes, int] | None = results.next()
assert record is not None, 'This statement is expect to always produce one record'
token, timestamp = record
assert isinstance(token, bytes), 'This statement is expected to return bytes'
return Finished(token)
assert isinstance(timestamp, int), 'This statement is expected to return a int'
return Finished(SessionTokenInfo(token, timestamp))
class InvalidateSession(NamedTuple):
"""
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment