chrome-tools 1.1.6 → 1.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +556 -1
- package/dist/src/core/browsers.d.ts +7 -3
- package/dist/src/core/browsers.js +186 -1
- package/dist/src/core/chrome.d.ts +6 -4
- package/dist/src/core/chrome.js +240 -1
- package/dist/src/core/crypto.d.ts +1 -1
- package/dist/src/core/crypto.js +113 -1
- package/dist/src/core/db.d.ts +4 -2
- package/dist/src/core/db.js +90 -1
- package/dist/src/core/keychain.js +191 -1
- package/dist/src/core/limit.d.ts +4 -0
- package/dist/src/core/limit.js +12 -0
- package/dist/src/core/platform/darwin.js +31 -1
- package/dist/src/core/platform/index.d.ts +4 -3
- package/dist/src/core/platform/index.js +69 -1
- package/dist/src/core/platform/linux.js +64 -1
- package/dist/src/core/platform/types.d.ts +3 -2
- package/dist/src/core/platform/types.js +1 -1
- package/dist/src/core/platform/win32.js +114 -1
- package/dist/src/core/sql.d.ts +2 -0
- package/dist/src/core/sql.js +4 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +34 -1
- package/dist/src/modules/autofill.d.ts +7 -15
- package/dist/src/modules/autofill.js +170 -1
- package/dist/src/modules/bookmarks.d.ts +3 -5
- package/dist/src/modules/bookmarks.js +83 -1
- package/dist/src/modules/cookies.d.ts +3 -5
- package/dist/src/modules/cookies.js +157 -1
- package/dist/src/modules/downloads.d.ts +3 -5
- package/dist/src/modules/downloads.js +80 -1
- package/dist/src/modules/extensions.d.ts +3 -5
- package/dist/src/modules/extensions.js +71 -1
- package/dist/src/modules/history.d.ts +5 -10
- package/dist/src/modules/history.js +83 -1
- package/dist/src/modules/local-storage.d.ts +3 -5
- package/dist/src/modules/local-storage.js +455 -1
- package/dist/src/modules/passwords.d.ts +3 -5
- package/dist/src/modules/passwords.js +131 -1
- package/dist/src/modules/search-engines.d.ts +3 -5
- package/dist/src/modules/search-engines.js +38 -1
- package/dist/src/modules/top-sites.d.ts +3 -5
- package/dist/src/modules/top-sites.js +33 -1
- package/package.json +14 -12
|
@@ -1 +1,80 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { resolveTargetProfiles } from "../core/chrome.js";
|
|
3
|
+
import { chromeTimeToDate } from "../core/crypto.js";
|
|
4
|
+
import { queryDatabase } from "../core/db.js";
|
|
5
|
+
import { limitResults, normalizeLimit } from "../core/limit.js";
|
|
6
|
+
import { sqlLikePattern } from "../core/sql.js";
|
|
7
|
+
/** Maps Chrome download state integers to human-readable strings. */
|
|
8
|
+
const DOWNLOAD_STATES = {
|
|
9
|
+
0: "in_progress",
|
|
10
|
+
1: "complete",
|
|
11
|
+
2: "cancelled",
|
|
12
|
+
3: "interrupted",
|
|
13
|
+
};
|
|
14
|
+
/** Maps Chrome download danger type integers to strings. */
|
|
15
|
+
const DANGER_TYPES = {
|
|
16
|
+
0: "not_dangerous",
|
|
17
|
+
1: "dangerous_file",
|
|
18
|
+
2: "dangerous_url",
|
|
19
|
+
3: "dangerous_content",
|
|
20
|
+
4: "maybe_dangerous_content",
|
|
21
|
+
5: "uncommon_content",
|
|
22
|
+
6: "user_validated",
|
|
23
|
+
7: "dangerous_host",
|
|
24
|
+
8: "potentially_unwanted",
|
|
25
|
+
9: "allowlisted_by_policy",
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Retrieves download history from Chrome's History database.
|
|
29
|
+
*
|
|
30
|
+
* @param options - Targeting, filtering, and limit options.
|
|
31
|
+
* @returns Array of download entries.
|
|
32
|
+
*/
|
|
33
|
+
export function getDownloads({ chromeDir, profilePath, profile, browser, search, limit = 100, } = {}) {
|
|
34
|
+
const profiles = resolveTargetProfiles({ chromeDir, profilePath, profile, browser });
|
|
35
|
+
const results = [];
|
|
36
|
+
const rowLimit = normalizeLimit(limit);
|
|
37
|
+
for (const p of profiles) {
|
|
38
|
+
const dbPath = join(p.path, "History");
|
|
39
|
+
try {
|
|
40
|
+
// Apply search in SQL before LIMIT so older matches are not truncated away.
|
|
41
|
+
let sql = `SELECT target_path, tab_url, total_bytes, received_bytes,
|
|
42
|
+
start_time, end_time, mime_type, original_mime_type,
|
|
43
|
+
state, danger_type, opened, referrer, site_url
|
|
44
|
+
FROM downloads`;
|
|
45
|
+
const params = [];
|
|
46
|
+
if (search) {
|
|
47
|
+
sql += ` WHERE IFNULL(target_path, '') LIKE ? ESCAPE '\\'
|
|
48
|
+
OR IFNULL(tab_url, '') LIKE ? ESCAPE '\\'`;
|
|
49
|
+
const like = sqlLikePattern(search);
|
|
50
|
+
params.push(like, like);
|
|
51
|
+
}
|
|
52
|
+
sql += ` ORDER BY start_time DESC`;
|
|
53
|
+
if (rowLimit) {
|
|
54
|
+
sql += ` LIMIT ${rowLimit}`;
|
|
55
|
+
}
|
|
56
|
+
const rows = queryDatabase(dbPath, sql, params);
|
|
57
|
+
for (const row of rows) {
|
|
58
|
+
results.push({
|
|
59
|
+
profile: p.name,
|
|
60
|
+
targetPath: row.target_path || "",
|
|
61
|
+
url: row.tab_url || "",
|
|
62
|
+
siteUrl: row.site_url || "",
|
|
63
|
+
referrer: row.referrer || "",
|
|
64
|
+
totalBytes: row.total_bytes || 0,
|
|
65
|
+
receivedBytes: row.received_bytes || 0,
|
|
66
|
+
mimeType: row.mime_type || row.original_mime_type || "",
|
|
67
|
+
state: DOWNLOAD_STATES[row.state] || `unknown(${row.state})`,
|
|
68
|
+
dangerType: DANGER_TYPES[row.danger_type] || `unknown(${row.danger_type})`,
|
|
69
|
+
opened: Boolean(row.opened),
|
|
70
|
+
startTime: chromeTimeToDate(row.start_time || 0),
|
|
71
|
+
endTime: chromeTimeToDate(row.end_time || 0),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Skip profiles with errors
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return limitResults(results, limit);
|
|
80
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
profile?: string;
|
|
4
|
-
browser?: string;
|
|
1
|
+
import { type ResolveProfilesOptions } from "../core/chrome.js";
|
|
2
|
+
export interface ExtensionOptions extends ResolveProfilesOptions {
|
|
5
3
|
search?: string;
|
|
6
4
|
}
|
|
7
5
|
export interface ExtensionEntry {
|
|
@@ -23,4 +21,4 @@ export interface ExtensionEntry {
|
|
|
23
21
|
* @param options - Targeting and filtering options.
|
|
24
22
|
* @returns Array of extension entries.
|
|
25
23
|
*/
|
|
26
|
-
export declare function getExtensions({ chromeDir, profile, search, browser }?: ExtensionOptions): ExtensionEntry[];
|
|
24
|
+
export declare function getExtensions({ chromeDir, profilePath, profile, search, browser, }?: ExtensionOptions): ExtensionEntry[];
|
|
@@ -1 +1,71 @@
|
|
|
1
|
-
import{existsSync
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { resolveTargetProfiles } from "../core/chrome.js";
|
|
4
|
+
/**
|
|
5
|
+
* Retrieves installed Chrome extensions from the Preferences JSON file.
|
|
6
|
+
*
|
|
7
|
+
* @param options - Targeting and filtering options.
|
|
8
|
+
* @returns Array of extension entries.
|
|
9
|
+
*/
|
|
10
|
+
export function getExtensions({ chromeDir, profilePath, profile, search, browser, } = {}) {
|
|
11
|
+
const profiles = resolveTargetProfiles({ chromeDir, profilePath, profile, browser });
|
|
12
|
+
const results = [];
|
|
13
|
+
for (const p of profiles) {
|
|
14
|
+
// Prefer Secure Preferences, but continue to Preferences if it has no settings.
|
|
15
|
+
let settings = null;
|
|
16
|
+
for (const filename of ["Secure Preferences", "Preferences"]) {
|
|
17
|
+
const prefsPath = join(p.path, filename);
|
|
18
|
+
if (existsSync(prefsPath)) {
|
|
19
|
+
try {
|
|
20
|
+
const prefs = JSON.parse(readFileSync(prefsPath, "utf-8"));
|
|
21
|
+
const candidate = prefs?.extensions?.settings;
|
|
22
|
+
if (candidate && typeof candidate === "object") {
|
|
23
|
+
settings = candidate;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (!settings)
|
|
33
|
+
continue;
|
|
34
|
+
for (const [extId, extDataAny] of Object.entries(settings)) {
|
|
35
|
+
const extData = extDataAny;
|
|
36
|
+
// Skip component extensions and internal Chrome extensions
|
|
37
|
+
if (extData.location === 5 || extData.location === 10)
|
|
38
|
+
continue;
|
|
39
|
+
const manifest = extData.manifest || {};
|
|
40
|
+
const entry = {
|
|
41
|
+
profile: p.name,
|
|
42
|
+
id: extId,
|
|
43
|
+
name: manifest.name || extData.name || extId,
|
|
44
|
+
version: manifest.version || extData.version || "unknown",
|
|
45
|
+
description: manifest.description || "",
|
|
46
|
+
enabled: extData.state === 1,
|
|
47
|
+
homepageUrl: manifest.homepage_url || "",
|
|
48
|
+
updateUrl: manifest.update_url || "",
|
|
49
|
+
installTime: extData.install_time || "",
|
|
50
|
+
fromWebstore: extData.from_webstore || false,
|
|
51
|
+
location: extData.location || 0,
|
|
52
|
+
};
|
|
53
|
+
// Clean up __MSG_ placeholders in name/description
|
|
54
|
+
if (entry.name.startsWith("__MSG_")) {
|
|
55
|
+
entry.name = extId; // Fallback to ID if name is a message key
|
|
56
|
+
}
|
|
57
|
+
if (entry.description.startsWith("__MSG_")) {
|
|
58
|
+
entry.description = "";
|
|
59
|
+
}
|
|
60
|
+
if (search) {
|
|
61
|
+
const term = search.toLowerCase();
|
|
62
|
+
if (!(entry.name && entry.name.toLowerCase().includes(term)) &&
|
|
63
|
+
!(entry.id && entry.id.toLowerCase().includes(term))) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
results.push(entry);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return results;
|
|
71
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
profile?: string;
|
|
4
|
-
browser?: string;
|
|
1
|
+
import { type ResolveProfilesOptions } from "../core/chrome.js";
|
|
2
|
+
export interface HistoryOptions extends ResolveProfilesOptions {
|
|
5
3
|
search?: string;
|
|
6
4
|
limit?: number;
|
|
7
5
|
}
|
|
@@ -12,10 +10,7 @@ export interface HistoryEntry {
|
|
|
12
10
|
visitCount: number;
|
|
13
11
|
lastVisit: string;
|
|
14
12
|
}
|
|
15
|
-
export interface SearchTermOptions {
|
|
16
|
-
chromeDir?: string;
|
|
17
|
-
profile?: string;
|
|
18
|
-
browser?: string;
|
|
13
|
+
export interface SearchTermOptions extends ResolveProfilesOptions {
|
|
19
14
|
limit?: number;
|
|
20
15
|
}
|
|
21
16
|
export interface SearchTermEntry {
|
|
@@ -29,11 +24,11 @@ export interface SearchTermEntry {
|
|
|
29
24
|
* @param options - Filtering and targeting options.
|
|
30
25
|
* @returns Array of history entries.
|
|
31
26
|
*/
|
|
32
|
-
export declare function getHistory({ chromeDir, profile, search, limit, browser }?: HistoryOptions): HistoryEntry[];
|
|
27
|
+
export declare function getHistory({ chromeDir, profilePath, profile, search, limit, browser, }?: HistoryOptions): HistoryEntry[];
|
|
33
28
|
/**
|
|
34
29
|
* Retrieves search terms from Chrome's History database.
|
|
35
30
|
*
|
|
36
31
|
* @param options - Targeting and limit options.
|
|
37
32
|
* @returns Array of search term entries.
|
|
38
33
|
*/
|
|
39
|
-
export declare function getSearchTerms({ chromeDir, profile, limit, browser }?: SearchTermOptions): SearchTermEntry[];
|
|
34
|
+
export declare function getSearchTerms({ chromeDir, profilePath, profile, limit, browser, }?: SearchTermOptions): SearchTermEntry[];
|
|
@@ -1 +1,83 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { resolveTargetProfiles } from "../core/chrome.js";
|
|
3
|
+
import { chromeTimeToDate } from "../core/crypto.js";
|
|
4
|
+
import { queryDatabase } from "../core/db.js";
|
|
5
|
+
import { limitResults, normalizeLimit } from "../core/limit.js";
|
|
6
|
+
import { sqlLikePattern } from "../core/sql.js";
|
|
7
|
+
/**
|
|
8
|
+
* Retrieves browsing history from Chrome's History database.
|
|
9
|
+
*
|
|
10
|
+
* @param options - Filtering and targeting options.
|
|
11
|
+
* @returns Array of history entries.
|
|
12
|
+
*/
|
|
13
|
+
export function getHistory({ chromeDir, profilePath, profile, search, limit = 100, browser, } = {}) {
|
|
14
|
+
const profiles = resolveTargetProfiles({ chromeDir, profilePath, profile, browser });
|
|
15
|
+
const results = [];
|
|
16
|
+
const rowLimit = normalizeLimit(limit);
|
|
17
|
+
for (const p of profiles) {
|
|
18
|
+
const dbPath = join(p.path, "History");
|
|
19
|
+
try {
|
|
20
|
+
// Apply search in SQL before LIMIT so older matches are not truncated away.
|
|
21
|
+
let sql = `SELECT url, title, visit_count, last_visit_time FROM urls`;
|
|
22
|
+
const params = [];
|
|
23
|
+
if (search) {
|
|
24
|
+
sql += ` WHERE url LIKE ? ESCAPE '\\' OR IFNULL(title, '') LIKE ? ESCAPE '\\'`;
|
|
25
|
+
const like = sqlLikePattern(search);
|
|
26
|
+
params.push(like, like);
|
|
27
|
+
}
|
|
28
|
+
sql += ` ORDER BY last_visit_time DESC`;
|
|
29
|
+
if (rowLimit) {
|
|
30
|
+
sql += ` LIMIT ${rowLimit}`;
|
|
31
|
+
}
|
|
32
|
+
const rows = queryDatabase(dbPath, sql, params);
|
|
33
|
+
for (const row of rows) {
|
|
34
|
+
results.push({
|
|
35
|
+
profile: p.name,
|
|
36
|
+
url: row.url,
|
|
37
|
+
title: row.title || "",
|
|
38
|
+
visitCount: row.visit_count || 0,
|
|
39
|
+
lastVisit: chromeTimeToDate(row.last_visit_time || 0),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Skip profiles with errors
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return limitResults(results, limit);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Retrieves search terms from Chrome's History database.
|
|
51
|
+
*
|
|
52
|
+
* @param options - Targeting and limit options.
|
|
53
|
+
* @returns Array of search term entries.
|
|
54
|
+
*/
|
|
55
|
+
export function getSearchTerms({ chromeDir, profilePath, profile, limit = 100, browser, } = {}) {
|
|
56
|
+
const profiles = resolveTargetProfiles({ chromeDir, profilePath, profile, browser });
|
|
57
|
+
const results = [];
|
|
58
|
+
const rowLimit = normalizeLimit(limit);
|
|
59
|
+
for (const p of profiles) {
|
|
60
|
+
const dbPath = join(p.path, "History");
|
|
61
|
+
try {
|
|
62
|
+
let sql = `SELECT kst.term, u.url
|
|
63
|
+
FROM keyword_search_terms kst
|
|
64
|
+
JOIN urls u ON kst.url_id = u.id
|
|
65
|
+
ORDER BY u.last_visit_time DESC`;
|
|
66
|
+
if (rowLimit) {
|
|
67
|
+
sql += ` LIMIT ${rowLimit}`;
|
|
68
|
+
}
|
|
69
|
+
const rows = queryDatabase(dbPath, sql);
|
|
70
|
+
for (const row of rows) {
|
|
71
|
+
results.push({
|
|
72
|
+
profile: p.name,
|
|
73
|
+
term: row.term || "",
|
|
74
|
+
url: row.url || "",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Skip profiles with errors
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return limitResults(results, limit);
|
|
83
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
profile?: string;
|
|
4
|
-
browser?: string;
|
|
1
|
+
import { type ResolveProfilesOptions } from "../core/chrome.js";
|
|
2
|
+
export interface LocalStorageOptions extends ResolveProfilesOptions {
|
|
5
3
|
origin?: string;
|
|
6
4
|
url?: string;
|
|
7
5
|
key?: string;
|
|
@@ -26,7 +24,7 @@ interface RawLevelDBRecord {
|
|
|
26
24
|
* @param options - Targeting and filtering options.
|
|
27
25
|
* @returns Array of localStorage entries.
|
|
28
26
|
*/
|
|
29
|
-
export declare function getLocalStorage({ chromeDir, profile, browser, origin, url, key, search, limit, }?: LocalStorageOptions): LocalStorageEntry[];
|
|
27
|
+
export declare function getLocalStorage({ chromeDir, profilePath, profile, browser, origin, url, key, search, limit, }?: LocalStorageOptions): LocalStorageEntry[];
|
|
30
28
|
declare function parseLocalStorageRecord(rawKey: Buffer, rawValue: Buffer): {
|
|
31
29
|
origin: string;
|
|
32
30
|
key: string;
|