brave-real-launcher 1.2.32 → 1.2.34
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/.github/workflows/chrome-launcher-sync.yml +2 -2
- package/README.md +75 -100
- package/dist/brave-installer.d.ts +57 -0
- package/dist/brave-installer.js +352 -0
- package/dist/brave-installer.mjs +323 -0
- package/dist/brave-launcher.d.ts +21 -0
- package/dist/brave-launcher.js +207 -15
- package/dist/brave-launcher.mjs +207 -15
- package/dist/extension-manager.d.ts +58 -0
- package/dist/extension-manager.js +333 -0
- package/dist/extension-manager.mjs +304 -0
- package/dist/flags.js +15 -1
- package/dist/flags.mjs +15 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +15 -2
- package/dist/index.mjs +7 -1
- package/dist/stealth-utils.d.ts +128 -0
- package/dist/stealth-utils.js +210 -0
- package/dist/stealth-utils.mjs +206 -0
- package/package.json +1 -1
- package/console.log(ESM build works!))' +0 -0
- package/workflow-test-report.md +0 -44
|
@@ -3,8 +3,8 @@ name: Chrome Launcher Sync & Publish
|
|
|
3
3
|
on:
|
|
4
4
|
# Automatic triggers
|
|
5
5
|
schedule:
|
|
6
|
-
#
|
|
7
|
-
- cron: '0 6 * *
|
|
6
|
+
# Daily trigger - Every day at 6 AM UTC (11:30 AM IST)
|
|
7
|
+
- cron: '0 6 * * *'
|
|
8
8
|
|
|
9
9
|
# Manual trigger
|
|
10
10
|
workflow_dispatch:
|
package/README.md
CHANGED
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
Launch Brave Browser with ease from Node.js. Based on [chrome-launcher](https://github.com/GoogleChrome/chrome-launcher) but specifically adapted for Brave Browser with additional features.
|
|
4
4
|
|
|
5
|
-
## Features
|
|
5
|
+
## ✨ Features
|
|
6
6
|
|
|
7
7
|
- 🦁 **Brave Browser Detection**: Automatically detects Brave Browser installations across all platforms
|
|
8
8
|
- 🖥️ **Multi-Platform Support**: Linux (x64/ARM64), macOS (Intel/Apple Silicon), Windows (x64/ARM64)
|
|
9
9
|
- 🐧 **Xvfb Support**: Built-in Xvfb support for headless operation on Linux
|
|
10
10
|
- 🎯 **Launch Modes**: Headless mode, GUI mode, or automatic detection
|
|
11
11
|
- 🔄 **Auto-Sync**: Automatically syncs with chrome-launcher updates while preserving Brave-specific features
|
|
12
|
-
-
|
|
12
|
+
- 📦 **uBlock Origin**: Automatic download and loading of uBlock Origin ad blocker
|
|
13
|
+
- 🛡️ **Stealth Mode**: Anti-bot-detection capabilities for automation
|
|
14
|
+
- ⬇️ **Auto-Install**: Automatically install Brave if not present (Windows/Linux/macOS)
|
|
15
|
+
- 🔇 **P3A Disabled**: Private analytics notifications disabled by default
|
|
13
16
|
|
|
14
17
|
## Installation
|
|
15
18
|
|
|
@@ -17,23 +20,6 @@ Launch Brave Browser with ease from Node.js. Based on [chrome-launcher](https://
|
|
|
17
20
|
npm install brave-real-launcher
|
|
18
21
|
```
|
|
19
22
|
|
|
20
|
-
## Quick Start
|
|
21
|
-
|
|
22
|
-
```javascript
|
|
23
|
-
const { launch } = require('brave-real-launcher');
|
|
24
|
-
|
|
25
|
-
// Launch Brave in headless mode
|
|
26
|
-
const brave = await launch({
|
|
27
|
-
braveFlags: ['--headless', '--disable-gpu'],
|
|
28
|
-
logLevel: 'info'
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
console.log('Brave is running on port', brave.port);
|
|
32
|
-
|
|
33
|
-
// Kill Brave
|
|
34
|
-
brave.kill();
|
|
35
|
-
```
|
|
36
|
-
|
|
37
23
|
## API
|
|
38
24
|
|
|
39
25
|
### `launch(options)`
|
|
@@ -41,116 +27,105 @@ brave.kill();
|
|
|
41
27
|
Launches Brave Browser with the specified options.
|
|
42
28
|
|
|
43
29
|
**Options:**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
30
|
+
|
|
31
|
+
| Option | Type | Default | Description |
|
|
32
|
+
|--------|------|---------|-------------|
|
|
33
|
+
| `bravePath` | `string` | auto-detected | Path to Brave executable |
|
|
34
|
+
| `braveFlags` | `string[]` | `[]` | Array of Brave flags to pass |
|
|
35
|
+
| `startingUrl` | `string` | `about:blank` | URL to navigate to on start |
|
|
36
|
+
| `port` | `number` | random | Debug port |
|
|
37
|
+
| `userDataDir` | `string\|boolean` | temp dir | User data directory |
|
|
38
|
+
| `launchMode` | `'auto'\|'headless'\|'gui'` | `'auto'` | Launch mode |
|
|
39
|
+
| `enableXvfb` | `boolean` | `false` | Enable Xvfb on Linux |
|
|
40
|
+
| `autoLoadUBlock` | `boolean` | `false` | Auto-load uBlock Origin |
|
|
41
|
+
| `enableStealth` | `boolean` | `false` | Enable stealth mode |
|
|
42
|
+
| `autoInstall` | `boolean` | `false` | Auto-install Brave if not found |
|
|
43
|
+
| `userAgent` | `string` | default | Custom user agent |
|
|
44
|
+
| `logLevel` | `'verbose'\|'info'\|'error'\|'silent'` | `'silent'` | Log level |
|
|
45
|
+
|
|
46
|
+
**Returns:** `LaunchedBrave` object with:
|
|
47
|
+
- `pid`: Process ID
|
|
48
|
+
- `port`: Debug port
|
|
49
|
+
- `process`: Child process
|
|
50
|
+
- `extensions`: Loaded extensions info
|
|
51
|
+
- `kill()`: Function to kill browser
|
|
53
52
|
|
|
54
53
|
### `getBravePath()`
|
|
55
54
|
|
|
56
55
|
Returns the path to the Brave Browser executable.
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Manages Xvfb virtual display for headless environments.
|
|
61
|
-
|
|
62
|
-
```javascript
|
|
63
|
-
const { XvfbManager } = require('brave-real-launcher');
|
|
57
|
+
## Platform Support
|
|
64
58
|
|
|
65
|
-
|
|
66
|
-
display: ':99',
|
|
67
|
-
width: 1920,
|
|
68
|
-
height: 1080
|
|
69
|
-
});
|
|
59
|
+
### Auto-Install Behavior
|
|
70
60
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
61
|
+
| Platform | Method | Skip if Installed |
|
|
62
|
+
|----------|--------|-------------------|
|
|
63
|
+
| **Windows** | Downloads installer, runs silently | ✅ Yes |
|
|
64
|
+
| **Linux** | apt/dnf/yum/pacman | ✅ Yes |
|
|
65
|
+
| **macOS** | Downloads DMG, mounts & copies | ✅ Yes |
|
|
75
66
|
|
|
76
|
-
|
|
67
|
+
### Path Detection
|
|
77
68
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
|
|
69
|
+
| Platform | Detection Paths |
|
|
70
|
+
|----------|-----------------|
|
|
71
|
+
| **Windows** | `%LOCALAPPDATA%\BraveSoftware\...`, `%PROGRAMFILES%\...` |
|
|
72
|
+
| **Linux** | `/usr/bin/brave-browser`, `/opt/brave.com/brave/...`, Flatpak, Snap |
|
|
73
|
+
| **macOS** | `/Applications/Brave Browser.app/...` |
|
|
83
74
|
|
|
84
|
-
|
|
85
|
-
- Intel and Apple Silicon (M1/M2) support
|
|
86
|
-
- Detects Brave Browser, Brave Browser Beta, Nightly, and Dev versions
|
|
87
|
-
- Standard installation paths in `/Applications/`
|
|
75
|
+
## Testing
|
|
88
76
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
- Standard installation paths in Program Files and Local AppData
|
|
77
|
+
```bash
|
|
78
|
+
# Install dependencies
|
|
79
|
+
npm install
|
|
93
80
|
|
|
94
|
-
|
|
81
|
+
# Build project
|
|
82
|
+
npm run build
|
|
95
83
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
- `DISPLAY`: X11 display (Linux)
|
|
84
|
+
# Run tests
|
|
85
|
+
npm test
|
|
99
86
|
|
|
100
|
-
|
|
87
|
+
# Test Brave detection
|
|
88
|
+
npm run test:detection
|
|
101
89
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const brave = await launch({
|
|
105
|
-
launchMode: 'headless',
|
|
106
|
-
enableXvfb: true,
|
|
107
|
-
xvfbOptions: { width: 1920, height: 1080 }
|
|
108
|
-
});
|
|
90
|
+
# Test with uBlock Origin
|
|
91
|
+
node -e "const {launch} = require('./dist'); launch({autoLoadUBlock:true, startingUrl:'https://example.com', logLevel:'info'}).then(b => setTimeout(() => b.kill(), 5000))"
|
|
109
92
|
```
|
|
110
93
|
|
|
111
|
-
|
|
112
|
-
```javascript
|
|
113
|
-
const brave = await launch({
|
|
114
|
-
braveFlags: [
|
|
115
|
-
'--no-sandbox',
|
|
116
|
-
'--disable-dev-shm-usage',
|
|
117
|
-
'--disable-gpu'
|
|
118
|
-
]
|
|
119
|
-
});
|
|
120
|
-
```
|
|
94
|
+
## Environment Variables
|
|
121
95
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
});
|
|
128
|
-
```
|
|
96
|
+
| Variable | Description |
|
|
97
|
+
|----------|-------------|
|
|
98
|
+
| `BRAVE_PATH` | Path to Brave executable |
|
|
99
|
+
| `HEADLESS` | Force headless mode when set |
|
|
100
|
+
| `DISPLAY` | X11 display (Linux) |
|
|
129
101
|
|
|
130
102
|
## Development
|
|
131
103
|
|
|
132
|
-
### Building
|
|
133
|
-
|
|
134
104
|
```bash
|
|
135
|
-
|
|
136
|
-
|
|
105
|
+
# Clone repository
|
|
106
|
+
git clone https://github.com/user/brave-real-launcher.git
|
|
107
|
+
cd brave-real-launcher
|
|
137
108
|
|
|
138
|
-
|
|
109
|
+
# Install dependencies
|
|
110
|
+
npm install
|
|
139
111
|
|
|
140
|
-
|
|
141
|
-
npm
|
|
112
|
+
# Build
|
|
113
|
+
npm run build
|
|
114
|
+
|
|
115
|
+
# Run CI tests
|
|
116
|
+
npm run test:ci
|
|
142
117
|
```
|
|
143
118
|
|
|
144
119
|
## Auto-Sync with chrome-launcher
|
|
145
120
|
|
|
146
|
-
This project automatically syncs with chrome-launcher updates while preserving Brave-specific functionality
|
|
121
|
+
This project automatically syncs with chrome-launcher updates while preserving Brave-specific functionality:
|
|
147
122
|
|
|
148
|
-
- Checks for chrome-launcher updates daily
|
|
149
|
-
- Automatically integrates compatible changes
|
|
150
|
-
- Preserves Brave-specific browser detection
|
|
151
|
-
- Runs comprehensive tests
|
|
152
|
-
- Publishes
|
|
123
|
+
- ✅ Checks for chrome-launcher updates **daily**
|
|
124
|
+
- ✅ Automatically integrates compatible changes
|
|
125
|
+
- ✅ Preserves Brave-specific browser detection
|
|
126
|
+
- ✅ Runs comprehensive tests
|
|
127
|
+
- ✅ Publishes to npm automatically
|
|
153
128
|
|
|
154
129
|
## License
|
|
155
130
|
|
|
156
|
-
Apache-2.0 - Based on chrome-launcher by The Chromium Authors
|
|
131
|
+
Apache-2.0 - Based on chrome-launcher by The Chromium Authors
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface InstallerOptions {
|
|
2
|
+
silent?: boolean;
|
|
3
|
+
downloadDir?: string;
|
|
4
|
+
channel?: 'release' | 'beta' | 'nightly';
|
|
5
|
+
}
|
|
6
|
+
export interface InstallResult {
|
|
7
|
+
success: boolean;
|
|
8
|
+
bravePath?: string;
|
|
9
|
+
error?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class BraveInstaller {
|
|
12
|
+
private silent;
|
|
13
|
+
private downloadDir;
|
|
14
|
+
private channel;
|
|
15
|
+
constructor(options?: InstallerOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Install Brave browser on the current platform
|
|
18
|
+
*/
|
|
19
|
+
install(): Promise<InstallResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Install Brave on Windows
|
|
22
|
+
*/
|
|
23
|
+
private installWindows;
|
|
24
|
+
/**
|
|
25
|
+
* Install Brave on Linux
|
|
26
|
+
*/
|
|
27
|
+
private installLinux;
|
|
28
|
+
/**
|
|
29
|
+
* Install Brave on macOS
|
|
30
|
+
*/
|
|
31
|
+
private installMacOS;
|
|
32
|
+
/**
|
|
33
|
+
* Download file from URL
|
|
34
|
+
*/
|
|
35
|
+
private downloadFile;
|
|
36
|
+
/**
|
|
37
|
+
* Detect Linux package manager
|
|
38
|
+
*/
|
|
39
|
+
private detectLinuxPackageManager;
|
|
40
|
+
/**
|
|
41
|
+
* Find Brave on Windows
|
|
42
|
+
*/
|
|
43
|
+
private findBraveWindows;
|
|
44
|
+
/**
|
|
45
|
+
* Find Brave on Linux
|
|
46
|
+
*/
|
|
47
|
+
private findBraveLinux;
|
|
48
|
+
/**
|
|
49
|
+
* Delay helper
|
|
50
|
+
*/
|
|
51
|
+
private delay;
|
|
52
|
+
/**
|
|
53
|
+
* Check if Brave is installed
|
|
54
|
+
*/
|
|
55
|
+
static isInstalled(): boolean;
|
|
56
|
+
}
|
|
57
|
+
export default BraveInstaller;
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright 2024 Brave Real Launcher Contributors.
|
|
3
|
+
* Licensed under the Apache License, Version 2.0
|
|
4
|
+
*
|
|
5
|
+
* Brave Browser Installer
|
|
6
|
+
* Auto-installs Brave browser on Windows, Linux, and macOS
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
26
|
+
if (mod && mod.__esModule) return mod;
|
|
27
|
+
var result = {};
|
|
28
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
29
|
+
__setModuleDefault(result, mod);
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
33
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
34
|
+
};
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.BraveInstaller = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const https = __importStar(require("https"));
|
|
40
|
+
const http = __importStar(require("http"));
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
42
|
+
const os_1 = require("os");
|
|
43
|
+
const logger_js_1 = __importDefault(require("./logger.js"));
|
|
44
|
+
const utils_js_1 = require("./utils.js");
|
|
45
|
+
const BRAVE_DOWNLOAD_URLS = {
|
|
46
|
+
win32: {
|
|
47
|
+
release: 'https://laptop-updates.brave.com/latest/winx64',
|
|
48
|
+
beta: 'https://laptop-updates.brave.com/latest/winx64-beta',
|
|
49
|
+
nightly: 'https://laptop-updates.brave.com/latest/winx64-nightly'
|
|
50
|
+
},
|
|
51
|
+
darwin: {
|
|
52
|
+
release: 'https://laptop-updates.brave.com/latest/osx',
|
|
53
|
+
beta: 'https://laptop-updates.brave.com/latest/osx-beta',
|
|
54
|
+
nightly: 'https://laptop-updates.brave.com/latest/osx-nightly'
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
class BraveInstaller {
|
|
58
|
+
constructor(options = {}) {
|
|
59
|
+
this.silent = options.silent || false;
|
|
60
|
+
this.downloadDir = options.downloadDir || path.join((0, os_1.homedir)(), '.brave-real-launcher', 'downloads');
|
|
61
|
+
this.channel = options.channel || 'release';
|
|
62
|
+
if (!fs.existsSync(this.downloadDir)) {
|
|
63
|
+
fs.mkdirSync(this.downloadDir, { recursive: true });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Install Brave browser on the current platform
|
|
68
|
+
*/
|
|
69
|
+
async install() {
|
|
70
|
+
const platform = (0, utils_js_1.getPlatform)();
|
|
71
|
+
if (!this.silent) {
|
|
72
|
+
logger_js_1.default.log('BraveInstaller', `Installing Brave Browser on ${platform}...`);
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
switch (platform) {
|
|
76
|
+
case 'win32':
|
|
77
|
+
return await this.installWindows();
|
|
78
|
+
case 'linux':
|
|
79
|
+
return await this.installLinux();
|
|
80
|
+
case 'darwin':
|
|
81
|
+
return await this.installMacOS();
|
|
82
|
+
default:
|
|
83
|
+
return { success: false, error: `Unsupported platform: ${platform}` };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
return { success: false, error: error.message };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Install Brave on Windows
|
|
92
|
+
*/
|
|
93
|
+
async installWindows() {
|
|
94
|
+
const installerPath = path.join(this.downloadDir, 'BraveBrowserSetup.exe');
|
|
95
|
+
const downloadUrl = BRAVE_DOWNLOAD_URLS.win32[this.channel];
|
|
96
|
+
if (!this.silent) {
|
|
97
|
+
logger_js_1.default.log('BraveInstaller', 'Downloading Brave installer for Windows...');
|
|
98
|
+
}
|
|
99
|
+
// Download installer
|
|
100
|
+
await this.downloadFile(downloadUrl, installerPath);
|
|
101
|
+
if (!this.silent) {
|
|
102
|
+
logger_js_1.default.log('BraveInstaller', 'Running Brave installer (silent mode)...');
|
|
103
|
+
}
|
|
104
|
+
// Run installer silently
|
|
105
|
+
try {
|
|
106
|
+
(0, child_process_1.execSync)(`"${installerPath}" /silent /install`, {
|
|
107
|
+
stdio: 'ignore',
|
|
108
|
+
timeout: 300000 // 5 minutes timeout
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
// Try alternative silent flags
|
|
113
|
+
try {
|
|
114
|
+
(0, child_process_1.execSync)(`"${installerPath}" --system-level --do-not-launch-chrome`, {
|
|
115
|
+
stdio: 'ignore',
|
|
116
|
+
timeout: 300000
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
// Installation might still succeed, continue checking
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Wait for installation to complete
|
|
124
|
+
await this.delay(5000);
|
|
125
|
+
// Find Brave installation
|
|
126
|
+
const bravePath = this.findBraveWindows();
|
|
127
|
+
if (bravePath) {
|
|
128
|
+
if (!this.silent) {
|
|
129
|
+
logger_js_1.default.log('BraveInstaller', `Brave installed successfully at: ${bravePath}`);
|
|
130
|
+
}
|
|
131
|
+
// Cleanup installer
|
|
132
|
+
try {
|
|
133
|
+
fs.unlinkSync(installerPath);
|
|
134
|
+
}
|
|
135
|
+
catch (e) { }
|
|
136
|
+
return { success: true, bravePath };
|
|
137
|
+
}
|
|
138
|
+
return { success: false, error: 'Installation completed but Brave not found' };
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Install Brave on Linux
|
|
142
|
+
*/
|
|
143
|
+
async installLinux() {
|
|
144
|
+
if (!this.silent) {
|
|
145
|
+
logger_js_1.default.log('BraveInstaller', 'Installing Brave on Linux...');
|
|
146
|
+
}
|
|
147
|
+
// Detect package manager
|
|
148
|
+
const packageManager = this.detectLinuxPackageManager();
|
|
149
|
+
try {
|
|
150
|
+
if (packageManager === 'apt') {
|
|
151
|
+
// Debian/Ubuntu based
|
|
152
|
+
(0, child_process_1.execSync)('sudo apt install -y curl', { stdio: 'ignore' });
|
|
153
|
+
(0, child_process_1.execSync)('sudo curl -fsSLo /usr/share/keyrings/brave-browser-archive-keyring.gpg https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg', { stdio: 'ignore' });
|
|
154
|
+
(0, child_process_1.execSync)('echo "deb [signed-by=/usr/share/keyrings/brave-browser-archive-keyring.gpg] https://brave-browser-apt-release.s3.brave.com/ stable main" | sudo tee /etc/apt/sources.list.d/brave-browser-release.list', { stdio: 'ignore' });
|
|
155
|
+
(0, child_process_1.execSync)('sudo apt update', { stdio: 'ignore' });
|
|
156
|
+
(0, child_process_1.execSync)('sudo apt install -y brave-browser', { stdio: 'ignore' });
|
|
157
|
+
}
|
|
158
|
+
else if (packageManager === 'dnf' || packageManager === 'yum') {
|
|
159
|
+
// Fedora/RHEL based
|
|
160
|
+
(0, child_process_1.execSync)('sudo dnf install -y dnf-plugins-core', { stdio: 'ignore' });
|
|
161
|
+
(0, child_process_1.execSync)('sudo dnf config-manager --add-repo https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo', { stdio: 'ignore' });
|
|
162
|
+
(0, child_process_1.execSync)('sudo rpm --import https://brave-browser-rpm-release.s3.brave.com/brave-core.asc', { stdio: 'ignore' });
|
|
163
|
+
(0, child_process_1.execSync)('sudo dnf install -y brave-browser', { stdio: 'ignore' });
|
|
164
|
+
}
|
|
165
|
+
else if (packageManager === 'pacman') {
|
|
166
|
+
// Arch based
|
|
167
|
+
(0, child_process_1.execSync)('yay -S --noconfirm brave-bin', { stdio: 'ignore' });
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
return { success: false, error: `Unsupported package manager. Please install Brave manually.` };
|
|
171
|
+
}
|
|
172
|
+
// Find Brave installation
|
|
173
|
+
const bravePath = this.findBraveLinux();
|
|
174
|
+
if (bravePath) {
|
|
175
|
+
if (!this.silent) {
|
|
176
|
+
logger_js_1.default.log('BraveInstaller', `Brave installed successfully at: ${bravePath}`);
|
|
177
|
+
}
|
|
178
|
+
return { success: true, bravePath };
|
|
179
|
+
}
|
|
180
|
+
return { success: false, error: 'Installation completed but Brave not found' };
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
return { success: false, error: `Linux installation failed: ${error.message}` };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Install Brave on macOS
|
|
188
|
+
*/
|
|
189
|
+
async installMacOS() {
|
|
190
|
+
var _a;
|
|
191
|
+
const dmgPath = path.join(this.downloadDir, 'Brave-Browser.dmg');
|
|
192
|
+
const downloadUrl = BRAVE_DOWNLOAD_URLS.darwin[this.channel];
|
|
193
|
+
if (!this.silent) {
|
|
194
|
+
logger_js_1.default.log('BraveInstaller', 'Downloading Brave for macOS...');
|
|
195
|
+
}
|
|
196
|
+
// Download DMG
|
|
197
|
+
await this.downloadFile(downloadUrl, dmgPath);
|
|
198
|
+
if (!this.silent) {
|
|
199
|
+
logger_js_1.default.log('BraveInstaller', 'Installing Brave...');
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
// Mount DMG
|
|
203
|
+
const mountOutput = (0, child_process_1.execSync)(`hdiutil attach "${dmgPath}" -nobrowse`, { encoding: 'utf-8' });
|
|
204
|
+
const mountPoint = ((_a = mountOutput.split('\t').pop()) === null || _a === void 0 ? void 0 : _a.trim()) || '/Volumes/Brave Browser';
|
|
205
|
+
// Copy to Applications
|
|
206
|
+
(0, child_process_1.execSync)(`cp -R "${mountPoint}/Brave Browser.app" /Applications/`, { stdio: 'ignore' });
|
|
207
|
+
// Unmount DMG
|
|
208
|
+
(0, child_process_1.execSync)(`hdiutil detach "${mountPoint}"`, { stdio: 'ignore' });
|
|
209
|
+
// Cleanup
|
|
210
|
+
try {
|
|
211
|
+
fs.unlinkSync(dmgPath);
|
|
212
|
+
}
|
|
213
|
+
catch (e) { }
|
|
214
|
+
const bravePath = '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser';
|
|
215
|
+
if (fs.existsSync(bravePath)) {
|
|
216
|
+
if (!this.silent) {
|
|
217
|
+
logger_js_1.default.log('BraveInstaller', `Brave installed successfully at: ${bravePath}`);
|
|
218
|
+
}
|
|
219
|
+
return { success: true, bravePath };
|
|
220
|
+
}
|
|
221
|
+
return { success: false, error: 'Installation completed but Brave not found' };
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
return { success: false, error: `macOS installation failed: ${error.message}` };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Download file from URL
|
|
229
|
+
*/
|
|
230
|
+
downloadFile(url, destPath) {
|
|
231
|
+
return new Promise((resolve, reject) => {
|
|
232
|
+
const followRedirect = (url, redirectCount = 0) => {
|
|
233
|
+
if (redirectCount > 10) {
|
|
234
|
+
reject(new Error('Too many redirects'));
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const protocol = url.startsWith('https') ? https : http;
|
|
238
|
+
protocol.get(url, {
|
|
239
|
+
headers: { 'User-Agent': 'brave-real-launcher' }
|
|
240
|
+
}, (response) => {
|
|
241
|
+
if (response.statusCode === 301 || response.statusCode === 302 || response.statusCode === 307 || response.statusCode === 308) {
|
|
242
|
+
const redirectUrl = response.headers.location;
|
|
243
|
+
if (redirectUrl) {
|
|
244
|
+
followRedirect(redirectUrl, redirectCount + 1);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (response.statusCode !== 200) {
|
|
249
|
+
reject(new Error(`Download failed: ${response.statusCode}`));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const file = fs.createWriteStream(destPath);
|
|
253
|
+
response.pipe(file);
|
|
254
|
+
file.on('finish', () => {
|
|
255
|
+
file.close();
|
|
256
|
+
resolve();
|
|
257
|
+
});
|
|
258
|
+
file.on('error', (err) => {
|
|
259
|
+
fs.unlinkSync(destPath);
|
|
260
|
+
reject(err);
|
|
261
|
+
});
|
|
262
|
+
}).on('error', reject);
|
|
263
|
+
};
|
|
264
|
+
followRedirect(url);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Detect Linux package manager
|
|
269
|
+
*/
|
|
270
|
+
detectLinuxPackageManager() {
|
|
271
|
+
try {
|
|
272
|
+
(0, child_process_1.execSync)('which apt', { stdio: 'ignore' });
|
|
273
|
+
return 'apt';
|
|
274
|
+
}
|
|
275
|
+
catch (e) { }
|
|
276
|
+
try {
|
|
277
|
+
(0, child_process_1.execSync)('which dnf', { stdio: 'ignore' });
|
|
278
|
+
return 'dnf';
|
|
279
|
+
}
|
|
280
|
+
catch (e) { }
|
|
281
|
+
try {
|
|
282
|
+
(0, child_process_1.execSync)('which yum', { stdio: 'ignore' });
|
|
283
|
+
return 'yum';
|
|
284
|
+
}
|
|
285
|
+
catch (e) { }
|
|
286
|
+
try {
|
|
287
|
+
(0, child_process_1.execSync)('which pacman', { stdio: 'ignore' });
|
|
288
|
+
return 'pacman';
|
|
289
|
+
}
|
|
290
|
+
catch (e) { }
|
|
291
|
+
return 'unknown';
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Find Brave on Windows
|
|
295
|
+
*/
|
|
296
|
+
findBraveWindows() {
|
|
297
|
+
const paths = [
|
|
298
|
+
`${process.env.LOCALAPPDATA}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
|
|
299
|
+
`${process.env.PROGRAMFILES}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
|
|
300
|
+
`${process.env['PROGRAMFILES(X86)']}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
|
|
301
|
+
];
|
|
302
|
+
for (const p of paths) {
|
|
303
|
+
if (p && fs.existsSync(p)) {
|
|
304
|
+
return p;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Find Brave on Linux
|
|
311
|
+
*/
|
|
312
|
+
findBraveLinux() {
|
|
313
|
+
const paths = [
|
|
314
|
+
'/usr/bin/brave-browser',
|
|
315
|
+
'/usr/bin/brave-browser-stable',
|
|
316
|
+
'/opt/brave.com/brave/brave',
|
|
317
|
+
'/snap/bin/brave'
|
|
318
|
+
];
|
|
319
|
+
for (const p of paths) {
|
|
320
|
+
if (fs.existsSync(p)) {
|
|
321
|
+
return p;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Delay helper
|
|
328
|
+
*/
|
|
329
|
+
delay(ms) {
|
|
330
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Check if Brave is installed
|
|
334
|
+
*/
|
|
335
|
+
static isInstalled() {
|
|
336
|
+
const platform = (0, utils_js_1.getPlatform)();
|
|
337
|
+
const installer = new BraveInstaller({ silent: true });
|
|
338
|
+
switch (platform) {
|
|
339
|
+
case 'win32':
|
|
340
|
+
return installer.findBraveWindows() !== null;
|
|
341
|
+
case 'linux':
|
|
342
|
+
return installer.findBraveLinux() !== null;
|
|
343
|
+
case 'darwin':
|
|
344
|
+
return fs.existsSync('/Applications/Brave Browser.app/Contents/MacOS/Brave Browser');
|
|
345
|
+
default:
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
exports.BraveInstaller = BraveInstaller;
|
|
351
|
+
exports.default = BraveInstaller;
|
|
352
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJhdmUtaW5zdGFsbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2JyYXZlLWluc3RhbGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFDSCxZQUFZLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRWIsdUNBQXlCO0FBQ3pCLDJDQUE2QjtBQUM3Qiw2Q0FBK0I7QUFDL0IsMkNBQTZCO0FBQzdCLGlEQUFnRDtBQUNoRCwyQkFBNkI7QUFDN0IsNERBQThCO0FBQzlCLHlDQUF5QztBQWN6QyxNQUFNLG1CQUFtQixHQUFHO0lBQ3hCLEtBQUssRUFBRTtRQUNILE9BQU8sRUFBRSxnREFBZ0Q7UUFDekQsSUFBSSxFQUFFLHFEQUFxRDtRQUMzRCxPQUFPLEVBQUUsd0RBQXdEO0tBQ3BFO0lBQ0QsTUFBTSxFQUFFO1FBQ0osT0FBTyxFQUFFLDZDQUE2QztRQUN0RCxJQUFJLEVBQUUsa0RBQWtEO1FBQ3hELE9BQU8sRUFBRSxxREFBcUQ7S0FDakU7Q0FDSixDQUFDO0FBRUYsTUFBYSxjQUFjO0lBS3ZCLFlBQVksVUFBNEIsRUFBRTtRQUN0QyxJQUFJLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLElBQUksS0FBSyxDQUFDO1FBQ3RDLElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDLFdBQVcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUEsWUFBTyxHQUFFLEVBQUUsc0JBQXNCLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDcEcsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxJQUFJLFNBQVMsQ0FBQztRQUU1QyxJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUU7WUFDbEMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7U0FD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
|