#!/usr/bin/env python3.14# -*- coding: utf-8 -*-"""One-time shell tickets: web identity for PTY children.Every web shell runs as the shared `euler-ws` uid and `/proc/<pid>/environ`is same-uid-readable, so nothing carried in the environment can be a reusablecredential. Identity therefore transfers by a **consumable ticket**:- the ws service (holding the user's authenticated session cookie) asks the auth service to *mint* a ticket bound to `(email, profile)`;- the forked PTY child *redeems* it over `auth.sock` at startup — redemption consumes the ticket and returns the authoritative identity.Tickets live only in this process's memory, stored **hashed**, expire after`TICKET_TTL_SECONDS` (60 s — minting and forking are back-to-back), and aresingle-use: replay from a sibling shell's environ is dead on arrival becausethe victim's own startup already consumed the ticket."""from__future__importannotations__all__=['TicketStore']importsecretsimporttimefromhashlibimportsha256fromeuler_site.authimportpolicyfromeuler_site.auth.usersimportnormalize_emailclassTicketStore:"""hash(ticket) → (email, profile, expiry); single-use, short-TTL, in-memory."""def__init__(self,ttl_seconds:int=policy.TICKET_TTL_SECONDS)->None:self._ttl=ttl_secondsself._tickets:dict[str,tuple[str,str,float]]={}def_sweep(self)->None:now=time.time()self._tickets={key:valueforkey,valueinself._tickets.items()ifvalue[2]>now}defmint(self,email:str,profile:str)->str:"""Mint a ticket bound to `(email, profile)`; return the raw token."""self._sweep()ticket=secrets.token_urlsafe(32)key=sha256(ticket.encode()).hexdigest()self._tickets[key]=(normalize_email(email),profile,time.time()+self._ttl)returnticketdefredeem(self,ticket:str)->tuple[str,str]|None:"""Consume the ticket, returning `(email, profile)` — or None if unknown, expired, or already redeemed."""self._sweep()key=sha256(ticket.encode()).hexdigest()entry=self._tickets.pop(key,None)return(entry[0],entry[1])ifentryisnotNoneelseNone