atproto pds in zig
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485//! Development-only XRPC handlers gated by ZDS_DEV_TOOLS.//!//! These endpoints expose the centralized dev clock so local test rigs can//! fast-forward server time (token expiry, session lifetimes) without//! waiting. They must never be enabled on a production deployment.
const std = @import("std");const clock = @import("../core/clock.zig");const config = @import("../core/config.zig");const http_api = @import("../http/api.zig");const store = @import("../storage/store.zig");
pub fn dispatch(request: *http_api.Request) !void { if (!config.devTools()) { return http_api.xrpcError( request, .not_implemented, "MethodNotImplemented", "Dev tools are disabled on this PDS", ); }
const method = xrpcMethod(request.url.raw) orelse { return http_api.xrpcError(request, .bad_request, "InvalidRequest", "Invalid XRPC path"); };
if (std.mem.eql(u8, method, "dev.zat.debug.getClock")) return getClock(request); if (std.mem.eql(u8, method, "dev.zat.debug.setClock")) return setClock(request); if (std.mem.eql(u8, method, "dev.zat.debug.expireTokens")) return expireTokens(request);
return http_api.xrpcError( request, .not_implemented, "MethodNotImplemented", "Unknown dev tools method", );}
/// Force-expire all OAuth access tokens (refresh tokens untouched). This is/// the surgical alternative to setClock for exercising client refresh flows:/// DPoP proofs carry the client's iat, so fast-forwarding the server clock/// past the proof window breaks every proof; expiring the rows does not.fn expireTokens(request: *http_api.Request) !void { try store.expireAllOAuthAccessTokens(clock.now() - 1); return http_api.json(request, .ok, "{\"ok\":true}");}
fn getClock(request: *http_api.Request) !void { var buf: [128]u8 = undefined; const body = try std.fmt.bufPrint(&buf, "{{\"now\":{d},\"offsetSeconds\":{d}}}", .{ clock.now(), clock.offset() }); return http_api.json(request, .ok, body);}
fn setClock(request: *http_api.Request) !void { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const allocator = arena.allocator(); var body_buf: [4096]u8 = undefined; const body = try http_api.readBody(request, &body_buf); const parsed = try http_api.parseJsonBody(request, allocator, body); const offset_seconds = jsonInt(parsed.value, "offsetSeconds") orelse { return http_api.xrpcError(request, .bad_request, "InvalidRequest", "Missing offsetSeconds"); }; clock.setOffsetSeconds(offset_seconds); const body_out = try std.fmt.allocPrint(allocator, "{{\"ok\":true,\"offsetSeconds\":{d}}}", .{clock.offset()}); return http_api.json(request, .ok, body_out);}
fn jsonInt(value: std.json.Value, key: []const u8) ?i64 { if (value != .object) return null; const raw = value.object.get(key) orelse return null; return switch (raw) { .integer => |n| n, else => null, };}
fn xrpcMethod(target: []const u8) ?[]const u8 { const prefix = "/xrpc/"; if (!std.mem.startsWith(u8, target, prefix)) return null; const rest = target[prefix.len..]; const end = std.mem.indexOfScalar(u8, rest, '?') orelse rest.len; return rest[0..end];}