Skip to content

Commit

Permalink
List profiles (#13)
Browse files Browse the repository at this point in the history
* list firefox profiles

* rename getPath to getCookiesPath

* working chrome profile listing

* Update index.ts

* fix audit

* add firefox list profiles test

* getpath tests

* list chrome profiles test

* bump
  • Loading branch information
Kalininator committed Oct 2, 2021
1 parent dd60dc5 commit 96908db
Show file tree
Hide file tree
Showing 9 changed files with 836 additions and 677 deletions.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cookie-thief",
"version": "0.6.0",
"version": "0.7.0",
"description": "Steal browser cookies",
"main": "./lib/index.js",
"author": "Alex Kalinin (https://kalinin.uk)",
Expand Down Expand Up @@ -29,6 +29,7 @@
},
"scripts": {
"build": "npm run clean:some && tsc -p .",
"newcov": "jest --coverage --changedSince=master",
"publish-package": "npm run build && npm publish",
"test": "jest",
"test:watch": "jest --watch",
Expand All @@ -42,6 +43,7 @@
"@types/better-sqlite3": "^5.4.3",
"@types/ini": "^1.3.30",
"@types/jest": "^26.0.24",
"@types/mock-fs": "^4.13.1",
"@types/node": "^16.3.1",
"@types/tldjs": "^2.3.1",
"@typescript-eslint/eslint-plugin": "^4.28.2",
Expand All @@ -54,6 +56,7 @@
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.4.0",
"jest": "^27.0.6",
"mock-fs": "^5.1.1",
"prettier": "^2.3.2",
"ts-jest": "^27.0.3",
"ts-node": "^10.1.0",
Expand Down
15 changes: 12 additions & 3 deletions src/chrome/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { existsSync, readdirSync } from 'fs';
import { join } from 'path';
import { Cookie } from '../types';
import { mergeDefaults } from '../utils';
import { ChromeCookieDatabase } from './ChromeCookieDatabase';

import { decrypt, decryptWindows } from './decrypt';
import { getDerivedKey } from './getDerivedKey';
import { getDomain, getIterations, getPath } from './util';
import { getDomain, getIterations, getCookiesPath, getPath } from './util';

const KEYLENGTH = 16;

Expand All @@ -25,7 +27,7 @@ export async function getChromeCookie(
options?: Partial<GetChromeCookiesOptions>,
): Promise<string | undefined> {
const config = mergeDefaults(defaultOptions, options);
const path = getPath(config.profile);
const path = getCookiesPath(config.profile);
const domain = getDomain(url);

const db = new ChromeCookieDatabase(path);
Expand All @@ -48,11 +50,18 @@ export async function getChromeCookie(
throw new Error(`Platform ${process.platform} is not supported`);
}

export async function listChromeProfiles(): Promise<string[]> {
const path = getPath();
return readdirSync(path).filter(
(f) => f !== 'System Profile' && existsSync(join(path, f, 'Preferences')),
);
}

export async function listChromeCookies(
options?: Partial<GetChromeCookiesOptions>,
): Promise<Cookie[]> {
const config = mergeDefaults(defaultOptions, options);
const path = getPath(config.profile);
const path = getCookiesPath(config.profile);
const db = new ChromeCookieDatabase(path);
const cookies = db.listCookies();
const decryptedCookies = await Promise.all(
Expand Down
27 changes: 27 additions & 0 deletions src/chrome/listChromeProfiles.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import mockFs from 'mock-fs';
import { listChromeProfiles } from '.';

jest.mock('../../src/chrome/util', () => ({
getPath: jest.fn().mockReturnValue('some/path'),
}));

describe('list chrome profiles', () => {
it('should return Default', async () => {
mockFs({
'some/path': {
'System Profile': {
Preferences: '',
},
Default: {
Preferences: '',
},
},
});

const profiles = await listChromeProfiles();

expect(profiles).toEqual(['Default']);

mockFs.restore();
});
});
12 changes: 11 additions & 1 deletion src/chrome/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,17 @@ export function getDomain(url: string): string {
throw new Error(`Failed to extract domain from URL ${url}`);
}

export function getPath(profile: string): string {
export function getPath(): string {
if (process.platform === 'darwin')
return `${homedir()}/Library/Application Support/Google/Chrome`;
if (process.platform === 'linux') return `${homedir()}/.config/google-chrome`;
if (process.platform === 'win32')
return `${homedir()}\\AppData\\Local\\Google\\Chrome\\User Data`;

throw new Error(`Platform ${process.platform} is not supported`);
}

export function getCookiesPath(profile: string): string {
if (process.platform === 'darwin')
return `${homedir()}/Library/Application Support/Google/Chrome/${profile}/Cookies`;
if (process.platform === 'linux')
Expand Down
44 changes: 39 additions & 5 deletions src/chrome/util.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { homedir } from 'os';
import { getDomain, getIterations, getPath } from './util';
import { getDomain, getIterations, getCookiesPath, getPath } from './util';
import { mockPlatform, restorePlatform } from '../../test/util';

describe('getDomain', () => {
Expand Down Expand Up @@ -28,31 +28,65 @@ describe('getPath', () => {
it('should get correct windows path', async () => {
mockPlatform('win32');

expect(getPath('Default')).toEqual(
expect(getPath()).toEqual(
`${homedir()}\\AppData\\Local\\Google\\Chrome\\User Data`,
);
});

it('should get correct macos path', async () => {
mockPlatform('darwin');

expect(getPath()).toEqual(
`${homedir()}/Library/Application Support/Google/Chrome`,
);
});

it('should get correct linux path', async () => {
mockPlatform('linux');

expect(getPath()).toEqual(`${homedir()}/.config/google-chrome`);
});

it('should throw if invalid os', () => {
mockPlatform('freebsd');

expect(() => getPath()).toThrow('Platform freebsd is not supported');
});
});

describe('getCookiesPath', () => {
afterEach(() => {
restorePlatform();
});

it('should get correct windows path', async () => {
mockPlatform('win32');

expect(getCookiesPath('Default')).toEqual(
`${homedir()}\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cookies`,
);
});

it('should get correct macos path', async () => {
mockPlatform('darwin');

expect(getPath('Default')).toEqual(
expect(getCookiesPath('Default')).toEqual(
`${homedir()}/Library/Application Support/Google/Chrome/Default/Cookies`,
);
});

it('should get correct linux path', async () => {
mockPlatform('linux');

expect(getPath('Default')).toEqual(
expect(getCookiesPath('Default')).toEqual(
`${homedir()}/.config/google-chrome/Default/Cookies`,
);
});

it('should throw if invalid os', () => {
mockPlatform('freebsd');

expect(() => getPath('Default')).toThrow(
expect(() => getCookiesPath('Default')).toThrow(
'Platform freebsd is not supported',
);
});
Expand Down
4 changes: 4 additions & 0 deletions src/firefox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ const defaultOptions: GetFirefoxCookieOptions = {
profile: 'default-release',
};

export async function listFirefoxProfiles(): Promise<string[]> {
return getProfiles().map((p) => p.Name);
}

/**
* @deprecated Replaced by getCookie
*/
Expand Down
13 changes: 13 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import {
GetChromeCookiesOptions,
getChromeCookie,
listChromeCookies,
listChromeProfiles,
} from './chrome';
import {
GetFirefoxCookieOptions,
getFirefoxCookie,
listFirefoxCookies,
listFirefoxProfiles,
} from './firefox';
import { Cookie } from './types';
import { assertUnreachable } from './utils';
Expand Down Expand Up @@ -75,3 +77,14 @@ export async function listCookies(
return assertUnreachable(config);
}
}

export async function listProfiles(browser: Browser): Promise<string[]> {
switch (browser) {
case Browser.Firefox:
return listFirefoxProfiles();
case Browser.Chrome:
return listChromeProfiles();
default:
return assertUnreachable(browser);
}
}
16 changes: 15 additions & 1 deletion test/firefox.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as sqlite from 'better-sqlite3';
import { homedir } from 'os';
import { getCookie, Browser, listCookies } from '../src';
import { getCookie, Browser, listCookies, listProfiles } from '../src';
import { mockPlatform, restorePlatform } from './util';

jest.mock('fs', () => ({
readFileSync: jest.fn().mockReturnValue(`[Profile1]
Expand Down Expand Up @@ -31,6 +32,19 @@ jest.mock('better-sqlite3', () =>
}),
);

describe('firefox list profiles', () => {
it('should return correct profiles', async () => {
mockPlatform('linux');

expect(await listProfiles(Browser.Firefox)).toEqual([
'default',
'default-release',
]);

restorePlatform();
});
});

describe('firefox get cookie', () => {
describe('macos', () => {
let originalPlatform: any;
Expand Down

0 comments on commit 96908db

Please sign in to comment.