n8n-nodes-nvk-browser 1.0.39 → 1.0.40
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/nodes/ProfileManagement/CreateProfile/CreateProfile.description.js +6 -4
- package/dist/nodes/ProfileManagement/CreateProfile/CreateProfile.node.js +24 -9
- package/dist/utils/ExtensionHandler.d.ts +3 -0
- package/dist/utils/ExtensionHandler.js +74 -1
- package/dist/utils/ProfileManager.js +5 -1
- package/package.json +1 -1
|
@@ -21,7 +21,8 @@ exports.createProfileFields = [
|
|
|
21
21
|
name: 'proxy',
|
|
22
22
|
type: 'string',
|
|
23
23
|
default: '',
|
|
24
|
-
|
|
24
|
+
placeholder: 'http://127.0.0.1:8080:user:pass hoặc socks5:127.0.0.1:1080:user:pass',
|
|
25
|
+
description: 'Proxy format: http://ip:port:user:pass or socks5:ip:port:user:pass',
|
|
25
26
|
displayOptions: {
|
|
26
27
|
show: {
|
|
27
28
|
resource: ['profile'],
|
|
@@ -43,14 +44,15 @@ exports.createProfileFields = [
|
|
|
43
44
|
},
|
|
44
45
|
},
|
|
45
46
|
{
|
|
46
|
-
displayName: '
|
|
47
|
-
name: '
|
|
47
|
+
displayName: 'Extension',
|
|
48
|
+
name: 'extension',
|
|
48
49
|
type: 'string',
|
|
49
50
|
typeOptions: {
|
|
50
51
|
rows: 4,
|
|
51
52
|
},
|
|
52
53
|
default: '',
|
|
53
|
-
|
|
54
|
+
placeholder: 'Nhập ID extension Chrome Store hoặc đường dẫn tới extension local, mỗi extension một dòng',
|
|
55
|
+
description: 'Enter Chrome Store extension ID or path to local extension, one extension per line',
|
|
54
56
|
displayOptions: {
|
|
55
57
|
show: {
|
|
56
58
|
resource: ['profile'],
|
|
@@ -24,6 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.CreateProfile = void 0;
|
|
27
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
27
28
|
const path = __importStar(require("path"));
|
|
28
29
|
const ProfileManager_1 = require("../../../utils/ProfileManager");
|
|
29
30
|
const ExtensionHandler_1 = require("../../../utils/ExtensionHandler");
|
|
@@ -91,14 +92,24 @@ class CreateProfile {
|
|
|
91
92
|
const profileName = this.getNodeParameter('profileName', i);
|
|
92
93
|
const proxy = this.getNodeParameter('proxy', i) || undefined;
|
|
93
94
|
const note = this.getNodeParameter('note', i) || undefined;
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
const extensionInput = this.getNodeParameter('extension', i) || '';
|
|
96
|
+
if (!profileName) {
|
|
97
|
+
throw new n8n_workflow_1.ApplicationError('Profile Name is required');
|
|
98
|
+
}
|
|
99
|
+
// Parse extensions từ input (mỗi extension một dòng)
|
|
100
|
+
const extensions = ExtensionHandler_1.ExtensionHandler.parseExtensions(extensionInput);
|
|
97
101
|
// Tạo profile
|
|
98
102
|
const profile = profileManager.createProfile(profileName, proxy, note, extensions);
|
|
103
|
+
// Cài đặt extensions (Chrome Store IDs và local paths)
|
|
104
|
+
if (extensions.length > 0) {
|
|
105
|
+
const profilePath = profileManager.getProfilePath(profile.id);
|
|
106
|
+
ExtensionHandler_1.ExtensionHandler.installExtensions(profilePath, extensions);
|
|
107
|
+
}
|
|
99
108
|
returnData.push({
|
|
100
109
|
json: {
|
|
101
110
|
success: true,
|
|
111
|
+
profile_id: profile.id,
|
|
112
|
+
message: 'Profile created successfully',
|
|
102
113
|
profile: {
|
|
103
114
|
id: profile.id,
|
|
104
115
|
name: profile.name,
|
|
@@ -111,12 +122,16 @@ class CreateProfile {
|
|
|
111
122
|
});
|
|
112
123
|
}
|
|
113
124
|
catch (error) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
if (this.continueOnFail()) {
|
|
126
|
+
returnData.push({
|
|
127
|
+
json: {
|
|
128
|
+
success: false,
|
|
129
|
+
error: error instanceof Error ? error.message : String(error),
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
throw error;
|
|
120
135
|
}
|
|
121
136
|
}
|
|
122
137
|
return [returnData];
|
|
@@ -5,5 +5,8 @@ export declare class ExtensionHandler {
|
|
|
5
5
|
path?: string;
|
|
6
6
|
error?: string;
|
|
7
7
|
};
|
|
8
|
+
static getExtensionId(extension: string): string | null;
|
|
9
|
+
static installExtensions(profilePath: string, extensions: string[]): void;
|
|
10
|
+
private static installChromeStoreExtensions;
|
|
8
11
|
static getExtensionArgs(extensions: string[]): string[];
|
|
9
12
|
}
|
|
@@ -40,9 +40,15 @@ class ExtensionHandler {
|
|
|
40
40
|
}
|
|
41
41
|
static validateExtension(extension) {
|
|
42
42
|
// Nếu là ID từ Chrome Store (thường là 32 ký tự alphanumeric)
|
|
43
|
+
// Cũng hỗ trợ format URL từ Chrome Web Store
|
|
43
44
|
if (/^[a-z]{32}$/i.test(extension)) {
|
|
44
45
|
return { valid: true };
|
|
45
46
|
}
|
|
47
|
+
// Nếu là URL Chrome Web Store, extract ID
|
|
48
|
+
const chromeStoreMatch = extension.match(/chrome\.google\.com\/webstore\/detail\/[^/]+\/([a-z]{32})/i);
|
|
49
|
+
if (chromeStoreMatch) {
|
|
50
|
+
return { valid: true };
|
|
51
|
+
}
|
|
46
52
|
// Nếu là đường dẫn local
|
|
47
53
|
if (path.isAbsolute(extension) || extension.startsWith('./') || extension.startsWith('../')) {
|
|
48
54
|
const resolvedPath = path.resolve(extension);
|
|
@@ -67,6 +73,73 @@ class ExtensionHandler {
|
|
|
67
73
|
}
|
|
68
74
|
return { valid: false, error: 'Invalid extension format. Must be Chrome Store ID or valid path' };
|
|
69
75
|
}
|
|
76
|
+
static getExtensionId(extension) {
|
|
77
|
+
// Nếu là ID trực tiếp (32 ký tự)
|
|
78
|
+
if (/^[a-z]{32}$/i.test(extension)) {
|
|
79
|
+
return extension;
|
|
80
|
+
}
|
|
81
|
+
// Nếu là URL Chrome Web Store, extract ID
|
|
82
|
+
const chromeStoreMatch = extension.match(/chrome\.google\.com\/webstore\/detail\/[^/]+\/([a-z]{32})/i);
|
|
83
|
+
if (chromeStoreMatch) {
|
|
84
|
+
return chromeStoreMatch[1];
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
static installExtensions(profilePath, extensions) {
|
|
89
|
+
if (!extensions || extensions.length === 0) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// Tách Chrome Store IDs và local paths
|
|
93
|
+
const chromeStoreIds = [];
|
|
94
|
+
const localPaths = [];
|
|
95
|
+
for (const ext of extensions) {
|
|
96
|
+
const extensionId = this.getExtensionId(ext);
|
|
97
|
+
if (extensionId) {
|
|
98
|
+
chromeStoreIds.push(extensionId);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
const validation = this.validateExtension(ext);
|
|
102
|
+
if (validation.valid && validation.path) {
|
|
103
|
+
localPaths.push(validation.path);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Cài đặt Chrome Store extensions thông qua external_extensions.json
|
|
108
|
+
if (chromeStoreIds.length > 0) {
|
|
109
|
+
this.installChromeStoreExtensions(profilePath, chromeStoreIds);
|
|
110
|
+
}
|
|
111
|
+
// Local extensions sẽ được load qua --load-extension khi start browser
|
|
112
|
+
// (đã được xử lý trong getExtensionArgs)
|
|
113
|
+
}
|
|
114
|
+
static installChromeStoreExtensions(profilePath, extensionIds) {
|
|
115
|
+
// Tạo thư mục Extensions nếu chưa có
|
|
116
|
+
const extensionsDir = path.join(profilePath, 'Extensions');
|
|
117
|
+
if (!fs.existsSync(extensionsDir)) {
|
|
118
|
+
fs.mkdirSync(extensionsDir, { recursive: true });
|
|
119
|
+
}
|
|
120
|
+
// Đường dẫn đến file external_extensions.json
|
|
121
|
+
const externalExtensionsPath = path.join(extensionsDir, 'external_extensions.json');
|
|
122
|
+
// Đọc file hiện tại nếu có
|
|
123
|
+
let externalExtensions = {};
|
|
124
|
+
if (fs.existsSync(externalExtensionsPath)) {
|
|
125
|
+
try {
|
|
126
|
+
const content = fs.readFileSync(externalExtensionsPath, 'utf-8');
|
|
127
|
+
externalExtensions = JSON.parse(content);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
// Nếu file không hợp lệ, bắt đầu từ đầu
|
|
131
|
+
externalExtensions = {};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Thêm các extension IDs vào external_extensions
|
|
135
|
+
for (const extensionId of extensionIds) {
|
|
136
|
+
externalExtensions[extensionId] = {
|
|
137
|
+
external_update_url: 'https://clients2.google.com/service/update2/crx',
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// Ghi lại file
|
|
141
|
+
fs.writeFileSync(externalExtensionsPath, JSON.stringify(externalExtensions, null, 2), 'utf-8');
|
|
142
|
+
}
|
|
70
143
|
static getExtensionArgs(extensions) {
|
|
71
144
|
const args = [];
|
|
72
145
|
const validPaths = [];
|
|
@@ -75,7 +148,7 @@ class ExtensionHandler {
|
|
|
75
148
|
if (validation.valid && validation.path) {
|
|
76
149
|
validPaths.push(validation.path);
|
|
77
150
|
}
|
|
78
|
-
// Chrome Store IDs
|
|
151
|
+
// Chrome Store IDs đã được cài đặt qua external_extensions.json
|
|
79
152
|
}
|
|
80
153
|
if (validPaths.length > 0) {
|
|
81
154
|
args.push(`--load-extension=${validPaths.join(',')}`);
|
|
@@ -101,19 +101,23 @@ class ProfileManager {
|
|
|
101
101
|
// Cũng set trong Preferences file
|
|
102
102
|
const prefsPath = path.join(defaultDir, 'Preferences');
|
|
103
103
|
let prefs = {};
|
|
104
|
+
// Đọc Preferences nếu đã tồn tại
|
|
104
105
|
if (fs.existsSync(prefsPath)) {
|
|
105
106
|
try {
|
|
106
107
|
const prefsContent = fs.readFileSync(prefsPath, 'utf-8');
|
|
107
108
|
prefs = JSON.parse(prefsContent);
|
|
108
109
|
}
|
|
109
110
|
catch (error) {
|
|
110
|
-
//
|
|
111
|
+
// Nếu file không hợp lệ, bắt đầu từ đầu
|
|
112
|
+
prefs = {};
|
|
111
113
|
}
|
|
112
114
|
}
|
|
115
|
+
// Đảm bảo cấu trúc profile tồn tại
|
|
113
116
|
if (!prefs.profile) {
|
|
114
117
|
prefs.profile = {};
|
|
115
118
|
}
|
|
116
119
|
prefs.profile.name = profileName;
|
|
120
|
+
// Luôn ghi Preferences file (tạo mới hoặc cập nhật)
|
|
117
121
|
fs.writeFileSync(prefsPath, JSON.stringify(prefs, null, 2), 'utf-8');
|
|
118
122
|
}
|
|
119
123
|
catch (error) {
|
package/package.json
CHANGED