├── .gitignore ├── LICENSE ├── README.md ├── browsers.js ├── history_paths.js ├── index.js ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | yarn.lock 2 | package-lock.json 3 | 4 | \.idea/ 5 | node_modules/ 6 | 7 | yarn-error\.log 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2021, MyOutDesk LLC 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :warning: Deprecation Notice 2 | 3 | As of **2023-12-05**, this repository is no longer actively maintained. 4 | 5 | ## :memo: Details 6 | 7 | We regret to announce that we are deprecating this project and will no longer be providing updates. We will be accepting pull requests, but is not activey maintianed, 8 | 9 | # node-browser-history 10 | 11 | This module will gather browser history from common internet browsers. Given a time frame. 12 | 13 | ## Supported operating systems 14 | 15 | * Windows 16 | * Mac 17 | * Linux (only Firefox and Chrome) 18 | 19 | ## Supported browsers 20 | 21 | | Browser | Windows | Mac | Linux | 22 | | --------------- | ---- | --- | ----- | 23 | | Google Chrome | ✅ | ✅ | ✅ | 24 | | Maxthon | ❌ | ✅ | ❌ | 25 | | Microsoft Edge | ✅ | ✅ | ❌ | 26 | | Mozilla Firefox | ✅ | ✅ | ✅ | 27 | | Opera | ✅ | ✅ | ❌ | 28 | | Seamonkey | ✅ | ✅ | ❌ | 29 | | Torch | ✅ | ❌ | ❌ | 30 | | Vivaldi | ✅ | ✅ | ❌ | 31 | | Brave | ✅ | ✅ | ❌ | 32 | | Avast Browser | ✅ | ✅ | ❌ | 33 | 34 | 35 | # How to Install 36 | 37 | > npm install node-browser-history 38 | 39 | **OR** 40 | 41 | > yarn install node-browser-history 42 | 43 | # Notes 44 | 45 | * You may experience slow downs when dealing with browser that have a larger browser history. 46 | 47 | # How to Use 48 | 49 | ```javascript 50 | const BrowserHistory = require('node-browser-history'); 51 | 52 | 53 | //Only All Support Browser History 54 | 55 | /** 56 | * Gets the history for the Specified browsers and time in minutes. 57 | * Returns an array of browser records. 58 | * @param historyTimeLength | Integer 59 | * @returns {Promise} 60 | */ 61 | getAllHistory(10).then(function (history) { 62 | console.log(history); 63 | }); 64 | 65 | 66 | 67 | /** 68 | * Gets Firefox history 69 | * @param historyTimeLength 70 | * @returns {Promise} 71 | */ 72 | getFirefoxHistory(10).then(function (history) { 73 | console.log(history); 74 | }); 75 | 76 | 77 | /** 78 | * Gets Seamonkey History 79 | * @param historyTimeLength time is in minutes 80 | * @returns {Promise} 81 | */ 82 | getSeaMonkeyHistory(10).then(function (history) { 83 | console.log(history); 84 | }); 85 | 86 | 87 | /** 88 | * Gets Chrome History 89 | * @param historyTimeLength time is in minutes 90 | * @returns {Promise} 91 | */ 92 | getChromeHistory(10).then(function (history) { 93 | console.log(history); 94 | }); 95 | 96 | 97 | /** 98 | * Get Opera History 99 | * @param historyTimeLength time is in minutes 100 | * @returns {Promise} 101 | */ 102 | getOperaHistory(10).then(function (history) { 103 | console.log(history); 104 | }); 105 | 106 | 107 | /** 108 | * Get Torch History 109 | * @param historyTimeLength time is in minutes 110 | * @returns {Promise} 111 | */ 112 | getTorchHistory(10).then(function (history) { 113 | console.log(history); 114 | }); 115 | 116 | 117 | /** 118 | * Get Brave History 119 | * @param historyTimeLength time is in minutes 120 | * @returns {Promise} 121 | */ 122 | getBraveHistory(10).then(function (history) { 123 | console.log(history); 124 | }); 125 | 126 | 127 | /** 128 | * Get Maxthon History 129 | * @param historyTimeLength time is in minutes 130 | * @returns {Promise} 131 | */ 132 | getMaxthonHistory(10).then(function (history) { 133 | console.log(history); 134 | }); 135 | 136 | /** 137 | * Get Vivaldi History 138 | * @param historyTimeLength time is in minutes 139 | * @returns {Promise} 140 | */ 141 | getVivaldiHistory(10).then(function (history) { 142 | console.log(history); 143 | }); 144 | 145 | ``` 146 | -------------------------------------------------------------------------------- /browsers.js: -------------------------------------------------------------------------------- 1 | const Path = require('path') 2 | const fs = require("fs"); 3 | const { setupDefaultPaths: setupPaths } = require('./history_paths'); 4 | 5 | const CHROME = "Google Chrome", 6 | FIREFOX = "Mozilla Firefox", 7 | TORCH = "Torch", 8 | OPERA = "Opera", 9 | SEAMONKEY = "SeaMonkey", 10 | VIVALDI = "Vivaldi", 11 | MAXTHON = "Maxthon", 12 | EDGE = "Microsoft Edge", 13 | BRAVE = "Brave", 14 | AVAST = "AVAST Browser"; 15 | 16 | let browserDbLocations = { 17 | chrome: "", 18 | firefox: "", 19 | opera: "", 20 | edge: "", 21 | torch: "", 22 | seamonkey: "", 23 | vivaldi: "", 24 | maxthon: "", 25 | brave: "", 26 | avast: "" 27 | }; 28 | 29 | 30 | let defaultPaths = setupPaths(); 31 | 32 | /** 33 | * Find all files recursively in specific folder with specific extension, e.g: 34 | * findFilesInDir('./project/src', '.html') ==> ['./project/src/a.html','./project/src/build/index.html'] 35 | * @param {String} startPath Path relative to this file or other file which requires this files 36 | * @param {String} filter Extension name, e.g: '.html' 37 | * @param targetFile 38 | * @param depth 39 | * @return {Array} Result files with path string in an array 40 | */ 41 | function findFilesInDir(startPath, filter, targetFile, depth = 0) { 42 | if(depth === 4){ 43 | return []; 44 | } 45 | let results = []; 46 | if (!fs.existsSync(startPath)) { 47 | //console.log("no dir ", startPath); 48 | return results; 49 | } 50 | let files = fs.readdirSync(startPath); 51 | for (let i = 0; i < files.length; i++) { 52 | let filename = Path.join(startPath, files[i]); 53 | if (!fs.existsSync(filename)) { 54 | // console.log('file doesn\'t exist ', startPath); 55 | continue; 56 | } 57 | let stat = fs.lstatSync(filename); 58 | if (stat.isDirectory()) { 59 | results = results.concat(findFilesInDir(filename, filter, targetFile, depth + 1)); //recurse 60 | } else if(filename.endsWith(targetFile) === true) { 61 | // console.log('-- found: ', filename); 62 | results.push(filename); 63 | } 64 | /* 65 | } else if (filename.indexOf(filter) >= 0 && regExp.test(filename)) { 66 | results.push(filename); 67 | } else if (filename.endsWith('\\History') === true) { 68 | // console.log('-- found: ', filename); 69 | results.push(filename); 70 | }*/ 71 | } 72 | return results; 73 | } 74 | 75 | 76 | 77 | /** 78 | * Finds the path to the browsers DB file. 79 | * Returns an array of strings, paths, or an empty array 80 | * @param path 81 | * @param browserName 82 | * @returns {Array} 83 | */ 84 | function findPaths(path, browserName) { 85 | switch (browserName) { 86 | case FIREFOX: 87 | case SEAMONKEY: 88 | return findFilesInDir(path, ".sqlite", Path.sep + 'places.sqlite'); 89 | case CHROME: 90 | case TORCH: 91 | case OPERA: 92 | case BRAVE: 93 | case VIVALDI: 94 | case EDGE: 95 | case AVAST: 96 | return findFilesInDir(path, "History", Path.sep + 'History'); 97 | case MAXTHON: 98 | return findFilesInDir(path, ".dat", Path.sep + 'History.dat'); 99 | default: 100 | return []; 101 | } 102 | } 103 | 104 | module.exports = { 105 | findPaths, 106 | browserDbLocations, 107 | defaultPaths, 108 | CHROME, 109 | FIREFOX, 110 | TORCH, 111 | OPERA, 112 | SEAMONKEY, 113 | VIVALDI, 114 | MAXTHON, 115 | BRAVE, 116 | EDGE, 117 | AVAST 118 | }; 119 | 120 | -------------------------------------------------------------------------------- /history_paths.js: -------------------------------------------------------------------------------- 1 | const Path = require('path'); 2 | 3 | const homeDirectory = process.env.HOME; 4 | 5 | function setupForWindows() { 6 | let defaultPaths = {} 7 | 8 | const appDataDirectory = Path.join(process.env.HOMEDRIVE, "Users", process.env.USERNAME, "AppData"); 9 | 10 | defaultPaths.chrome = Path.join(appDataDirectory, "Local", "Google", "Chrome"); 11 | defaultPaths.avast = Path.join(appDataDirectory, "Local", "Google", "AVAST Software"); 12 | defaultPaths.firefox = Path.join(appDataDirectory, "Roaming", "Mozilla", "Firefox"); 13 | defaultPaths.opera = Path.join(appDataDirectory, "Roaming", "Opera Software"); 14 | defaultPaths.edge = Path.join(appDataDirectory, "Local", "Microsoft", "Edge"); 15 | defaultPaths.torch = Path.join(appDataDirectory, "Local", "Torch", "User Data"); 16 | defaultPaths.seamonkey = Path.join(appDataDirectory, "Roaming", "Mozilla", "SeaMonkey"); 17 | defaultPaths.brave = Path.join(appDataDirectory, "Local", "BraveSoftware", "Brave-Browser", "User Data"); 18 | defaultPaths.vivaldi = Path.join(appDataDirectory, "Local", "Vivaldi", "User Data"); 19 | return defaultPaths 20 | } 21 | 22 | function setupForMac() { 23 | let defaultPaths = {} 24 | defaultPaths.chrome = Path.join(homeDirectory, "Library", "Application Support", "Google", "Chrome"); 25 | defaultPaths.avast = Path.join(homeDirectory, "Library", "Application Support", "AVAST Software", "Browser"); 26 | defaultPaths.firefox = Path.join(homeDirectory, "Library", "Application Support", "Firefox"); 27 | defaultPaths.edge = Path.join(homeDirectory, "Library", "Application Support", "Microsoft Edge"); 28 | defaultPaths.opera = Path.join(homeDirectory, "Library", "Application Support", "com.operasoftware.Opera"); 29 | defaultPaths.maxthon = Path.join(homeDirectory, "Library", "Application Support", "com.maxthon.mac.Maxthon"); 30 | defaultPaths.vivaldi = Path.join(homeDirectory, "Library", "Application Support", "Vivaldi"); 31 | defaultPaths.seamonkey = Path.join(homeDirectory, "Library", "Application Support", "SeaMonkey", "Profiles"); 32 | defaultPaths.brave = Path.join(homeDirectory, "Library", "Application Support", "BraveSoftware", "Brave-Browser"); 33 | return defaultPaths; 34 | } 35 | 36 | function setupForLinux() { 37 | let defaultPaths = {} 38 | defaultPaths.firefox = Path.join(homeDirectory, ".mozilla", "firefox"); 39 | defaultPaths.chrome = Path.join(homeDirectory, ".config", "google-chrome"); 40 | return defaultPaths 41 | } 42 | 43 | function setupDefaultPaths(defaultPaths) { 44 | switch (process.platform) { 45 | case 'darwin': 46 | return setupForMac(defaultPaths); 47 | case 'linux': 48 | return setupForLinux(defaultPaths); 49 | case 'win32': 50 | return setupForWindows(defaultPaths); 51 | default: 52 | console.error(`Platform ${process.platform} is not supported by node-browser-history`); 53 | } 54 | } 55 | 56 | module.exports = { 57 | setupDefaultPaths 58 | }; 59 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const fs = require("fs"); 3 | const Database = require("sqlite-async"); 4 | const uuidV4 = require("uuid").v4; 5 | 6 | const browsers = require("./browsers"); 7 | const { tmpdir } = require("os"); 8 | 9 | /** 10 | * Get the path to the temp directory of 11 | * the current platform. 12 | */ 13 | function getTempDir() { 14 | return process.env.TMP || process.env.TMPDIR || tmpdir(); 15 | } 16 | 17 | /** 18 | * Runs the the proper function for the given browser. Some browsers follow the same standards as 19 | * chrome and firefox others have their own syntax. 20 | * Returns an empty array or an array of browser record objects 21 | * @param paths 22 | * @param browserName 23 | * @param historyTimeLength 24 | * @returns {Promise} 25 | */ 26 | async function getBrowserHistory(paths = [], browserName, historyTimeLength) { 27 | switch (browserName) { 28 | case browsers.FIREFOX: 29 | case browsers.SEAMONKEY: 30 | return getMozillaBasedBrowserRecords(paths, browserName, historyTimeLength); 31 | case browsers.CHROME: 32 | case browsers.OPERA: 33 | case browsers.TORCH: 34 | case browsers.VIVALDI: 35 | case browsers.BRAVE: 36 | case browsers.EDGE: 37 | case browsers.AVAST: 38 | return await getChromeBasedBrowserRecords(paths, browserName, historyTimeLength); 39 | 40 | case browsers.MAXTHON: 41 | return await getMaxthonBasedBrowserRecords(paths, browserName, historyTimeLength); 42 | default: 43 | return []; 44 | } 45 | } 46 | 47 | async function getHistoryFromDb(dbPath, sql, browserName) { 48 | const db = await Database.open(dbPath); 49 | const rows = await db.all(sql); 50 | let browserHistory = rows.map(row => { 51 | return { 52 | title: row.title, 53 | utc_time: row.last_visit_time, 54 | url: row.url, 55 | browser: browserName, 56 | }; 57 | }); 58 | await db.close(); 59 | return browserHistory; 60 | } 61 | 62 | function copyDbAndWalFile(dbPath, fileExtension = 'sqlite') { 63 | const newDbPath = path.join(getTempDir(), uuidV4() + `.${fileExtension}`); 64 | const filePaths = {}; 65 | filePaths.db = newDbPath; 66 | filePaths.dbWal = `${newDbPath}-wal`; 67 | fs.copyFileSync(dbPath, filePaths.db); 68 | fs.copyFileSync(dbPath, filePaths.dbWal); 69 | return filePaths; 70 | } 71 | 72 | async function forceWalFileDump(tmpDbPath) { 73 | const db = await Database.open(tmpDbPath); 74 | 75 | // If the browser uses a wal file we need to create a wal file with the same filename as our temp database. 76 | await db.run("PRAGMA wal_checkpoint(FULL)"); 77 | await db.close(); 78 | } 79 | 80 | function deleteTempFiles(paths) { 81 | paths.forEach(path => { 82 | fs.unlinkSync(path); 83 | }); 84 | } 85 | 86 | async function getChromeBasedBrowserRecords(paths, browserName, historyTimeLength) { 87 | if (!paths || paths.length === 0) { 88 | return []; 89 | } 90 | let newDbPaths = []; 91 | let browserHistory = []; 92 | for (let i = 0; i < paths.length; i++) { 93 | let newDbPath = path.join(getTempDir(), uuidV4() + ".sqlite"); 94 | newDbPaths.push(newDbPath); 95 | let sql = `SELECT title, datetime(last_visit_time/1000000 + (strftime('%s', '1601-01-01')),'unixepoch') last_visit_time, url from urls WHERE DATETIME (last_visit_time/1000000 + (strftime('%s', '1601-01-01')), 'unixepoch') >= DATETIME('now', '-${historyTimeLength} minutes') group by title, last_visit_time order by last_visit_time`; 96 | //Assuming the sqlite file is locked so lets make a copy of it 97 | fs.copyFileSync(paths[i], newDbPath); 98 | browserHistory.push(await getHistoryFromDb(newDbPath, sql, browserName)); 99 | } 100 | deleteTempFiles(newDbPaths); 101 | return browserHistory; 102 | } 103 | 104 | async function getMozillaBasedBrowserRecords(paths, browserName, historyTimeLength) { 105 | if (!paths || paths.length === 0) { 106 | return []; 107 | } 108 | let newDbPaths = []; 109 | let browserHistory = []; 110 | for (let i = 0; i < paths.length; i++) { 111 | const tmpFilePaths = copyDbAndWalFile(paths[i]); 112 | console.log(tmpFilePaths) 113 | newDbPaths.push(tmpFilePaths.db); 114 | let sql = `SELECT title, datetime(last_visit_date/1000000,'unixepoch') last_visit_time, url from moz_places WHERE DATETIME (last_visit_date/1000000, 'unixepoch') >= DATETIME('now', '-${historyTimeLength} minutes') group by title, last_visit_time order by last_visit_time`; 115 | await forceWalFileDump(tmpFilePaths.db); 116 | browserHistory.push(await getHistoryFromDb(tmpFilePaths.db, sql, browserName)); 117 | } 118 | deleteTempFiles(newDbPaths); 119 | return browserHistory; 120 | 121 | } 122 | 123 | 124 | async function getMaxthonBasedBrowserRecords(paths, browserName, historyTimeLength) { 125 | let browserHistory = []; 126 | for (let i = 0; i < paths.length; i++) { 127 | let sql = `SELECT zlastvisittime last_visit_time, zhost host, ztitle title, zurl url FROM zmxhistoryentry WHERE Datetime (zlastvisittime + 978307200, 'unixepoch') >= Datetime('now', '-${historyTimeLength} minutes')`; 128 | browserHistory.push(await getHistoryFromDb(paths[i], sql, browserName)); 129 | } 130 | return browserHistory; 131 | } 132 | 133 | /** 134 | * Gets Firefox history 135 | * @param historyTimeLength time is in minutes 136 | * @returns {Promise} 137 | */ 138 | async function getFirefoxHistory(historyTimeLength = 5) { 139 | browsers.browserDbLocations.firefox = browsers.findPaths(browsers.defaultPaths.firefox, browsers.FIREFOX); 140 | return getBrowserHistory(browsers.browserDbLocations.firefox, browsers.FIREFOX, historyTimeLength).then(records => { 141 | return records; 142 | }); 143 | } 144 | 145 | /** 146 | * Gets Seamonkey History 147 | * @param historyTimeLength time is in minutes 148 | * @returns {Promise} 149 | */ 150 | function getSeaMonkeyHistory(historyTimeLength = 5) { 151 | browsers.browserDbLocations.seamonkey = browsers.findPaths(browsers.defaultPaths.seamonkey, browsers.SEAMONKEY); 152 | return getBrowserHistory(browsers.browserDbLocations.seamonkey, browsers.SEAMONKEY, historyTimeLength).then(records => { 153 | return records; 154 | }); 155 | } 156 | 157 | /** 158 | * Gets Chrome History 159 | * @param historyTimeLength time is in minutes 160 | * @returns {Promise} 161 | */ 162 | async function getChromeHistory(historyTimeLength = 5) { 163 | browsers.browserDbLocations.chrome = browsers.findPaths(browsers.defaultPaths.chrome, browsers.CHROME); 164 | return getBrowserHistory(browsers.browserDbLocations.chrome, browsers.CHROME, historyTimeLength).then(records => { 165 | return records; 166 | }); 167 | } 168 | 169 | /** 170 | * Get Opera History 171 | * @param historyTimeLength time is in minutes 172 | * @returns {Promise} 173 | */ 174 | async function getOperaHistory(historyTimeLength = 5) { 175 | browsers.browserDbLocations.opera = browsers.findPaths(browsers.defaultPaths.opera, browsers.OPERA); 176 | return getBrowserHistory(browsers.browserDbLocations.opera, browsers.OPERA, historyTimeLength).then(records => { 177 | return records; 178 | }); 179 | } 180 | 181 | /** 182 | * Get Torch History 183 | * @param historyTimeLength time is in minutes 184 | * @returns {Promise} 185 | */ 186 | async function getTorchHistory(historyTimeLength = 5) { 187 | browsers.browserDbLocations.torch = browsers.findPaths(browsers.defaultPaths.torch, browsers.TORCH); 188 | return getBrowserHistory(browsers.browserDbLocations.torch, browsers.TORCH, historyTimeLength).then(records => { 189 | return records; 190 | }); 191 | } 192 | 193 | /** 194 | * Get Brave History 195 | * @param historyTimeLength time is in minutes 196 | * @returns {Promise} 197 | */ 198 | async function getBraveHistory(historyTimeLength = 5) { 199 | browsers.browserDbLocations.brave = browsers.findPaths(browsers.defaultPaths.brave, browsers.BRAVE); 200 | return getBrowserHistory(browsers.browserDbLocations.brave, browsers.BRAVE, historyTimeLength).then(records => { 201 | return records; 202 | }); 203 | } 204 | 205 | /** 206 | * Get Maxthon History 207 | * @param historyTimeLength time is in minutes 208 | * @returns {Promise} 209 | */ 210 | async function getMaxthonHistory(historyTimeLength = 5) { 211 | browsers.browserDbLocations.maxthon = browsers.findPaths(browsers.defaultPaths.maxthon, browsers.MAXTHON); 212 | return getBrowserHistory(browsers.browserDbLocations.maxthon, browsers.MAXTHON, historyTimeLength).then(records => { 213 | return records; 214 | }); 215 | } 216 | 217 | /** 218 | * Get Vivaldi History 219 | * @param historyTimeLength time is in minutes 220 | * @returns {Promise} 221 | */ 222 | async function getVivaldiHistory(historyTimeLength = 5) { 223 | browsers.browserDbLocations.vivaldi = browsers.findPaths(browsers.defaultPaths.vivaldi, browsers.VIVALDI); 224 | return getBrowserHistory(browsers.browserDbLocations.vivaldi, browsers.VIVALDI, historyTimeLength).then(records => { 225 | return records; 226 | }); 227 | } 228 | 229 | /** 230 | * Get AVAST Browser History 231 | * @param historyTimeLength 232 | * @return {Promise} 233 | */ 234 | async function getAvastHistory(historyTimeLength = 5) { 235 | browsers.browserDbLocations.avast = browsers.findPaths(browsers.defaultPaths.avast, browsers.AVAST); 236 | return getBrowserHistory(browsers.browserDbLocations.avast, browsers.AVAST, historyTimeLength).then(records => { 237 | return records; 238 | }); 239 | } 240 | 241 | /** 242 | * Get Microsoft Edge History 243 | * @param historyTimeLength time is in minutes 244 | * @returns {Promise} 245 | */ 246 | async function getMicrosoftEdge(historyTimeLength = 5) { 247 | browsers.browserDbLocations.edge = browsers.findPaths(browsers.defaultPaths.edge, browsers.EDGE); 248 | return getBrowserHistory(browsers.browserDbLocations.edge, browsers.EDGE, historyTimeLength).then(records => { 249 | return records; 250 | }); 251 | } 252 | 253 | /** 254 | * Gets the history for the Specified browsers and time in minutes. 255 | * Returns an array of browser records. 256 | * @param historyTimeLength | Integer 257 | * @returns {Promise} 258 | */ 259 | async function getAllHistory(historyTimeLength = 5) { 260 | let allBrowserRecords = []; 261 | 262 | browsers.browserDbLocations.firefox = browsers.findPaths(browsers.defaultPaths.firefox, browsers.FIREFOX); 263 | browsers.browserDbLocations.chrome = browsers.findPaths(browsers.defaultPaths.chrome, browsers.CHROME); 264 | browsers.browserDbLocations.seamonkey = browsers.findPaths(browsers.defaultPaths.seamonkey, browsers.SEAMONKEY); 265 | browsers.browserDbLocations.opera = browsers.findPaths(browsers.defaultPaths.opera, browsers.OPERA); 266 | browsers.browserDbLocations.torch = browsers.findPaths(browsers.defaultPaths.torch, browsers.TORCH); 267 | browsers.browserDbLocations.brave = browsers.findPaths(browsers.defaultPaths.brave, browsers.BRAVE); 268 | browsers.browserDbLocations.seamonkey = browsers.findPaths(browsers.defaultPaths.seamonkey, browsers.SEAMONKEY); 269 | browsers.browserDbLocations.maxthon = browsers.findPaths(browsers.defaultPaths.maxthon, browsers.MAXTHON); 270 | browsers.browserDbLocations.vivaldi = browsers.findPaths(browsers.defaultPaths.vivaldi, browsers.VIVALDI); 271 | browsers.browserDbLocations.edge = browsers.findPaths(browsers.defaultPaths.edge, browsers.EDGE); 272 | browsers.browserDbLocations.avast = browsers.findPaths(browsers.defaultPaths.avast, browsers.AVAST); 273 | 274 | allBrowserRecords = allBrowserRecords.concat(await getBrowserHistory(browsers.browserDbLocations.firefox, browsers.FIREFOX, historyTimeLength)); 275 | allBrowserRecords = allBrowserRecords.concat(await getBrowserHistory(browsers.browserDbLocations.seamonkey, browsers.SEAMONKEY, historyTimeLength)); 276 | allBrowserRecords = allBrowserRecords.concat(await getBrowserHistory(browsers.browserDbLocations.chrome, browsers.CHROME, historyTimeLength)); 277 | allBrowserRecords = allBrowserRecords.concat(await getBrowserHistory(browsers.browserDbLocations.opera, browsers.OPERA, historyTimeLength)); 278 | allBrowserRecords = allBrowserRecords.concat(await getBrowserHistory(browsers.browserDbLocations.torch, browsers.TORCH, historyTimeLength)); 279 | allBrowserRecords = allBrowserRecords.concat(await getBrowserHistory(browsers.browserDbLocations.brave, browsers.BRAVE, historyTimeLength)); 280 | allBrowserRecords = allBrowserRecords.concat(await getBrowserHistory(browsers.browserDbLocations.vivaldi, browsers.VIVALDI, historyTimeLength)); 281 | allBrowserRecords = allBrowserRecords.concat(await getBrowserHistory(browsers.browserDbLocations.seamonkey, browsers.SEAMONKEY, historyTimeLength)); 282 | allBrowserRecords = allBrowserRecords.concat(await getBrowserHistory(browsers.browserDbLocations.maxthon, browsers.MAXTHON, historyTimeLength)); 283 | allBrowserRecords = allBrowserRecords.concat(await getBrowserHistory(browsers.browserDbLocations.edge, browsers.EDGE, historyTimeLength)); 284 | allBrowserRecords = allBrowserRecords.concat(await getBrowserHistory(browsers.browserDbLocations.avast, browsers.EDGE, historyTimeLength)); 285 | //No Path because this is handled by the dll 286 | 287 | return allBrowserRecords; 288 | } 289 | 290 | module.exports = { 291 | getAllHistory, 292 | getFirefoxHistory, 293 | getSeaMonkeyHistory, 294 | getChromeHistory, 295 | getOperaHistory, 296 | getTorchHistory, 297 | getBraveHistory, 298 | getMaxthonHistory, 299 | getVivaldiHistory, 300 | getMicrosoftEdge, 301 | getAvastHistory 302 | }; 303 | 304 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-browser-history", 3 | "version": "3.0.0", 4 | "description": "This application aims to retrieve browser history from all browsers on the user's computer. It will attempt to read from some common locations.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node test.js" 8 | }, 9 | "engine": { 10 | "node": "12" 11 | }, 12 | "build": { 13 | "extraResources": [], 14 | "win": { 15 | "extraResources": [] 16 | }, 17 | "osx": { 18 | "extraResources": [] 19 | } 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/MyOutDeskLLC/node-browser-history.git" 24 | }, 25 | "keywords": [ 26 | "browser", 27 | "history" 28 | ], 29 | "author": "Lance Thompson", 30 | "license": "ISC", 31 | "bugs": { 32 | "url": "https://github.com/MyOutDeskLLC/node-browser-history/issues" 33 | }, 34 | "homepage": "https://github.com/MyOutDeskLLC/node-browser-history#readme", 35 | "dependencies": { 36 | "sqlite-async": "github:tance77/sqlite-async", 37 | "uuid": "^8.1.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | let history = require("./index"); 2 | 3 | function testGetAllHistory() { 4 | console.log("***** RUNNING GET ALL HISTORY TEST *****"); 5 | return new Promise(res => { 6 | history.getAllHistory(60).then(browsers => { 7 | history = [] 8 | for(let browser of browsers){ 9 | for(let record of browser){ 10 | history.push(record) 11 | } 12 | } 13 | console.log("PASS GET ALL HISTORY"); 14 | console.log(history); 15 | res(history); 16 | }).catch(error => { 17 | console.log("***** FAILED TO GET ALL HISTORY *****"); 18 | return Promise.reject(error); 19 | }); 20 | }); 21 | } 22 | 23 | function testGetChromeOnly() { 24 | console.log("***** RUNNING GET CHROME ONLY *****"); 25 | return new Promise(res => { 26 | history.getChromeHistory(180).then(history => { 27 | console.log("PASS GET CHROME ONLY"); 28 | console.log(history); 29 | res(history); 30 | }).catch(error => { 31 | console.log("***** FAIL TO GET CHROME ONLY *****"); 32 | return Promise.reject(error); 33 | }); 34 | }); 35 | } 36 | 37 | function testFireFoxOnly() { 38 | console.log("***** RUNNING GET FIREFOX ONLY *****"); 39 | return new Promise(res => { 40 | history.getFirefoxHistory(180).then(history => { 41 | console.log("PASS GET FIREFOX ONLY"); 42 | console.log(history); 43 | res(history); 44 | }).catch(error => { 45 | console.log("***** FAIL TO GET FIREFOX ONLY *****"); 46 | return Promise.reject(error); 47 | }); 48 | }); 49 | } 50 | 51 | function testAvastOnly() { 52 | console.log("***** RUNNING GET AVAST ONLY *****"); 53 | return new Promise(res => { 54 | history.getAvastHistory(180).then(history => { 55 | console.log(history); 56 | console.log("PASS AVAST ONLY"); 57 | res(history); 58 | }).catch(error => { 59 | console.log("***** FAIL TO GET AVAST ONLY *****"); 60 | return Promise.reject(error); 61 | }); 62 | }); 63 | } 64 | 65 | function testOperaOnly() { 66 | console.log("***** RUNNING GET OPERA ONLY *****"); 67 | return new Promise(res => { 68 | history.getOperaHistory(60).then(history => { 69 | console.log("PASS GET OPERA ONLY"); 70 | console.log(history); 71 | res(history); 72 | }).catch(error => { 73 | console.log("***** FAIL TO GET OPERA ONLY *****"); 74 | return Promise.reject(error); 75 | }); 76 | }); 77 | } 78 | 79 | function testSeaMonkeyOnly() { 80 | console.log("***** RUNNING GET SEAMONKEY ONLY *****"); 81 | return new Promise(res => { 82 | history.getSeaMonkeyHistory(60).then(history => { 83 | console.log("PASS GET SEAMONKEY ONLY"); 84 | console.log(history); 85 | res(history); 86 | }).catch(error => { 87 | console.log("***** FAIL TO GET SEAMONKEY ONLY *****"); 88 | return Promise.reject(error); 89 | }); 90 | }); 91 | } 92 | 93 | function testVivaldiOnly() { 94 | console.log("***** RUNNING GET VIVALDI ONLY *****"); 95 | return new Promise(res => { 96 | history.getVivaldiHistory(60).then(history => { 97 | console.log("PASS GET VIVALDI ONLY"); 98 | console.log(history); 99 | res(history); 100 | }).catch(error => { 101 | console.log("***** FAIL TO GET VIVALDI ONLY *****"); 102 | return Promise.reject(error); 103 | }); 104 | }); 105 | } 106 | 107 | function testMaxthonOnly() { 108 | console.log("***** RUNNING GET MAXTHON ONLY *****"); 109 | return new Promise(res => { 110 | history.getMaxthonHistory(60).then(history => { 111 | console.log("PASS GET MAXTHON ONLY"); 112 | console.log(history); 113 | res(history); 114 | }).catch(error => { 115 | console.log("***** FAIL TO GET MAXTHON ONLY *****"); 116 | return Promise.reject(error); 117 | }); 118 | }); 119 | } 120 | 121 | function testInternetExplorerOnly() { 122 | if (process.platform !== "win32") { 123 | console.log("Internet explorer not supported on Mac"); 124 | return; 125 | } 126 | console.log("***** RUNNING GET INTERNET EXPLORER ONLY *****"); 127 | return new Promise(res => { 128 | history.getIEHistory(60).then(history => { 129 | console.log("PASS GET INTERNET EXPLORER ONLY"); 130 | console.log(history); 131 | res(history); 132 | }).catch(error => { 133 | console.log("***** FAIL TO GET INTERNET EXPLORER ONLY *****"); 134 | return Promise.reject(error); 135 | }); 136 | }); 137 | } 138 | 139 | function testTorchOnly() { 140 | console.log("***** RUNNING GET TORCH ONLY *****"); 141 | return new Promise(res => { 142 | history.getTorchHistory(60).then(history => { 143 | console.log("PASS GET TORCH ONLY"); 144 | console.log(history); 145 | res(history); 146 | }).catch(error => { 147 | console.log("***** FAIL TO GET TORCH ONLY *****"); 148 | return Promise.reject(error); 149 | }); 150 | }); 151 | } 152 | 153 | function testBraveOnly() { 154 | console.log("***** RUNNING GET BRAVE ONLY *****"); 155 | return new Promise(res => { 156 | history.getBraveHistory(180).then(history => { 157 | console.log("PASS GET BRAVE ONLY"); 158 | console.log(history); 159 | res(history); 160 | }).catch(error => { 161 | console.log("***** FAIL TO GET BRAVE ONLY *****"); 162 | return Promise.reject(error); 163 | }); 164 | }); 165 | } 166 | 167 | function testMicrosoftEdgeOnly() { 168 | console.log("***** RUNNING GET MICROSOFT EDGE ONLY *****"); 169 | return new Promise(res => { 170 | history.getMicrosoftEdge(180).then(history => { 171 | console.log("PASS GET MICROSOFT EDGE ONLY"); 172 | console.log(history); 173 | res(history); 174 | }).catch(error => { 175 | console.log("***** FAIL TO GET MICROSOFT EDGE ONLY *****"); 176 | return Promise.reject(error); 177 | }); 178 | }); 179 | } 180 | 181 | 182 | let tests = [ 183 | // testGetChromeOnly(), 184 | // testFireFoxOnly(), 185 | // testBraveOnly(), 186 | // testOperaOnly(), 187 | // testSeaMonkeyOnly(), 188 | // testMaxthonOnly(), 189 | // testVivaldiOnly(), 190 | // testAvastOnly(), 191 | // testMicrosoftEdgeOnly(), 192 | // testSafariOnly(), 193 | // testTorchOnly(), 194 | testGetAllHistory(), 195 | ]; 196 | 197 | Promise.all(tests).then(() => { 198 | console.log("PASSING ALL TESTS"); 199 | process.exit(0); 200 | }).catch(error => { 201 | console.log('kasjdlasdjlaskdjalskdj') 202 | console.log(error) 203 | process.exit(error); 204 | }); 205 | 206 | // testGetAllHistory() 207 | 208 | // setInterval(()=>{ 209 | // testGetAllHistory(); 210 | // },2000) 211 | 212 | 213 | 214 | 215 | --------------------------------------------------------------------------------