From a73b7eab91148fd7e523a1a02c4a326a8e9fcdd4 Mon Sep 17 00:00:00 2001 From: Evan Date: Fri, 20 Dec 2024 21:41:17 -0800 Subject: [PATCH] use custom ip masking instead of library --- TODO.txt | 3 ++- src/server/Archive.ts | 41 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/TODO.txt b/TODO.txt index 34dac9f4b..d64b05aee 100644 --- a/TODO.txt +++ b/TODO.txt @@ -253,7 +253,8 @@ * create more prominant discord link DONE 12/20/2024 * make defense post stronger & larger radius DONE 12/20/2024 * make event box wider DONE 12/20/2024 -* make attack bonus based on current attack size +* make attack bonus based on current attack size DONE 12/20/2024 +* bug: ips are not stored * highlight player spawn * troop density affects attack bonus * bug: NPCs don't have money diff --git a/src/server/Archive.ts b/src/server/Archive.ts index 324d8c8d5..59415bead 100644 --- a/src/server/Archive.ts +++ b/src/server/Archive.ts @@ -1,8 +1,6 @@ import { GameConfig, GameID, GameRecord, GameRecordSchema, Turn } from "../core/Schemas"; import { Storage } from '@google-cloud/storage'; import { BigQuery } from '@google-cloud/bigquery'; -// import { anonymize } from 'ip-anonymize'; -import anonymize from 'ip-anonymize'; @@ -26,7 +24,7 @@ export async function archive(gameRecord: GameRecord) { username: p.username, // Masks last couple of bits from ip for // user privacy. - ip: anonymize(p.ip), + ip: anonymizeIP(p.ip), persistentID: p.persistentID, clientID: p.clientID, })), @@ -90,4 +88,41 @@ export async function archive(gameRecord: GameRecord) { console.log(`error handling archive error: ${error}`) } } +} + +function anonymizeIP(ip: string): string { + // IPv4 regex that validates octets are 0-255 + const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; + + // More permissive IPv6 regex that handles compressed notation + const ipv6Regex = /^(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(?:ffff(?::0{1,4}){0,1}:){0,1}(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])|(?:[0-9a-fA-F]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/; + + // For IPv4, keep first three octets, mask the last + if (ipv4Regex.test(ip)) { + const octets = ip.split('.'); + return `${octets[0]}.${octets[1]}.${octets[2]}.*`; + } + + // For IPv6, normalize the address first (expand ::) + if (ipv6Regex.test(ip)) { + // Handle compressed notation + const expandedIP = ip.includes('::') + ? expandIPv6(ip) + : ip; + + const segments = expandedIP.split(':'); + return `${segments.slice(0, 6).join(':')}:****:****`; + } + + throw new Error('Invalid IP address format'); +} + +// Helper function to expand IPv6 compressed notation +function expandIPv6(ip: string): string { + const parts = ip.split('::'); + const firstPart = parts[0] ? parts[0].split(':') : []; + const secondPart = parts[1] ? parts[1].split(':') : []; + const missing = 8 - (firstPart.length + secondPart.length); + const expanded = [...firstPart, ...Array(missing).fill('0000'), ...secondPart]; + return expanded.map(x => x.padStart(4, '0')).join(':'); } \ No newline at end of file