Issue a trusted device token, save to DB, and return the raw token for cookie.
(config, db)
| 182 | |
| 183 | |
| 184 | async def issue_totp_trusted_device(config, db) -> str | None: |
| 185 | """Issue a trusted device token, save to DB, and return the raw token for cookie.""" |
| 186 | raw_token = secrets.token_urlsafe(48) |
| 187 | token_hash = _hash_totp_trusted_device_token(config, raw_token) |
| 188 | totp_secret_hash = _hash_totp_secret(config) |
| 189 | if not token_hash or not totp_secret_hash: |
| 190 | return None |
| 191 | |
| 192 | expires_at = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta( |
| 193 | seconds=TOTP_TRUSTED_DEVICE_MAX_AGE |
| 194 | ) |
| 195 | async with db.get_db() as session: |
| 196 | async with session.begin(): |
| 197 | await session.execute( |
| 198 | delete(DashboardTrustedDevice).where( |
| 199 | col(DashboardTrustedDevice.token_hash) == token_hash |
| 200 | ) |
| 201 | ) |
| 202 | trusted_device = DashboardTrustedDevice.model_validate( |
| 203 | { |
| 204 | "token_hash": token_hash, |
| 205 | "totp_secret_hash": totp_secret_hash, |
| 206 | "expires_at": expires_at, |
| 207 | } |
| 208 | ) |
| 209 | session.add(trusted_device) |
| 210 | return raw_token |
| 211 | |
| 212 | |
| 213 | async def _cleanup_expired_totp_trusted_devices(db) -> None: |