Skip to content

jmwalletd.deps

jmwalletd.deps

FastAPI dependency injection helpers.

Provides get_daemon_state, get_bearer_token, require_auth, and require_wallet_match which are used by route handlers to access the daemon state and enforce authentication and resource ownership.

Classes

Functions:

get_daemon_state() -> DaemonState

FastAPI dependency that returns the daemon state.

Source code in jmwalletd/src/jmwalletd/deps.py
29
30
31
32
33
34
def get_daemon_state() -> DaemonState:
    """FastAPI dependency that returns the daemon state."""
    if _daemon_state is None:
        msg = "Daemon state not initialized"
        raise RuntimeError(msg)
    return _daemon_state

get_optional_token(request: Request) -> str | None

Extract bearer token if present, or return None.

Source code in jmwalletd/src/jmwalletd/deps.py
50
51
52
def get_optional_token(request: Request) -> str | None:
    """Extract bearer token if present, or return None."""
    return _extract_bearer_token(request)

require_auth(request: Request, state: DaemonState = Depends(get_daemon_state)) -> dict[str, Any]

FastAPI dependency that enforces bearer token authentication.

Returns the decoded JWT payload on success.

Raises: InvalidToken: If the token is missing, invalid, or expired. NoWalletFound: If no wallet is currently loaded.

Source code in jmwalletd/src/jmwalletd/deps.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
def require_auth(
    request: Request,
    state: DaemonState = Depends(get_daemon_state),
) -> dict[str, Any]:
    """FastAPI dependency that enforces bearer token authentication.

    Returns the decoded JWT payload on success.

    Raises:
        InvalidToken: If the token is missing, invalid, or expired.
        NoWalletFound: If no wallet is currently loaded.
    """
    if not state.wallet_loaded:
        raise NoWalletFound()

    token = _extract_bearer_token(request)
    if not token:
        raise InvalidToken("No authorization token provided.")

    try:
        payload = state.token_authority.verify_access(token)
    except jwt.InvalidTokenError as exc:
        logger.debug("Token verification failed: {}", exc)
        raise InvalidToken(str(exc)) from exc

    return payload

require_auth_allow_expired(request: Request, state: DaemonState = Depends(get_daemon_state)) -> dict[str, Any]

Like require_auth but accepts expired access tokens.

Used for the token-refresh endpoint where the access token may be expired but still needs to be structurally valid.

Source code in jmwalletd/src/jmwalletd/deps.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
def require_auth_allow_expired(
    request: Request,
    state: DaemonState = Depends(get_daemon_state),
) -> dict[str, Any]:
    """Like ``require_auth`` but accepts expired access tokens.

    Used for the token-refresh endpoint where the access token may be expired
    but still needs to be structurally valid.
    """
    if not state.wallet_loaded:
        raise NoWalletFound()

    token = _extract_bearer_token(request)
    if not token:
        raise InvalidToken("No authorization token provided.")

    try:
        payload = state.token_authority.verify_access(token, verify_exp=False)
    except jwt.InvalidTokenError as exc:
        logger.debug("Token verification failed: {}", exc)
        raise InvalidToken(str(exc)) from exc

    return payload

require_wallet_match(walletname: str, state: DaemonState = Depends(get_daemon_state)) -> None

FastAPI path-dependency that validates the walletname URL parameter.

Every route whose URL contains {walletname} must include this dependency to prevent IDOR: an authenticated client with a valid token must only be able to act on the wallet that is actually loaded, not any arbitrary name they pass in the path.

Raises: WalletNotFound: If no wallet is loaded, or if the requested walletname does not match the currently loaded wallet.

Source code in jmwalletd/src/jmwalletd/deps.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
def require_wallet_match(
    walletname: str,
    state: DaemonState = Depends(get_daemon_state),
) -> None:
    """FastAPI path-dependency that validates the ``walletname`` URL parameter.

    Every route whose URL contains ``{walletname}`` must include this
    dependency to prevent IDOR: an authenticated client with a valid token
    must only be able to act on the wallet that is actually loaded, not any
    arbitrary name they pass in the path.

    Raises:
        WalletNotFound: If no wallet is loaded, or if the requested walletname
            does not match the currently loaded wallet.
    """
    if not state.wallet_loaded or state.wallet_name != walletname:
        raise WalletNotFound()

set_daemon_state(state: DaemonState) -> None

Set the global daemon state singleton (called once at startup).

Source code in jmwalletd/src/jmwalletd/deps.py
23
24
25
26
def set_daemon_state(state: DaemonState) -> None:
    """Set the global daemon state singleton (called once at startup)."""
    global _daemon_state
    _daemon_state = state