Replace passcode identity with Ed25519 challenge-response. - Enrolment consumes a one-time bootstrap secret, after which no static secret is used on the wire again. - Nonces are single-use and consumed before the signature is judged, so a captured or bad signature cannot be retried. - Sessions are short-lived, scoped, and typed agent vs human_via_agent. - Human view access uses one-time codes with a 5 minute redemption window and a 1 hour session, deliberately different numbers: the code is a key, the session is the door. - Invariant: only an agent signature may act as an agent. Enforced and tested. - Append-only audit trail. 54 tests, covering refusals rather than only the happy path. Reference implementation, not reviewed or hardened. See README Status.
66 lines
1.5 KiB
Python
66 lines
1.5 KiB
Python
"""Sigil error types.
|
|
|
|
Every failure mode an agent or human can hit is a named class, so callers can
|
|
distinguish "your nonce expired" from "that signature is not valid" without
|
|
string matching. Nothing here carries secret material.
|
|
"""
|
|
|
|
|
|
class SigilError(Exception):
|
|
"""Base for everything Sigil raises."""
|
|
|
|
|
|
class UnknownAgent(SigilError):
|
|
"""No such agent is enrolled."""
|
|
|
|
|
|
class EnrolmentFailed(SigilError):
|
|
"""Bootstrap rejected: wrong secret, or agent already enrolled."""
|
|
|
|
|
|
class BadSignature(SigilError):
|
|
"""Signature does not verify against the enrolled public key."""
|
|
|
|
|
|
class NonceUnknown(SigilError):
|
|
"""No such challenge was issued."""
|
|
|
|
|
|
class NonceExpired(SigilError):
|
|
"""Challenge aged out before it was answered."""
|
|
|
|
|
|
class NonceUsed(SigilError):
|
|
"""Challenge already answered. This is the replay guard."""
|
|
|
|
|
|
class SessionExpired(SigilError):
|
|
"""Session aged out."""
|
|
|
|
|
|
class SessionUnknown(SigilError):
|
|
"""No such session token."""
|
|
|
|
|
|
class ScopeDenied(SigilError):
|
|
"""Session lacks the scope required for this action."""
|
|
|
|
|
|
class AgentImpersonationDenied(SigilError):
|
|
"""A non-agent session tried to act as the agent.
|
|
|
|
This is the invariant: only an agent signature may act as an agent. A
|
|
human_via_agent session can look, but it can never send as the agent.
|
|
"""
|
|
|
|
|
|
class CodeInvalid(SigilError):
|
|
"""One-time code not recognised."""
|
|
|
|
|
|
class CodeExpired(SigilError):
|
|
"""One-time code aged out before redemption."""
|
|
|
|
|
|
class CodeUsed(SigilError):
|
|
"""One-time code already redeemed. Codes are single use.""" |