Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor key-logging.ts #62

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions __tests__/key-logging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import { defaultPuppeteerBrowserOptions } from "../src/pptr-utils/default";
import { fillForms } from "../src/pptr-utils/interaction-utils";
import puppeteer, { Browser } from "puppeteer";
import { setupKeyLoggingInspector } from "../src/key-logging";
import { Global } from "../src/types";
import { setUpKeyLoggingInspector } from "../src/key-logging";
import { Global, KeyLoggingEvent } from "../src/types";

declare var global: Global;

Expand Down Expand Up @@ -695,12 +695,12 @@ describe("KeyLogging", () => {
const page = await browser.newPage();
const testUrl = `${global.__DEV_SERVER__}/session_recorder.html`;
// const testUrl = "https://www.veteransunited.com/";
const rows = [];
const rows: KeyLoggingEvent[] = [];
const eventHandler = event => {
rows.push(event);
};

await setupKeyLoggingInspector(page, eventHandler);
await setUpKeyLoggingInspector(page, eventHandler);
await page.goto(testUrl, { waitUntil: "networkidle2" });
await page.waitForTimeout(1000);
await fillForms(page);
Expand Down Expand Up @@ -777,7 +777,7 @@ describe("KeyLogging", () => {
const eventHandler = event => {
rows.push(event);
};
await setupKeyLoggingInspector(page, eventHandler);
await setUpKeyLoggingInspector(page, eventHandler);
await page.goto(testUrl, { waitUntil: "networkidle2" });
await page.waitForTimeout(1000);
await fillForms(page);
Expand Down
13 changes: 6 additions & 7 deletions example.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@

import { KnownDevices } from "puppeteer";
import { CollectorOptions, collect } from "./src";
import { join } from 'path';
const { KnownDevices } = require('puppeteer');
const { collect } = require('./build/index');
const { join } = require('path');

(async () => {
const URL = 'example.com';
const URL = 'digg.com';
const EMULATE_DEVICE = 'iPhone 13 Mini';

const config: CollectorOptions = {
const config = {
numPages: 3,
headless: false,
emulateDevice: KnownDevices[EMULATE_DEVICE],
// Uncomment to run with desktop/laptop browser
// emulateDevice: {
// viewport: {height: 1440, width: 800},
// userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
// userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
// },
outDir: join(__dirname, 'demo-dir'),
};
Expand Down
6 changes: 2 additions & 4 deletions src/canvas-fingerprinting.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { BlacklightEvent, JsInstrumentEvent } from './types';
import { getScriptUrl, serializeCanvasCallMap } from './utils';

/**
* @fileOverview Utility functions for canvas finerprinting analysis.
* Implemented following the Princeton study's methodology.
*/

import { parse } from 'url';
import { getScriptUrl, serializeCanvasCallMap } from './utils';

const MIN_CANVAS_IMAGE_WIDTH = 16;
const MIN_CANVAS_IMAGE_HEIGHT = 16;
const MIN_FONT_LIST_SIZE = 50;
Expand Down Expand Up @@ -68,7 +66,7 @@ export const sortCanvasCalls = (canvasCalls: BlacklightEvent[]) => {
const cStyles = new Map() as CanvasCallMap;
for (const item of canvasCalls) {
const { url, data } = item as JsInstrumentEvent;
const url_host = parse(url).hostname;
const url_host = new URL(url).hostname;
const script_url = getScriptUrl(item);
const { symbol, operation, value } = data;
if (typeof script_url === 'undefined' || script_url.indexOf('http:') < -1 || script_url.indexOf('https:') < -1) {
Expand Down
7 changes: 3 additions & 4 deletions src/collector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import { join } from 'path';
import puppeteer, { Browser, Page, PuppeteerLifeCycleEvent, KnownDevices, PuppeteerLaunchOptions } from 'puppeteer';
import PuppeteerHar from 'puppeteer-har';
import { getDomain, getSubdomain, parse } from 'tldts';
import url from 'url';
import { captureBrowserCookies, clearCookiesCache, setupHttpCookieCapture } from './cookie-collector';
import { setupBlacklightInspector } from './inspector';
import { setupKeyLoggingInspector } from './key-logging';
import { setUpKeyLoggingInspector } from './key-logging';
import { getLogger } from './logger';
import { generateReport } from './parser';
import { defaultPuppeteerBrowserOptions, savePageContent } from './pptr-utils/default';
Expand Down Expand Up @@ -63,7 +62,7 @@ export const collect = async (inUrl: string, args: CollectorOptions) => {
uri_dest: null,
uri_redirects: null,
secure_connection: {},
host: url.parse(inUrl).hostname,
host: new URL(inUrl).hostname,
config: {
cleareCache: args.clearCache,
captureHar: args.captureHar,
Expand Down Expand Up @@ -157,7 +156,7 @@ export const collect = async (inUrl: string, args: CollectorOptions) => {

// Init blacklight instruments on page
await setupBlacklightInspector(page, logger.warn);
await setupKeyLoggingInspector(page, logger.warn);
await setUpKeyLoggingInspector(page, logger.warn);
await setupHttpCookieCapture(page, logger.warn);
await setupSessionRecordingInspector(page, logger.warn);
await setUpThirdPartyTrackersInspector(page, logger.warn, args.enableAdBlock);
Expand Down
88 changes: 46 additions & 42 deletions src/key-logging.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,66 @@
import { HTTPRequest, Page } from 'puppeteer';
import { Page } from 'puppeteer';
import { DEFAULT_INPUT_VALUES } from './pptr-utils/interaction-utils';
import { BlacklightEvent } from './types';
import { getHashedValues } from './utils';
const ts = [
...Object.values(DEFAULT_INPUT_VALUES),
...Object.values(getHashedValues('base64', DEFAULT_INPUT_VALUES)),
...Object.values(getHashedValues('md5', DEFAULT_INPUT_VALUES)),
...Object.values(getHashedValues('sha256', DEFAULT_INPUT_VALUES)),
...Object.values(getHashedValues('sha512', DEFAULT_INPUT_VALUES))
];
import { BlacklightErrorEvent, KeyLoggingEvent } from './types';
import { getHashedArray } from './utils';

const hashesMap = {
base64: Object.values(getHashedValues('base64', DEFAULT_INPUT_VALUES)),
md5: Object.values(getHashedValues('md5', DEFAULT_INPUT_VALUES)),
plaintext: Object.values(DEFAULT_INPUT_VALUES),
sha256: Object.values(getHashedValues('sha256', DEFAULT_INPUT_VALUES)),
sha512: Object.values(getHashedValues('sha512', DEFAULT_INPUT_VALUES))
const INPUT_VALUES = Object.values(DEFAULT_INPUT_VALUES);

const hashesMap: Record<string, string[]> = {
plaintext: INPUT_VALUES,
base64: getHashedArray('base64', INPUT_VALUES),
md5: getHashedArray('md5', INPUT_VALUES),
sha256: getHashedArray('sha256', INPUT_VALUES),
sha512: getHashedArray('sha512', INPUT_VALUES)
};
export const setupKeyLoggingInspector = async (page: Page, eventDataHandler: (event: BlacklightEvent) => void) => {
page.on('request', (request: HTTPRequest) => {

export async function setUpKeyLoggingInspector(
page: Page,
eventDataHandler: (event: KeyLoggingEvent|BlacklightErrorEvent) => void
) {
page.on('request', request => {
const stack = [
{
fileName: request.frame() ? request.frame().url() : '',
source: `RequestHandler`
source: 'RequestHandler'
}
];

if (request.method() === 'POST') {
try {
let filter = [];
filter = ts.filter((t: string) => request.postData().indexOf(t) > -1);
if (filter.length > 0) {
let match_type = [];
filter.forEach(val => {
const m = Object.entries(hashesMap).filter(([, hashes]) => {
return hashes.indexOf(val) > -1;
});
match_type = match_type.concat(m.map(e => e[0]));
});
match_type = [...new Set(match_type)];
eventDataHandler({
data: {
filter,
match_type,
post_data: request.postData(),
post_request_url: request.url()
},
stack,
type: `KeyLogging`,
url: request.frame().url()
});
let matchTypes = new Set<string>();
let filter: string[] = [];

for (const hashType in hashesMap) {
const hashedValues = hashesMap[hashType];

for (const value of hashedValues) {
if (request.postData()?.includes(value)) {
filter.push(value);
matchTypes.add(hashType);
break;
}
}
}

eventDataHandler({
data: {
filter,
match_type: Array.from(matchTypes),
post_data: request.postData(),
post_request_url: request.url()
},
stack,
type: 'KeyLogging',
url: request.frame().url()
});
} catch (error) {
console.error(error);
eventDataHandler({
data: {
message: JSON.stringify(error)
},
stack,
type: `Error.KeyLogging`,
type: 'Error.KeyLogging',
url: request.frame().url()
});
}
Expand Down
13 changes: 4 additions & 9 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,7 @@ import { getDomain } from 'tldts';
import { getCanvasFontFp, getCanvasFp } from './canvas-fingerprinting';
import { loadBrowserCookies, matchCookiesToEvents } from './cookie-collector';
import { FB_ADVANCED_MATCHING_PARAMETERS, FB_STANDARD_EVENTS } from './fb-pixel-lookup';
import {
BEHAVIOUR_TRACKING_EVENTS,
BlacklightEvent,
FINGERPRINTABLE_WINDOW_APIS,
JsInstrumentEvent,
KeyLoggingEvent,
SessionRecordingEvent,
TrackingRequestEvent
} from './types';
import { BEHAVIOUR_TRACKING_EVENTS, BlacklightEvent, FINGERPRINTABLE_WINDOW_APIS, JsInstrumentEvent, KeyLoggingEvent, SessionRecordingEvent, TrackingRequestEvent } from './types';
import { getScriptUrl, groupBy, loadJSONSafely } from './utils';

export const generateReport = (reportType, messages, dataDir, url) => {
Expand Down Expand Up @@ -42,6 +34,7 @@ export const generateReport = (reportType, messages, dataDir, url) => {
const filterByEvent = (messages, typePattern) => {
return messages.filter(m => m.message.type.includes(typePattern) && !m.message.type.includes('Error'));
};

const getEventData = (reportType, messages): BlacklightEvent[] => {
let filtered = [];
switch (reportType) {
Expand Down Expand Up @@ -78,6 +71,7 @@ const getEventData = (reportType, messages): BlacklightEvent[] => {
}
return filtered.map(m => m.message);
};

const reportSessionRecorders = (eventData: BlacklightEvent[]) => {
const report = {};
eventData.forEach((event: SessionRecordingEvent) => {
Expand Down Expand Up @@ -265,6 +259,7 @@ const reportFbPixelEvents = (eventData: BlacklightEvent[]) => {
};
});
};

const getDomainSafely = (message: KeyLoggingEvent) => {
try {
if (message.data.post_request_url) {
Expand Down
6 changes: 5 additions & 1 deletion src/pptr-utils/get-links.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { LinkObject } from '../types';
type LinkObject = {
href: string,
innerHtml: string,
innerText: string
}

export const getLinks = async (page): Promise<LinkObject[]> => {
return page.evaluate(() => {
Expand Down
3 changes: 1 addition & 2 deletions src/session-recording.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Page } from 'puppeteer';
import url from 'url';
import { BlacklightEvent, SESSION_RECORDERS_LIST } from './types';

export const setupSessionRecordingInspector = async (page: Page, eventDataHandler: (event: BlacklightEvent) => void) => {
page.on('request', async request => {
const parsedUrl = url.parse(request.url());
const parsedUrl = new URL(request.url());
const cleanUrl = `${parsedUrl.hostname}${parsedUrl.pathname}`;
const stack = [
{
Expand Down
45 changes: 21 additions & 24 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,30 @@ export interface Global {
__DEV_SERVER__: string;
}

export type BlacklightEvent = JsInstrumentEvent | KeyLoggingEvent | BlacklightErrorEvent | TrackingRequestEvent | SessionRecordingEvent;

export interface KeyLoggingEvent {
type: 'KeyLogging';
export interface BlacklightEvent {
type: string;
url: string;
stack: any[];
}

export interface KeyLoggingEvent extends BlacklightEvent {
type: 'KeyLogging';
data: {
filter: string[],
post_request_url: string;
post_data: string;
match_type: string[];
filter: string[];
};
}

export interface JsInstrumentEvent {
export interface JsInstrumentEvent extends BlacklightEvent {
type:
| 'JsInstrument'
| 'JsInstrument.Debug'
| 'JsInstrument.Error'
| 'JsInstrument.Function'
| 'JsInstrument.FunctionProxy'
| 'JsInstrument.ObjectProperty';
url: string;
stack: any[];
data: {
symbol: string;
value: string;
Expand All @@ -35,22 +35,22 @@ export interface JsInstrumentEvent {
};
}

export interface SessionRecordingEvent {
export interface SessionRecordingEvent extends BlacklightEvent {
type: 'SessionRecording';
url: string;
matches: string[];
stack: any[];
}
export interface TrackingRequestEvent {

export interface TrackingRequestEvent extends BlacklightEvent {
type: 'TrackingRequest';
url: string;
stack: any[];
data: { query?: any; filter: string; listName: string };
data: {
query?: any;
filter: string;
listName: string;
};
}
export interface BlacklightErrorEvent {

export interface BlacklightErrorEvent extends BlacklightEvent {
type: 'Error' | 'Error.BlacklightInspector' | 'Error.KeyLogging' | 'Error.JsInstrument';
url: string;
stack: any[];
data: {
message: any;
objectName?: string;
Expand All @@ -59,11 +59,6 @@ export interface BlacklightErrorEvent {
};
}

export interface LinkObject {
href: string;
innerHtml: string;
innerText: string;
}
export const SESSION_RECORDERS_LIST = [
'mc.yandex.ru/metrika/watch.js',
'mc.yandex.ru/metrika/tag.js',
Expand All @@ -85,8 +80,10 @@ export const SESSION_RECORDERS_LIST = [
'salemove.com',
'd10lpsik1i8c69.cloudfront.net',
'luckyorange.com',
'vwo.com'
'vwo.com',
'clarity.ms'
];

export const BEHAVIOUR_TRACKING_EVENTS = {
KEYBOARD: ['keydown', 'keypress', 'keyup', 'input'],
MOUSE: ['click', 'mousedown', 'mouseup', 'mousemove', 'select', 'dblclick', 'scroll'],
Expand Down
Loading