OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay / packages / core / core / relay-node / api-route-mounts.js

113 lines · javascript ref:
export const HYPER_GATEWAY_ROUTE_PREFIX = '/v1/hyper/'
export const INDEX_PROXY_ROOM_ROUTE = '/api/index/room'
export const INDEX_PROXY_ROUTE_PREFIX = '/index/'
export const OUTBOXLOG_HTTP_EXACT_ROUTES = Object.freeze([
  '/api/token',
  '/api/bridge/status',
  '/api/directory',
  '/api/identity',
  // Operator takedown admin surface — claimed as exactly these three routes so
  // outboxlog does NOT reserve the whole /api/admin/* namespace. Any future
  // non-outboxlog /api/admin/<x> route stays free to mount, and a stray
  // /api/admin/<other> falls through to the server's generic not-found rather
  // than being swallowed here. Routed into the outboxlog dispatch so
  // ctx.adminAuth can gate them; the adapter's isAdminPath matches the same
  // three and serves them as 404 when no admin auth is configured
  // (safe-by-default).
  '/api/admin/takedown',
  '/api/admin/restore',
  '/api/admin/takedowns'
])
export const OUTBOXLOG_HTTP_ROUTE_PREFIXES = Object.freeze([
  '/api/identity/',
  '/api/sync/',
  '/api/swarm/'
])
export const WITNESSLOG_HTTP_ROUTE = '/api/witness'
export const WITNESSLOG_HTTP_ROUTE_PREFIX = '/api/witness/'
export const REPAIRTICKET_HTTP_ROUTE = '/api/repair'
export const REPAIRTICKET_HTTP_ROUTE_PREFIX = '/api/repair/'
export const SHARD_HTTP_ROUTE = '/api/v1/shard'
export const SHARD_HTTP_ROUTE_PREFIX = '/api/v1/shard/'
export const POKER_HTTP_ROUTE = '/api/poker'
export const POKER_HTTP_ROUTE_PREFIX = '/api/poker/'
export const POKER_TABLE_CREATE_ROUTE = '/api/poker/tables'
export const POKER_TABLE_CREATE_AUTH_MESSAGE = 'Unauthorized — API key required to create a poker table'
export const MANAGEMENT_API_ROUTE_PREFIX = '/api/manage/'

export function isHyperGatewayRoute (path) {
  return typeof path === 'string' && path.startsWith(HYPER_GATEWAY_ROUTE_PREFIX)
}

export function isIndexProxyRoute (method, path) {
  return method === 'GET' && typeof path === 'string' &&
    (path === INDEX_PROXY_ROOM_ROUTE || path.startsWith(INDEX_PROXY_ROUTE_PREFIX))
}

export function isPokerHttpRoute (path) {
  return typeof path === 'string' &&
    (path === POKER_HTTP_ROUTE || path.startsWith(POKER_HTTP_ROUTE_PREFIX))
}

export function isOutboxLogHttpRoute (path) {
  return typeof path === 'string' &&
    (OUTBOXLOG_HTTP_EXACT_ROUTES.includes(path) ||
      OUTBOXLOG_HTTP_ROUTE_PREFIXES.some(prefix => path.startsWith(prefix)))
}

// The outboxlog READ surface. These routes only ever serve signed rows the
// client re-verifies (Ed25519 + key-binding), so throttling them protects no
// integrity property — and a cold browser boot legitimately bursts ~10+ reads,
// which is how the coarse per-IP budget locked returning visitors out to an
// empty feed. /api/sync/heads is POST (appIds ride in the body) but is a read.
// Writes (/api/token, create/join/append, swarm join/send/leave) and the admin
// surface are NOT reads and stay under the global budget.
export const OUTBOXLOG_HTTP_READ_GET_ROUTES = Object.freeze([
  '/api/bridge/status',
  '/api/directory',
  '/api/sync/get',
  '/api/sync/list',
  '/api/sync/range',
  '/api/sync/count',
  '/api/sync/status',
  '/api/sync/events',
  '/api/swarm/events'
])

export function isOutboxLogHttpReadRequest (method, path) {
  if (typeof path !== 'string') return false
  if (method === 'GET') return OUTBOXLOG_HTTP_READ_GET_ROUTES.includes(path)
  if (method === 'POST') return path === '/api/sync/heads'
  return false
}

export function isWitnessLogHttpRoute (path) {
  return typeof path === 'string' &&
    (path === WITNESSLOG_HTTP_ROUTE || path.startsWith(WITNESSLOG_HTTP_ROUTE_PREFIX))
}

export function isRepairTicketHttpRoute (path) {
  return typeof path === 'string' &&
    (path === REPAIRTICKET_HTTP_ROUTE || path.startsWith(REPAIRTICKET_HTTP_ROUTE_PREFIX))
}

export function isShardHttpRoute (path) {
  return typeof path === 'string' &&
    (path === SHARD_HTTP_ROUTE || path.startsWith(SHARD_HTTP_ROUTE_PREFIX))
}

export function resolvePokerHttpRoutePolicy (method, path) {
  if (method === 'POST' && path === POKER_TABLE_CREATE_ROUTE) {
    return {
      kind: 'poker-table-create',
      authRequired: true,
      authMessage: POKER_TABLE_CREATE_AUTH_MESSAGE
    }
  }
  return null
}

export function isManagementApiRoute (path) {
  return typeof path === 'string' && path.startsWith(MANAGEMENT_API_ROUTE_PREFIX)
}