on master help sign in
Remove /auth/revoke and /auth/logout endpoints
9f1d027iko
server.knot+5−51
@@ -343,7 +343,7 @@ type ActivePoll = {pubkey: PubkeyHex, startedAt: Timestamp}
343*challengeRates : [RateEntry]
343*challengeRates : [RateEntry]
344-- Per-key counters for read-only lookups (presence, /messages/list).
344-- Per-key counters for read-only lookups (presence, /messages/list).
345*lookupRates : [RateEntry]
345*lookupRates : [RateEntry]
346−-- Per-key counters for misc client writes (/auth/revoke, /auth/logout, /messages/status).
346+-- Per-key counters for misc client writes (/messages/status).
347*clientWriteRates : [RateEntry]
347*clientWriteRates : [RateEntry]
348-- Per-peer counters for inbound federation calls.
348-- Per-peer counters for inbound federation calls.
349*federationRates : [RateEntry]
349*federationRates : [RateEntry]
@@ -394,7 +394,7 @@ type ActivePoll = {pubkey: PubkeyHex, startedAt: Timestamp}
394-- Routes (response shapes preserved; removed metric fields are zero-filled)
394-- Routes (response shapes preserved; removed metric fields are zero-filled)
395-- ============================================
395-- ============================================
396-- Public HTTP surface, grouped by audience:
396-- Public HTTP surface, grouped by audience:
397−-- AuthApi -- challenge/verify/revoke/logout (client identity)
397+-- AuthApi -- challenge/verify (client identity)
398-- ClientApi -- /poll, send/batch/list/ack/delete, presence lookup
398-- ClientApi -- /poll, send/batch/list/ack/delete, presence lookup
399-- FederationApi -- inter-server gossip, forward, ack, delivery receipts
399-- FederationApi -- inter-server gossip, forward, ack, delivery receipts
400-- FederationPubkey -- exposes this server's federation Ed25519 public key
400-- FederationPubkey -- exposes this server's federation Ed25519 public key
@@ -406,8 +406,6 @@ type ActivePoll = {pubkey: PubkeyHex, startedAt: Timestamp}
406route AuthApi where
406route AuthApi where
407 POST {pubkey: PubkeyHex} /auth/challenge headers {clientIp: Text} -> {challenge: Text, ok: Bool, expiresAt: Timestamp, retryAfterMs: Int, error: Text} = ReqChallenge
407 POST {pubkey: PubkeyHex} /auth/challenge headers {clientIp: Text} -> {challenge: Text, ok: Bool, expiresAt: Timestamp, retryAfterMs: Int, error: Text} = ReqChallenge
408 POST {pubkey: PubkeyHex, challenge: Text, signature: SignatureHex, revokeOthers: Bool} /auth/verify headers {clientIp: Text} -> {token: Text, expiresAt: Timestamp, error: Text} = VerifyAuth
408 POST {pubkey: PubkeyHex, challenge: Text, signature: SignatureHex, revokeOthers: Bool} /auth/verify headers {clientIp: Text} -> {token: Text, expiresAt: Timestamp, error: Text} = VerifyAuth
409− POST {targetToken: Text} /auth/revoke headers {authorization: Text, clientIp: Text} -> {ok: Bool, authorized: Bool} = RevokeSession
410− POST /auth/logout headers {authorization: Text, clientIp: Text} -> {ok: Bool, authorized: Bool} = Logout
411
409
412route ClientApi where
410route ClientApi where
413 POST {cursor: Timestamp, generation: Int} /poll headers {authorization: Text, clientIp: Text} -> {events: [PollEvent], cursor: Timestamp, authorized: Bool, rateLimited: Bool, generation: Int, heartbeat: Bool, retryAfterMs: Int, cursorReset: Bool, hasMore: Bool, cursorStale: Bool, loadPct: Int} = Poll
411 POST {cursor: Timestamp, generation: Int} /poll headers {authorization: Text, clientIp: Text} -> {events: [PollEvent], cursor: Timestamp, authorized: Bool, rateLimited: Bool, generation: Int, heartbeat: Bool, retryAfterMs: Int, cursorReset: Bool, hasMore: Bool, cursorStale: Bool, loadPct: Int} = Poll
@@ -1146,7 +1144,7 @@ refreshLocalPresence = \t -> do
1146 when (count refreshState.refreshed > 0) (fork (sendBatchedGossip refreshState.peers (pluck refreshState.refreshed (\p -> mkGossip (GossipOnline {}) p.pubkey))))
1144 when (count refreshState.refreshed > 0) (fork (sendBatchedGossip refreshState.peers (pluck refreshState.refreshed (\p -> mkGossip (GossipOnline {}) p.pubkey))))
1147
1145
1148-- ============================================
1146-- ============================================
1149−-- Handler: challenge / verify / revoke / logout
1147+-- Handler: challenge / verify
1150-- ============================================
1148-- ============================================
1151-- Identity is a public key; there are no accounts. The flow is:
1149-- Identity is a public key; there are no accounts. The flow is:
1152-- 1. Client requests a fresh nonce (`handleChallenge`).
1150-- 1. Client requests a fresh nonce (`handleChallenge`).
@@ -1155,9 +1153,8 @@ refreshLocalPresence = \t -> do
1155-- 3. Server returns a Bearer token bound to (pubkey, ip, expiry); the new
1153-- 3. Server returns a Bearer token bound to (pubkey, ip, expiry); the new
1156-- session also installs a local presence row and gossips an `online`
1154-- session also installs a local presence row and gossips an `online`
1157-- event to known peers.
1155-- event to known peers.
1158−-- `handleRevoke` lets a session revoke its peers (same pubkey, different
1156+-- Sessions expire on their own (`sessionExpiry`); there is no client-driven
1159−-- token); `handleLogout` invalidates the caller's own token and, if no
1157+-- revoke/logout. Operators can force-revoke via `/maintenance/sessions/*`.
1160−-- sibling sessions remain, gossips an `offline` event.
1161
1158
1162-- POST /auth/challenge: issue a fresh signed-nonce challenge for `pubkey`.
1159-- POST /auth/challenge: issue a fresh signed-nonce challenge for `pubkey`.
1163-- Capped per-key (maxChallengesPerKey) and rate-limited; the IP is recorded
1160-- Capped per-key (maxChallengesPerKey) and rate-limited; the IP is recorded
@@ -1242,47 +1239,6 @@ handleVerifyAuth = \pubkey challenge signature revokeOthers clientIp -> do
1242 ]))
1239 ]))
1243 yield {token, expiresAt: expiry, error: ""}
1240 yield {token, expiresAt: expiry, error: ""}
1244
1241
1245−-- POST /auth/revoke: caller (any session for the pubkey) revokes a sibling
1246−-- session by token. Returns ok=False if no such sibling existed.
1247−handleRevoke : Text -> Text -> Text -> IO {rw *globalRateCount, rw *globalRateWindowStart, r *sessions, clock} {authorized: Bool, ok: Bool}
1248−handleRevoke = \targetToken authorization clientIp -> do
1249− t <- now
1250− gateAuth authorization clientIp t (\_ -> {ok: False {}, authorized: False {}}) (\caller -> do
1251− result <- atomic (do
1252− ses <- *sessions
1253− let pred = \s -> s.pubkey == caller && s.token == targetToken
1254− *sessions = removeWhere ses pred
1255− yield (any ses pred))
1256− yield {ok: result, authorized: True {}})
1257−
1258−-- POST /auth/logout: drop the caller's own session. If this was the last
1259−-- session for the pubkey, also clear local presence and gossip offline.
1260−handleLogout : Text -> Text -> IO {rw *presence, rw *sessions, clock} {authorized: Bool, ok: Bool}
1261−handleLogout = \authorization clientIp -> do
1262− t <- now
1263− let myToken = case extractToken authorization of
1264− Just {value: tk} -> tk
1265− _ -> ""
1266− removed <- atomic withSessionAuth authorization t clientIp (yield {
1267− ok: False {},
1268− pubkey: "",
1269− peers: []
1270− }) (\pubkey -> do
1271− ses <- *sessions
1272− *sessions = removeWhere ses (\s -> s.token == myToken)
1273− after <- *sessions
1274− peers <- if any after (\s -> s.pubkey == pubkey)
1275− then yield []
1276− else do
1277− pres <- *presence
1278− *presence = removeWhere pres (\p -> p.pubkey == pubkey && isLocalServer p.server)
1279− yield (knownPeerServersFromPresence pres)
1280− yield {ok: True {}, pubkey, peers})
1281− when (removed.ok && federationEnabled) (fork (sendBatchedGossip removed.peers [
1282− mkGossip (GossipOffline {}) removed.pubkey
1283− ]))
1284− yield {removed.ok, authorized: removed.ok}
1285−
1286-- ============================================
1242-- ============================================
1287-- Handler: poll
1243-- Handler: poll
1288-- ============================================
1244-- ============================================
@@ -2337,8 +2293,6 @@ api : Server Api _
2337api = serve Api where
2293api = serve Api where
2338 ReqChallenge = \{pubkey, clientIp} -> handleChallenge pubkey clientIp
2294 ReqChallenge = \{pubkey, clientIp} -> handleChallenge pubkey clientIp
2339 VerifyAuth = \{pubkey, challenge, signature, revokeOthers, clientIp} -> handleVerifyAuth pubkey challenge signature revokeOthers clientIp
2295 VerifyAuth = \{pubkey, challenge, signature, revokeOthers, clientIp} -> handleVerifyAuth pubkey challenge signature revokeOthers clientIp
2340− RevokeSession = \{targetToken, authorization, clientIp} -> handleRevoke targetToken authorization clientIp
2341− Logout = \{authorization, clientIp} -> handleLogout authorization clientIp
2342 Poll = \{cursor, generation, authorization, clientIp} -> handlePoll cursor generation authorization clientIp
2296 Poll = \{cursor, generation, authorization, clientIp} -> handlePoll cursor generation authorization clientIp
2343 SendMessages = \{messages, authorization, clientIp} -> handleSendMessages messages authorization clientIp
2297 SendMessages = \{messages, authorization, clientIp} -> handleSendMessages messages authorization clientIp
2344 MessageStatus = \{to, messageId, authorization, clientIp} -> handleMessageStatus to messageId authorization clientIp
2298 MessageStatus = \{to, messageId, authorization, clientIp} -> handleMessageStatus to messageId authorization clientIp