ibrahimgulbutt's picture
Claude Opus 5
deploy: campaign flow + location verification check
86063f3
Raw History Blame Contribute Delete
6.61 kB
/**
* Verdict rules for the location and presence check.
*
* Every threshold, pattern and region mapping in this file is ported VERBATIM
* from location-poc/server.js, where it was derived from measurement against
* real VPN exits and real consumer ISPs: 27/27 paid-VPN exits caught, 0/18
* false positives across Comcast, BT, PTCL, Zong, Jio, Etisalat, Starlink and
* eleven more.
*
* Do not re-tune anything here without re-running scripts/e2e/p3-verification
* against those same networks. A regression is silent: a slightly wider
* threshold does not throw, it just quietly starts blocking real people, and
* nothing in the application will tell you.
*/
/**
* Names that only ever belong to hosting, cloud or VPN operators.
*
* This list exists because ip-api's own hosting/proxy booleans miss a lot.
* Measured: they missed AS212238 (Datacamp/CDN77, which carries NordVPN and
* Surfshark exits) and AS16276 (OVH) entirely. Deliberately excludes any
* operator that also sells home or mobile internet.
*/
export const HOSTING_NAME_PATTERNS = [
'm247', 'datacamp', 'cdn77', 'leaseweb', 'ovh', 'hetzner', 'digitalocean',
'linode', 'vultr', 'contabo', 'anexia', 'private layer', 'choopa', 'psychz',
'quadranet', 'hostwinds', 'scaleway', 'netcup', 'worldstream', 'serverius',
'hostkey', 'zenlayer', 'g-core', 'gcore', 'packethub', 'tefincom', 'nordvpn',
'surfshark', 'expressvpn', 'protonvpn', 'mullvad', '31173', 'cyberghost',
'ipvanish', 'windscribe', 'hidemyass', 'perfect privacy', 'frantech', 'buyvm',
'xtom', 'fdcservers', 'colocrossing', 'servermania', 'interserver', 'nforce',
'ddos-guard', 'aeza', 'cherry servers', 'melbicom', 'clouvider', 'flokinet',
'amazon', 'google llc', 'microsoft corporation', 'oracle corporation',
'alibaba', 'tencent', 'digital ocean', 'ionos se', 'hostinger', 'namecheap',
'dedipath', 'hivelocity', 'webnx', 'sharktech', 'phoenixnap', 'greenhost',
'datapacket', 'estnoc', 'hostslick', 'ipxo', 'terrahost', 'combahton',
'servers.com', 'rackspace', 'stark industries', 'vpn',
];
/**
* Rough "nearest AWS region" per country, with a deliberately generous
* round-trip ceiling. Real connections inside these regions sit far below the
* ceiling; exceeding it is a physical impossibility, not an opinion.
*
* Each country maps to EVERY region it could legitimately be nearest to, not
* just the geographically closest one - real routing does not follow a map.
* Pakistani ISPs, for instance, commonly peer through Dubai, so a genuine
* Karachi connection reaches me-central-1 faster than Mumbai. Scoring against a
* single "expected" region would flag those users for nothing.
*
* Do not simplify this to one region per country.
*/
export const REGIONS_BY_COUNTRY: Record<string, string[]> = {
DE: ['eu-central-1', 'eu-west-1'], FR: ['eu-central-1', 'eu-west-1'],
NL: ['eu-central-1', 'eu-west-1'], BE: ['eu-central-1', 'eu-west-1'],
CH: ['eu-central-1', 'eu-west-1'], AT: ['eu-central-1', 'eu-west-1'],
PL: ['eu-central-1', 'eu-west-1'], CZ: ['eu-central-1', 'eu-west-1'],
IT: ['eu-central-1', 'eu-west-1'], DK: ['eu-central-1', 'eu-west-1'],
SE: ['eu-central-1', 'eu-west-1'], NO: ['eu-central-1', 'eu-west-1'],
GB: ['eu-west-1', 'eu-central-1'], IE: ['eu-west-1', 'eu-central-1'],
PT: ['eu-west-1', 'eu-central-1'], ES: ['eu-west-1', 'eu-central-1'],
TR: ['eu-central-1', 'me-central-1', 'eu-west-1'],
US: ['us-east-1'], CA: ['us-east-1'], MX: ['us-east-1'],
BR: ['sa-east-1', 'us-east-1'], AR: ['sa-east-1', 'us-east-1'],
CL: ['sa-east-1', 'us-east-1'], CO: ['sa-east-1', 'us-east-1'],
AE: ['me-central-1', 'ap-south-1', 'eu-central-1'],
SA: ['me-central-1', 'ap-south-1', 'eu-central-1'],
QA: ['me-central-1', 'ap-south-1', 'eu-central-1'],
KW: ['me-central-1', 'ap-south-1', 'eu-central-1'],
BH: ['me-central-1', 'ap-south-1', 'eu-central-1'],
OM: ['me-central-1', 'ap-south-1', 'eu-central-1'],
JO: ['me-central-1', 'eu-central-1'], EG: ['me-central-1', 'eu-central-1'],
PK: ['ap-south-1', 'me-central-1'], IN: ['ap-south-1', 'me-central-1'],
BD: ['ap-south-1', 'ap-southeast-1'], LK: ['ap-south-1'], NP: ['ap-south-1'],
SG: ['ap-southeast-1'], MY: ['ap-southeast-1'], ID: ['ap-southeast-1'],
TH: ['ap-southeast-1'], PH: ['ap-southeast-1'], VN: ['ap-southeast-1'],
JP: ['ap-northeast-1'], KR: ['ap-northeast-1'], TW: ['ap-northeast-1', 'ap-southeast-1'],
AU: ['ap-southeast-2'], NZ: ['ap-southeast-2'],
ZA: ['af-south-1'], NG: ['af-south-1', 'eu-west-1'], KE: ['af-south-1', 'eu-central-1'],
};
/**
* A slow connection is not a lie.
*
* What matters is not the absolute round trip but the GAP: how much further the
* declared country's own region is than the fastest region this connection can
* reach. For an honest user that gap is near zero - their country's region IS
* their nearest. The threshold scales with the connection's own floor, so a
* uniformly slow link (mobile data, bad wifi, congested ISP) can never trigger
* it however slow it gets.
*/
export const RTT_MIN_GAP_MS = 80;
export const gapThreshold = (floorRtt: number): number => Math.max(RTT_MIN_GAP_MS, floorRtt);
/** Used only for the informational "everything was slow" note. */
export const RTT_SLOW_MS = 250;
/** Substrings that identify a virtual camera or virtual audio device by name. */
export const VIRTUAL_DEVICE_PATTERNS = [
'obs', 'manycam', 'xsplit', 'snap camera', 'virtual', 'vb-audio', 'vb-cable',
'voicemeeter', 'droidcam', 'epoccam', 'ivcam', 'ndi', 'streamlabs',
'remote audio', 'rdp', 'citrix', 'splitcam', 'altercam', 'e2esoft', 'fake',
];
/** WebGL renderer strings produced by virtualised or remote-desktop graphics. */
export const VIRTUAL_RENDERER_PATTERNS = [
'microsoft basic render', 'llvmpipe', 'swiftshader', 'vmware', 'virtualbox',
'parallels', 'remote display', 'mesa offscreen', 'gdi generic', 'virgl',
];
/**
* Fields hashed into a device signature.
*
* A signature match means "these sessions came from the same machine". That is
* a LINK, not a verdict, and never a block - real people share devices.
* Internet cafes, family computers, corporate laptop fleets and university labs
* all legitimately produce matches, and all of those are common in the markets
* this product targets.
*/
export const SIGNATURE_FIELDS = [
'glRenderer', 'glVendor', 'screen', 'languages', 'cores',
'memoryGb', 'platform', 'canvas', 'audio', 'fonts',
];
export const matchesAny = (value: unknown, patterns: string[]): boolean => {
const low = String(value ?? '').toLowerCase();
return patterns.some((p) => low.includes(p));
};