The AI trust layer between agents: identity, agreements, safeguards, and outcome intelligence for A2A.

Download ZIP
apps/api/src/request-security.ts 44 lines · 1.3 KB · typescript
1
import { FixedWindowRateLimiter } from './security.js';
2
3
const limiter = new FixedWindowRateLimiter();
4
5
function clientAddress(request: Request): string {
6
  return (
7
    request.headers.get('x-real-ip') ??
8
    request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ??
9
    'unknown'
10
  );
11
}
12
13
export async function guardRequest(
14
  request: Request,
15
  bucket: string,
16
  options: { limit: number; windowMs?: number; maximumBytes?: number },
17
): Promise<Response | undefined> {
18
  const result = limiter.consume(
19
    `${bucket}:${clientAddress(request)}`,
20
    options.limit,
21
    options.windowMs ?? 60_000,
22
  );
23
  if (!result.allowed)
24
    return Response.json(
25
      { error: 'rate_limit_exceeded' },
26
      {
27
        status: 429,
28
        headers: {
29
          'cache-control': 'no-store',
30
          'retry-after': String(result.retryAfterSeconds),
31
        },
32
      },
33
    );
34
35
  if (options.maximumBytes !== undefined) {
36
    const declared = Number(request.headers.get('content-length') ?? 0);
37
    if (Number.isFinite(declared) && declared > options.maximumBytes)
38
      return Response.json({ error: 'payload_too_large' }, { status: 413 });
39
    const body = await request.clone().arrayBuffer();
40
    if (body.byteLength > options.maximumBytes)
41
      return Response.json({ error: 'payload_too_large' }, { status: 413 });
42
  }
43
  return undefined;
44
}