Skip to content

Commit

Permalink
Core: Truncating IPs using geo activity (prebid#12107)
Browse files Browse the repository at this point in the history
* 11395 Truncating IPs using geo activity

* refactor

* returning null for invalid ip

---------

Co-authored-by: Marcin Komorski <marcinkomorski@Marcins-MacBook-Pro.local>
  • Loading branch information
mkomorski and Marcin Komorski authored Sep 4, 2024
1 parent 213caa7 commit 9c16cfb
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/activities/redactor.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ACTIVITY_TRANSMIT_TID,
ACTIVITY_TRANSMIT_UFPD
} from './activities.js';
import { scrubIPv4, scrubIPv6 } from '../utils/ipUtils.js';

export const ORTB_UFPD_PATHS = [
'data',
Expand All @@ -21,6 +22,8 @@ export const ORTB_UFPD_PATHS = [
].map(f => `user.${f}`).concat('device.ext.cdep');
export const ORTB_EIDS_PATHS = ['user.eids', 'user.ext.eids'];
export const ORTB_GEO_PATHS = ['user.geo.lat', 'user.geo.lon', 'device.geo.lat', 'device.geo.lon'];
export const ORTB_IPV4_PATHS = ['device.ip']
export const ORTB_IPV6_PATHS = ['device.ipv6']

/**
* @typedef TransformationRuleDef
Expand Down Expand Up @@ -157,6 +160,22 @@ export function ortb2TransmitRules(isAllowed = isActivityAllowed) {
return Math.round((val + Number.EPSILON) * 100) / 100;
}
},
{
name: ACTIVITY_TRANSMIT_PRECISE_GEO,
paths: ORTB_IPV4_PATHS,
applies: appliesWhenActivityDenied(ACTIVITY_TRANSMIT_PRECISE_GEO, isAllowed),
get(val) {
return scrubIPv4(val);
}
},
{
name: ACTIVITY_TRANSMIT_PRECISE_GEO,
paths: ORTB_IPV6_PATHS,
applies: appliesWhenActivityDenied(ACTIVITY_TRANSMIT_PRECISE_GEO, isAllowed),
get(val) {
return scrubIPv6(val);
}
},
{
name: ACTIVITY_TRANSMIT_TID,
paths: ['source.tid'],
Expand Down
52 changes: 52 additions & 0 deletions src/utils/ipUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export function scrubIPv4(ip) {
if (!ip) {
return null;
}

const ones = 24;

let ipParts = ip.split('.').map(Number)

if (ipParts.length != 4) {
return null;
}

let mask = [];
for (let i = 0; i < 4; i++) {
let n = Math.max(0, Math.min(8, ones - (i * 8)));
mask.push((0xff << (8 - n)) & 0xff);
}

let maskedIP = ipParts.map((part, i) => part & mask[i]);

return maskedIP.join('.');
}

export function scrubIPv6(ip) {
if (!ip) {
return null;
}

const ones = 64;

let ipParts = ip.split(':').map(part => parseInt(part, 16));

ipParts = ipParts.map(part => isNaN(part) ? 0 : part);
while (ipParts.length < 8) {
ipParts.push(0);
}

if (ipParts.length != 8) {
return null;
}

let mask = [];
for (let i = 0; i < 8; i++) {
let n = Math.max(0, Math.min(16, ones - (i * 16)));
mask.push((0xffff << (16 - n)) & 0xffff);
}

let maskedIP = ipParts.map((part, i) => part & mask[i]);

return maskedIP.map(part => part.toString(16)).join(':');
}
18 changes: 18 additions & 0 deletions test/spec/activities/redactor_spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
objectTransformer,
ORTB_EIDS_PATHS, ORTB_GEO_PATHS,
ORTB_IPV4_PATHS,
ORTB_IPV6_PATHS,
ORTB_UFPD_PATHS,
redactorFactory, redactRule
} from '../../../src/activities/redactor.js';
Expand Down Expand Up @@ -299,6 +301,22 @@ describe('redactor', () => {
expect(deepAccess(ortb2, path)).to.eql(allowed ? 1.2345 : 1.23);
})
})
ORTB_IPV4_PATHS.forEach(path => {
it(`should ${allowed ? 'NOT ' : ''} round down ${path}`, () => {
const ortb2 = {};
deepSetValue(ortb2, path, '192.168.1.1');
redactor.ortb2(ortb2);
expect(deepAccess(ortb2, path)).to.eql(allowed ? '192.168.1.1' : '192.168.1.0');
})
})
ORTB_IPV6_PATHS.forEach(path => {
it(`should ${allowed ? 'NOT ' : ''} round down ${path}`, () => {
const ortb2 = {};
deepSetValue(ortb2, path, '2001:0000:130F:0000:0000:09C0:876A:130B');
redactor.ortb2(ortb2);
expect(deepAccess(ortb2, path)).to.eql(allowed ? '2001:0000:130F:0000:0000:09C0:876A:130B' : '2001:0:130f:0:0:0:0:0');
})
})
});
});
})
58 changes: 58 additions & 0 deletions test/spec/unit/utils/ipUtils_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { scrubIPv4, scrubIPv6 } from '../../../../src/utils/ipUtils'

describe('ipUtils', () => {
describe('ipv4', () => {
it('should mask ip v4', () => {
let input = '192.168.1.1';
let output = scrubIPv4(input);
expect(output).to.deep.equal('192.168.1.0');
input = '192.168.255.255';
output = scrubIPv4(input);
expect(output).to.deep.equal('192.168.255.0');
});

it('should return null for null input', () => {
let input = null;
let output = scrubIPv4(input);
expect(output).to.deep.equal(null);
});

it('should convert invalid format to null', () => {
let invalidIp = '192.130.2';
let output = scrubIPv4(invalidIp);
expect(output).to.deep.equal(null);
});

it('should convert invalid format to null', () => {
let invalidIp = '2001:db8:3333:4444:CCCC:DDDD:EEEE:FFFF';
let output = scrubIPv4(invalidIp);
expect(output).to.deep.equal(null);
});
});

describe('ipv6', () => {
it('should mask ip v6', () => {
let input = '2001:db8:3333:4444:CCCC:DDDD:EEEE:FFFF';
let output = scrubIPv6(input);
expect(output).to.deep.equal('2001:db8:3333:4444:0:0:0:0');
});

it('should return null for null input', () => {
let input = null;
let output = scrubIPv6(input);
expect(output).to.deep.equal(null);
});

it('should convert invalid format to null', () => {
let invalidIp = '2001:db8:3333:4444:CCCC:DDDD:EEEE';
let output = scrubIPv4(invalidIp);
expect(output).to.deep.equal(null);
});

it('should convert invalid format to null', () => {
let invalidIp = 'invalid';
let output = scrubIPv4(invalidIp);
expect(output).to.deep.equal(null);
});
});
})

0 comments on commit 9c16cfb

Please sign in to comment.