All files / worker/fingerprint identificationClientTypes.ts

100% Statements 14/14
100% Branches 0/0
100% Functions 0/0
100% Lines 14/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191                                                        4x                 4x                       4x                   4x                   4x         4x   4x           4x               4x       4x                                   4x                                                                                                 4x         4x                     4x                          
import { RuleAction } from './ruleset'
import { z } from 'zod/v4'
 
type RulesetContext = {
  ruleset_id: string
}
/**
 * Request body structure for sending fingerprint data to the identification service.
 *
 */
export type SendBody = {
  /** Fingerprint data with signals */
  fingerprint_data: string
  /** Client's host header value */
  client_host: string
  /** Client's IP address from Cloudflare headers */
  client_ip: string
  /** Client's user agent string */
  client_user_agent: string
  /** Optional client cookie data (filtered to include only _iidt cookie) */
  client_cookie?: string
  /** Optional additional client headers (excluding cookies) */
  client_headers?: Record<string, string>
  /** Ruleset context for rule action evaluation */
  ruleset_context?: RulesetContext
}
 
// https://docs.fingerprint.com/reference/server-api-v4-get-event#response-bot-info
const BotInfo = z.object({
  category: z.string(),
  provider: z.string(),
  provider_url: z.string().optional(),
  name: z.string(),
  identity: z.enum(['verified', 'signed', 'spoofed', 'unknown']),
  confidence: z.enum(['low', 'medium', 'high']),
})
 
const Geolocation = z.object({
  accuracy_radius: z.number().optional(),
  latitude: z.number().optional(),
  longitude: z.number().optional(),
  postal_code: z.string().optional(),
  timezone: z.string().optional(),
  city_name: z.string().optional(),
  country_code: z.string().optional(),
  continent_code: z.string().optional(),
})
 
// https://docs.fingerprint.com/reference/server-api-v4-get-event#response-ip-info-v4
const IpV4Info = z.object({
  address: z.ipv4(),
  geolocation: Geolocation.optional(),
  asn_name: z.string().optional(),
  asn_network: z.string().optional(),
  asn_type: z.string().optional(),
  datacenter_name: z.string().optional(),
})
 
// https://docs.fingerprint.com/reference/server-api-v4-get-event#response-ip-info-v6
const IpV6Info = z.object({
  address: z.ipv6(),
  geolocation: Geolocation.optional(),
  asn_name: z.string().optional(),
  asn_network: z.string().optional(),
  asn_type: z.string().optional(),
  datacenter_name: z.string().optional(),
})
 
// https://docs.fingerprint.com/reference/server-api-v4-get-event#response-ip-info
const IpInfo = z.object({
  v4: IpV4Info.optional(),
  v6: IpV6Info.optional(),
})
 
const Confidence = z.enum(['low', 'medium', 'high'])
 
const ProxyDetails = z.object({
  proxy_type: z.string().optional(),
  last_seen_at: z.number().optional(),
  provider: z.string().optional(),
})
 
const VpnMethods = z.object({
  timezone_mismatch: z.boolean().optional(),
  public_vpn: z.boolean().optional(),
  auxiliary_mobile: z.boolean().optional(),
  os_mismatch: z.boolean().optional(),
  relay: z.boolean().optional(),
})
 
const IpBlocklist = z.object({
  tor_node: z.boolean().optional(),
})
 
export const IdentificationEvent = z.object({
  replayed: z.boolean(),
  timestamp: z.coerce.date(),
  url: z.url(),
  ip_address: z.ipv4().or(z.ipv6()),
  ip_info: IpInfo,
  bot_info: BotInfo.optional(),
  proxy: z.boolean().optional(),
  proxy_confidence: Confidence.optional(),
  proxy_details: ProxyDetails.optional(),
  vpn: z.boolean().optional(),
  vpn_confidence: Confidence.optional(),
  vpn_methods: VpnMethods.optional(),
  ip_blocklist: IpBlocklist.optional(),
})
 
export type IdentificationEvent = z.infer<typeof IdentificationEvent>
 
export const SendResponse = z.object({
  // Agent data returned by the identification service
  agent_data: z.string(),
  // Rule action resolved by the identification service
  rule_action: RuleAction.optional(),
  // Cookies that need to be set in the origin response
  set_cookie_headers: z.array(z.string()).optional(),
 
  event: IdentificationEvent,
})
 
export type SendResponse = z.infer<typeof SendResponse>
 
/**
 * Extended response structure that includes both agent data and cookie headers.
 */
export type SendResult = {
  // Agent data returned by the identification service
  agentData: string
  // Array of Set-Cookie header values to be sent to the client
  setCookieHeaders?: string[] | undefined
  // Optional rule action that was resolved by ingress
  ruleAction: RuleAction | undefined
  // Identification event received from ingress
  event: IdentificationEvent
}
 
export type ParsedIncomingRequest = {
  /** The signals extracted from a request */
  signals: string
 
  /**
   * Identification requires that cookies be sent in cross-origin requests. But
   * the application may not have requested this behavior.
   *
   * This flag will be true when the request is a cross-origin request
   * and the application did not request that cookies be included in the request,
   * indicating that both Cookies and Set-Cookie header fields must not be sent between the origin
   * and the client.
   */
  removeCookies: boolean
 
  /** The request with signals and optionally, cookies omitted, suitable for forwarding to the origin */
  originRequest: Request
 
  /** The cookie from the request that needs to be included in the identification request */
  clientCookie: string | undefined
}
 
const EdgeRequestHeader = z.object({
  name: z.string(),
  value: z.string(),
})
 
export const EdgeRequest = z.object({
  headers: z.array(EdgeRequestHeader).min(1),
  method: z.string(),
  url: z.url(),
  ipv4_address: z.ipv4().optional(),
  ipv6_address: z.ipv6().optional(),
  cf_properties: z.record(z.string(), z.unknown()).optional(),
})
 
export type EdgeRequest = z.infer<typeof EdgeRequest>
 
export const EdgeResponse = IdentificationEvent.pick({
  bot_info: true,
  ip_info: true,
  proxy: true,
  proxy_confidence: true,
  proxy_details: true,
  vpn: true,
  vpn_confidence: true,
  vpn_methods: true,
  ip_blocklist: true,
})
 
export type EdgeResponse = z.infer<typeof EdgeResponse>