biklitool 1.1.11
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/LICENSE-BIKLI +16 -0
- package/LICENSE-RDPWRAPPER +202 -0
- package/README.md +96 -0
- package/bin/biklimaster.js +409 -0
- package/config.json +4 -0
- package/lib/bikliwrapper.js +384 -0
- package/package.json +40 -0
- package/payload/RDPWInst.exe +0 -0
- package/payload/bikli-cli-installer.exe +0 -0
- package/payload/rdpwrap.ini +21109 -0
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const util = require('util');
|
|
8
|
+
const { createHash, randomBytes, randomUUID } = require('crypto');
|
|
9
|
+
const { spawnSync } = require('child_process');
|
|
10
|
+
|
|
11
|
+
const root = path.resolve(__dirname, '..');
|
|
12
|
+
const payloadDirectory = path.join(root, 'payload');
|
|
13
|
+
const bikliInstaller = path.join(payloadDirectory, 'bikli-cli-installer.exe');
|
|
14
|
+
const wrapperInstaller = path.join(payloadDirectory, 'RDPWInst.exe');
|
|
15
|
+
const wrapperIni = path.join(payloadDirectory, 'rdpwrap.ini');
|
|
16
|
+
const wrapperScript = path.join(root, 'lib', 'bikliwrapper.js');
|
|
17
|
+
const packageConfigFile = path.join(root, 'config.json');
|
|
18
|
+
const windowsDirectory = process.env.SystemRoot || process.env.WINDIR || 'C:\\Windows';
|
|
19
|
+
const powershell = path.join(windowsDirectory, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
|
|
20
|
+
const reg = path.join(windowsDirectory, 'System32', 'reg.exe');
|
|
21
|
+
const icacls = path.join(windowsDirectory, 'System32', 'icacls.exe');
|
|
22
|
+
const programData = process.env.ProgramData || 'C:\\ProgramData';
|
|
23
|
+
const credentialsFile = path.join(programData, 'BikliWrapper', 'admin-credentials.json');
|
|
24
|
+
const expectedBikliVersion = '1.1.10.0';
|
|
25
|
+
const administratorsGroupSid = 'S-1-5-32-544';
|
|
26
|
+
const remoteDesktopUsersGroupSid = 'S-1-5-32-555';
|
|
27
|
+
const terminalServerKey = 'HKLM\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server';
|
|
28
|
+
const rdpTcpKey = `${terminalServerKey}\\WinStations\\RDP-Tcp`;
|
|
29
|
+
const expectedHashes = {
|
|
30
|
+
'bikli-cli-installer.exe': '21EEDFBC9CFB2E360BC894C5774F18BDF7E1BDCAC04028E25907131569C5631E',
|
|
31
|
+
'RDPWInst.exe': 'AC92D4C6397EB4451095949AC485EF4EC38501D7BB6F475419529AE67E297753',
|
|
32
|
+
'rdpwrap.ini': 'BD04EBBE400E294DD795BE1F710464A70BF970559C3BB376C6C3C8333CDFB915'
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const resultArgument = process.argv.find(argument => argument.startsWith('--result-file='));
|
|
36
|
+
const resultFile = resultArgument ? resultArgument.slice('--result-file='.length) : '';
|
|
37
|
+
if (resultFile) {
|
|
38
|
+
const writeResult = (...items) => fs.appendFileSync(resultFile, util.format(...items) + os.EOL, 'utf8');
|
|
39
|
+
console.log = writeResult;
|
|
40
|
+
console.error = writeResult;
|
|
41
|
+
console.warn = writeResult;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function fail(message, exitCode = 1) {
|
|
45
|
+
const error = new Error(message);
|
|
46
|
+
error.exitCode = exitCode;
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function run(executable, args, options = {}) {
|
|
51
|
+
const result = spawnSync(executable, args, {
|
|
52
|
+
cwd: options.cwd || root,
|
|
53
|
+
encoding: 'utf8',
|
|
54
|
+
windowsHide: true,
|
|
55
|
+
env: options.env || process.env,
|
|
56
|
+
stdio: options.inherit ? 'inherit' : 'pipe'
|
|
57
|
+
});
|
|
58
|
+
if (result.error) fail(`Could not run ${path.basename(executable)}: ${result.error.message}`);
|
|
59
|
+
if (!options.allowFailure && result.status !== 0) {
|
|
60
|
+
const details = `${result.stdout || ''}${result.stderr || ''}`.trim();
|
|
61
|
+
fail(`${path.basename(executable)} failed with exit code ${result.status}.${details ? `\n${details}` : ''}`);
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function requireWindows() {
|
|
67
|
+
if (process.platform !== 'win32') fail('Bikli Master supports Windows only.');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function isAdministrator() {
|
|
71
|
+
const script = [
|
|
72
|
+
`$identity=[Security.Principal.WindowsIdentity]::GetCurrent()`,
|
|
73
|
+
`$principal=New-Object Security.Principal.WindowsPrincipal($identity)`,
|
|
74
|
+
`Write-Output $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)`
|
|
75
|
+
].join(';');
|
|
76
|
+
const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script], {
|
|
77
|
+
allowFailure: true
|
|
78
|
+
});
|
|
79
|
+
return result.status === 0 && /^true$/i.test(result.stdout.trim());
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function powershellLiteral(value) {
|
|
83
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function elevateAndRun(command) {
|
|
87
|
+
if (process.argv.includes('--elevated')) fail('Windows did not grant administrator rights.');
|
|
88
|
+
console.log('Bikli Master needs administrator access. Approve the Windows UAC prompt...');
|
|
89
|
+
const logPath = path.join(os.tmpdir(), `biklimaster-elevated-${randomUUID()}.log`);
|
|
90
|
+
const script = [
|
|
91
|
+
`$node=${powershellLiteral(process.execPath)}`,
|
|
92
|
+
`$target=${powershellLiteral(path.resolve(__filename))}`,
|
|
93
|
+
`$result=${powershellLiteral(logPath)}`,
|
|
94
|
+
`$arguments='"'+$target+'" ${command} --elevated "--result-file='+$result+'"'`,
|
|
95
|
+
`$process=Start-Process -FilePath $node -ArgumentList $arguments -Verb RunAs -WindowStyle Hidden -Wait -PassThru`,
|
|
96
|
+
`exit $process.ExitCode`
|
|
97
|
+
].join(';');
|
|
98
|
+
const result = run(powershell, [
|
|
99
|
+
'-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command', script
|
|
100
|
+
], { allowFailure: true });
|
|
101
|
+
let elevatedOutput = '';
|
|
102
|
+
if (fs.existsSync(logPath)) {
|
|
103
|
+
elevatedOutput = fs.readFileSync(logPath, 'utf8').trim();
|
|
104
|
+
fs.rmSync(logPath, { force: true });
|
|
105
|
+
}
|
|
106
|
+
if (result.status !== 0) {
|
|
107
|
+
const details = [elevatedOutput, result.stdout, result.stderr].filter(Boolean).join(os.EOL).trim();
|
|
108
|
+
fail(`Administrator elevation was cancelled or installation failed.${details ? `\n${details}` : ''}`);
|
|
109
|
+
}
|
|
110
|
+
if (elevatedOutput) console.log(elevatedOutput);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function sha256(file) {
|
|
114
|
+
return createHash('sha256').update(fs.readFileSync(file)).digest('hex').toUpperCase();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function verifyPayload() {
|
|
118
|
+
for (const [name, expected] of Object.entries(expectedHashes)) {
|
|
119
|
+
const file = path.join(payloadDirectory, name);
|
|
120
|
+
if (!fs.existsSync(file)) fail(`Missing package payload: ${name}`);
|
|
121
|
+
const actual = sha256(file);
|
|
122
|
+
if (actual !== expected) fail(`Payload checksum mismatch: ${name}`);
|
|
123
|
+
}
|
|
124
|
+
if (!fs.existsSync(wrapperScript)) fail('Missing embedded Bikli Wrapper CLI.');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function installedBikliPath() {
|
|
128
|
+
const candidates = [
|
|
129
|
+
path.join(process.env.ProgramFiles || 'C:\\Program Files', 'Bikli', 'Bikli.exe'),
|
|
130
|
+
path.join(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)', 'Bikli', 'Bikli.exe')
|
|
131
|
+
];
|
|
132
|
+
return candidates.find(candidate => fs.existsSync(candidate)) || '';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function fileVersion(file) {
|
|
136
|
+
if (!file) return '';
|
|
137
|
+
const escaped = file.replace(/'/g, "''");
|
|
138
|
+
const script = `(Get-Item -LiteralPath '${escaped}').VersionInfo.FileVersion`;
|
|
139
|
+
const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script], {
|
|
140
|
+
allowFailure: true
|
|
141
|
+
});
|
|
142
|
+
return result.status === 0 ? result.stdout.trim() : '';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function installBikli() {
|
|
146
|
+
const existing = installedBikliPath();
|
|
147
|
+
if (existing && fileVersion(existing) === expectedBikliVersion) {
|
|
148
|
+
console.log(`Bikli CLI ${expectedBikliVersion} is already installed; reinstall skipped.`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
console.log(`Installing Bikli CLI ${expectedBikliVersion} silently...`);
|
|
152
|
+
run(bikliInstaller, ['/S'], { cwd: payloadDirectory });
|
|
153
|
+
const installed = installedBikliPath();
|
|
154
|
+
if (!installed) fail('Bikli CLI installer completed but Bikli.exe was not found.', 5);
|
|
155
|
+
console.log(`Bikli CLI installed: ${fileVersion(installed) || 'version unknown'}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function runWrapper(args, options = {}) {
|
|
159
|
+
return run(process.execPath, [wrapperScript, ...args], {
|
|
160
|
+
cwd: root,
|
|
161
|
+
allowFailure: options.allowFailure,
|
|
162
|
+
inherit: options.inherit
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function queryDword(key, name) {
|
|
167
|
+
const result = run(reg, ['query', key, '/v', name, '/reg:64'], { allowFailure: true });
|
|
168
|
+
if (result.status !== 0) return null;
|
|
169
|
+
const match = result.stdout.match(/REG_DWORD\s+(0x[0-9a-f]+|\d+)/i);
|
|
170
|
+
if (!match) return null;
|
|
171
|
+
return Number.parseInt(match[1], match[1].toLowerCase().startsWith('0x') ? 16 : 10);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function remoteDesktopState() {
|
|
175
|
+
return {
|
|
176
|
+
enabled: queryDword(terminalServerKey, 'fDenyTSConnections') === 0,
|
|
177
|
+
port: queryDword(rdpTcpKey, 'PortNumber')
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function verifyRemoteDesktop() {
|
|
182
|
+
const state = remoteDesktopState();
|
|
183
|
+
if (!state.enabled) fail('Remote Desktop could not be enabled.', 6);
|
|
184
|
+
if (state.port !== 3389) fail(`Remote Desktop port verification failed (found ${state.port ?? 'unknown'}).`, 6);
|
|
185
|
+
console.log('Remote Desktop is enabled and verified on port 3389.');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function enableRemoteDesktop() {
|
|
189
|
+
requireWindows();
|
|
190
|
+
if (!isAdministrator()) return elevateAndRun('enable-rdp');
|
|
191
|
+
verifyPayload();
|
|
192
|
+
console.log('Enabling Remote Desktop and applying the firewall and security defaults...');
|
|
193
|
+
const wrapper = runWrapper(['defaults', '--elevated']);
|
|
194
|
+
if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
|
|
195
|
+
verifyRemoteDesktop();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function generatedAccountPassword() {
|
|
199
|
+
return `Bk1!${randomBytes(18).toString('base64url')}`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function configuredAdministratorPassword() {
|
|
203
|
+
if (!fs.existsSync(packageConfigFile)) fail('Missing package configuration file: config.json');
|
|
204
|
+
const config = JSON.parse(fs.readFileSync(packageConfigFile, 'utf8'));
|
|
205
|
+
return typeof config.administratorPassword === 'string' ? config.administratorPassword : '';
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function configuredBikliKey() {
|
|
209
|
+
if (!fs.existsSync(packageConfigFile)) return '';
|
|
210
|
+
const config = JSON.parse(fs.readFileSync(packageConfigFile, 'utf8'));
|
|
211
|
+
return typeof config.bikliKey === 'string' ? config.bikliKey.trim() : '';
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function setupBikliKey() {
|
|
215
|
+
requireWindows();
|
|
216
|
+
const key = (process.env.BIKLIMASTER_BIKLI_KEY || configuredBikliKey()).trim();
|
|
217
|
+
if (!key) {
|
|
218
|
+
console.log('No Bikli key configured; paste it into config.json under "bikliKey" to enable this step. Bikli key setup skipped.');
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (!isAdministrator()) return elevateAndRun('setup-key');
|
|
222
|
+
const bikli = installedBikliPath();
|
|
223
|
+
if (!bikli) fail('Bikli CLI is not installed. Run "biklimaster install" first.', 5);
|
|
224
|
+
console.log('Configuring the Bikli key (bikli up --setup-key)...');
|
|
225
|
+
const result = run(bikli, ['up', '--setup-key', key], { allowFailure: true });
|
|
226
|
+
const output = `${result.stdout || ''}${result.stderr || ''}`.trim();
|
|
227
|
+
if (result.status !== 0) {
|
|
228
|
+
fail(`Bikli key setup failed with exit code ${result.status}.${output ? `\n${output}` : ''}`, 8);
|
|
229
|
+
}
|
|
230
|
+
if (output) console.log(output);
|
|
231
|
+
console.log('Bikli key configured successfully.');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function saveAccountCredentials(username, password) {
|
|
235
|
+
fs.mkdirSync(path.dirname(credentialsFile), { recursive: true });
|
|
236
|
+
fs.writeFileSync(credentialsFile, JSON.stringify({ username, password }, null, 2), {
|
|
237
|
+
encoding: 'utf8',
|
|
238
|
+
mode: 0o600
|
|
239
|
+
});
|
|
240
|
+
run(icacls, [
|
|
241
|
+
credentialsFile,
|
|
242
|
+
'/inheritance:r',
|
|
243
|
+
'/grant:r',
|
|
244
|
+
'*S-1-5-18:(F)',
|
|
245
|
+
`*${administratorsGroupSid}:(F)`
|
|
246
|
+
]);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function showAccountCredentials() {
|
|
250
|
+
requireWindows();
|
|
251
|
+
if (!isAdministrator()) return elevateAndRun('credentials');
|
|
252
|
+
if (!fs.existsSync(credentialsFile)) {
|
|
253
|
+
fail('No saved password is available. The built-in Administrator account may already have been enabled.');
|
|
254
|
+
}
|
|
255
|
+
const credentials = JSON.parse(fs.readFileSync(credentialsFile, 'utf8'));
|
|
256
|
+
console.log(`Username: ${credentials.username}`);
|
|
257
|
+
console.log(`Password: ${credentials.password}`);
|
|
258
|
+
console.log(`Stored for Administrators only: ${credentialsFile}`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function createRdpAdministrator() {
|
|
262
|
+
requireWindows();
|
|
263
|
+
if (!isAdministrator()) return elevateAndRun('create-user');
|
|
264
|
+
|
|
265
|
+
const requestedPassword = process.env.BIKLIMASTER_USER_PASSWORD || configuredAdministratorPassword();
|
|
266
|
+
const accountPassword = requestedPassword || generatedAccountPassword();
|
|
267
|
+
const script = [
|
|
268
|
+
`$ErrorActionPreference='Stop'`,
|
|
269
|
+
`$password=$env:BIKLIMASTER_ACCOUNT_PASSWORD`,
|
|
270
|
+
`$secure=ConvertTo-SecureString $password -AsPlainText -Force`,
|
|
271
|
+
`$groupSids=@(${powershellLiteral(administratorsGroupSid)},${powershellLiteral(remoteDesktopUsersGroupSid)})`,
|
|
272
|
+
`$builtIn=Get-LocalUser | Where-Object {$_.SID.Value -match '-500$'} | Select-Object -First 1`,
|
|
273
|
+
`if($null -eq $builtIn){throw 'Built-in Administrator account (RID 500) was not found'}`,
|
|
274
|
+
`$builtInWasDisabled=-not $builtIn.Enabled`,
|
|
275
|
+
`$target=$null;$action='';$createdNew=$false;$enabledBuiltIn=$false;$passwordChanged=$false`,
|
|
276
|
+
`if($builtInWasDisabled){Set-LocalUser -Name $builtIn.Name -Password $secure;Enable-LocalUser -Name $builtIn.Name;$target=Get-LocalUser -SID $builtIn.SID;$enabledBuiltIn=$true;$passwordChanged=$true;$action='enabled-builtin'}else{$admin=Get-LocalUser -Name 'admin' -ErrorAction SilentlyContinue;if($null -eq $admin){New-LocalUser -Name 'admin' -Password $secure -FullName 'admin' -Description 'Local administrator created by Bikli Master' -PasswordNeverExpires | Out-Null;$target=Get-LocalUser -Name 'admin';$createdNew=$true;$passwordChanged=$true;$action='created-admin'}else{$existingUser=Get-LocalUser -Name 'user' -ErrorAction SilentlyContinue;if($null -eq $existingUser){New-LocalUser -Name 'user' -Password $secure -FullName 'user' -Description 'Local administrator created by Bikli Master' -PasswordNeverExpires | Out-Null;$target=Get-LocalUser -Name 'user';$createdNew=$true;$passwordChanged=$true;$action='created-user'}else{$target=$existingUser;$action='exists-user'}}}`,
|
|
277
|
+
`if(-not $target.Enabled){Enable-LocalUser -Name $target.Name;$target=Get-LocalUser -SID $target.SID}`,
|
|
278
|
+
`foreach($groupSid in $groupSids){$group=Get-LocalGroup -SID $groupSid;$member=Get-LocalGroupMember -Group $group.Name | Where-Object {$_.SID.Value -eq $target.SID.Value};if($null -eq $member){Add-LocalGroupMember -Group $group.Name -Member $target}}`,
|
|
279
|
+
`$verified=@()`,
|
|
280
|
+
`foreach($groupSid in $groupSids){$group=Get-LocalGroup -SID $groupSid;$member=Get-LocalGroupMember -Group $group.Name | Where-Object {$_.SID.Value -eq $target.SID.Value};if($null -eq $member){throw ('Account is not a member of '+$group.Name)};$verified+=$group.Name}`,
|
|
281
|
+
`$userListKey='HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList'`,
|
|
282
|
+
`$hideEntry=Get-ItemProperty -Path $userListKey -Name $target.Name -ErrorAction SilentlyContinue`,
|
|
283
|
+
`if($null -eq $hideEntry){New-Item -Path $userListKey -Force | Out-Null;New-ItemProperty -Path $userListKey -Name $target.Name -PropertyType DWord -Value 0 -Force | Out-Null;if((Get-ItemPropertyValue -Path $userListKey -Name $target.Name) -ne 0){throw ('Could not hide '+$target.Name+' from the sign-in screen')};$alreadyHidden=$false}else{$alreadyHidden=$true}`,
|
|
284
|
+
`[PSCustomObject]@{Name=$target.Name;BuiltInName=$builtIn.Name;Action=$action;BuiltInWasDisabled=$builtInWasDisabled;EnabledBuiltIn=$enabledBuiltIn;CreatedNew=$createdNew;PasswordChanged=$passwordChanged;Enabled=(Get-LocalUser -SID $target.SID).Enabled;Groups=$verified;HiddenUser=$target.Name;AlreadyHidden=$alreadyHidden} | ConvertTo-Json -Compress`
|
|
285
|
+
].join(';');
|
|
286
|
+
const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script], {
|
|
287
|
+
env: {
|
|
288
|
+
...process.env,
|
|
289
|
+
BIKLIMASTER_ACCOUNT_PASSWORD: accountPassword
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
const account = JSON.parse(result.stdout.trim());
|
|
293
|
+
if (!account.Enabled || !Array.isArray(account.Groups) || account.Groups.length !== 2 || !account.HiddenUser) {
|
|
294
|
+
fail('The Remote Desktop administrator account could not be verified.', 7);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (account.PasswordChanged) {
|
|
298
|
+
saveAccountCredentials(account.Name, accountPassword);
|
|
299
|
+
const message = {
|
|
300
|
+
'enabled-builtin': `Built-in Administrator was disabled; set the password and enabled it: ${account.Name}`,
|
|
301
|
+
'created-admin': `Built-in Administrator is already enabled and left untouched; created hidden admin account: ${account.Name}`,
|
|
302
|
+
'created-user': `Built-in Administrator and admin already exist and were left untouched; created hidden account: ${account.Name}`
|
|
303
|
+
}[account.Action] || `Configured account: ${account.Name}`;
|
|
304
|
+
console.log(message);
|
|
305
|
+
console.log(`Password: ${accountPassword}`);
|
|
306
|
+
console.log('The configured password was applied and saved for administrator-only retrieval.');
|
|
307
|
+
} else {
|
|
308
|
+
console.log(`Administrator, admin, and user accounts already exist; left their passwords unchanged and verified ${account.Name}.`);
|
|
309
|
+
}
|
|
310
|
+
console.log(`Verified ${account.Name} in Administrators and Remote Desktop Users.`);
|
|
311
|
+
if (account.AlreadyHidden) {
|
|
312
|
+
console.log(`${account.HiddenUser} is already hidden from the sign-in user list; left it unchanged.`);
|
|
313
|
+
} else {
|
|
314
|
+
console.log(`Hidden from the sign-in user list: ${account.HiddenUser}.`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function install() {
|
|
319
|
+
requireWindows();
|
|
320
|
+
if (!isAdministrator()) return elevateAndRun('install');
|
|
321
|
+
verifyPayload();
|
|
322
|
+
installBikli();
|
|
323
|
+
setupBikliKey();
|
|
324
|
+
console.log('Installing or updating Bikli Wrapper silently...');
|
|
325
|
+
const wrapper = runWrapper(['install', '--elevated']);
|
|
326
|
+
if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
|
|
327
|
+
verifyRemoteDesktop();
|
|
328
|
+
createRdpAdministrator();
|
|
329
|
+
console.log('Bikli Master installed and verified both components successfully.');
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function status() {
|
|
333
|
+
requireWindows();
|
|
334
|
+
const bikli = installedBikliPath();
|
|
335
|
+
console.log(`Bikli CLI: ${bikli ? `Installed (${fileVersion(bikli) || 'unknown version'})` : 'Not installed'}`);
|
|
336
|
+
const rdp = remoteDesktopState();
|
|
337
|
+
console.log(`Remote Desktop: ${rdp.enabled ? 'Enabled' : 'Disabled'}${rdp.port === null ? '' : ` (port ${rdp.port})`}`);
|
|
338
|
+
const wrapper = runWrapper(['status'], { allowFailure: true });
|
|
339
|
+
if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
|
|
340
|
+
if (wrapper.stderr.trim()) console.error(wrapper.stderr.trim());
|
|
341
|
+
process.exitCode = bikli && wrapper.status === 0 ? 0 : 2;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function selfTest() {
|
|
345
|
+
verifyPayload();
|
|
346
|
+
const ini = fs.readFileSync(wrapperIni, 'utf8');
|
|
347
|
+
const embeddedWrapper = fs.readFileSync(wrapperScript, 'utf8');
|
|
348
|
+
const packageConfig = JSON.parse(fs.readFileSync(packageConfigFile, 'utf8'));
|
|
349
|
+
const checks = {
|
|
350
|
+
bikliInstaller: fs.statSync(bikliInstaller).size > 10000000,
|
|
351
|
+
wrapperInstaller: fs.statSync(wrapperInstaller).size > 100000,
|
|
352
|
+
targetSupport: ini.split(/\r?\n/).some(line => line.trim() === '[10.0.26100.8737]'),
|
|
353
|
+
wrapperScript: fs.statSync(wrapperScript).size > 10000,
|
|
354
|
+
enablesRemoteDesktop: embeddedWrapper.includes("name: 'fDenyTSConnections', value: 0"),
|
|
355
|
+
configuresPort3389: embeddedWrapper.includes("name: 'PortNumber', value: 3389"),
|
|
356
|
+
administratorGroup: administratorsGroupSid === 'S-1-5-32-544',
|
|
357
|
+
remoteDesktopUsersGroup: remoteDesktopUsersGroupSid === 'S-1-5-32-555',
|
|
358
|
+
administratorPasswordConfig: typeof packageConfig.administratorPassword === 'string',
|
|
359
|
+
bikliKeyConfig: typeof packageConfig.bikliKey === 'string',
|
|
360
|
+
hidesLoginAccounts: fs.readFileSync(__filename, 'utf8').includes('SpecialAccounts\\\\UserList')
|
|
361
|
+
};
|
|
362
|
+
for (const [name, passed] of Object.entries(checks)) console.log(`${passed ? 'PASS' : 'FAIL'} ${name}`);
|
|
363
|
+
if (!Object.values(checks).every(Boolean)) fail('Bikli Master self-test failed.');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function help() {
|
|
367
|
+
console.log([
|
|
368
|
+
'Bikli Master',
|
|
369
|
+
'',
|
|
370
|
+
'Commands:',
|
|
371
|
+
' biklimaster install Install/update Bikli CLI and Bikli Wrapper',
|
|
372
|
+
' biklimaster enable-rdp Enable RDP, port 3389, firewall, and defaults',
|
|
373
|
+
' biklimaster create-user Enable/verify built-in Administrator for RDP',
|
|
374
|
+
' biklimaster setup-key Apply the Bikli key from config.json (bikli up --setup-key)',
|
|
375
|
+
' biklimaster credentials Display its saved generated password',
|
|
376
|
+
' biklimaster status Show both component states',
|
|
377
|
+
' biklimaster wrapper ... Run a Bikli Wrapper CLI command',
|
|
378
|
+
' biklimaster self-test Validate package payloads without installing',
|
|
379
|
+
' biklimaster elevation-self-test Validate UAC without installing',
|
|
380
|
+
'',
|
|
381
|
+
'The global install automatically runs the install command.'
|
|
382
|
+
].join(os.EOL));
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function main() {
|
|
386
|
+
const command = (process.argv[2] || 'status').toLowerCase();
|
|
387
|
+
if (command === 'install') return install();
|
|
388
|
+
if (command === 'enable-rdp') return enableRemoteDesktop();
|
|
389
|
+
if (command === 'create-user') return createRdpAdministrator();
|
|
390
|
+
if (command === 'setup-key') return setupBikliKey();
|
|
391
|
+
if (command === 'credentials') return showAccountCredentials();
|
|
392
|
+
if (command === 'status') return status();
|
|
393
|
+
if (command === 'self-test') return selfTest();
|
|
394
|
+
if (command === 'elevation-self-test') return elevateAndRun('self-test');
|
|
395
|
+
if (command === 'wrapper') {
|
|
396
|
+
const result = runWrapper(process.argv.slice(3), { inherit: true, allowFailure: true });
|
|
397
|
+
process.exitCode = result.status === null ? 1 : result.status;
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (command === 'help' || command === '--help' || command === '-h') return help();
|
|
401
|
+
fail(`Unknown command: ${command}`);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
try {
|
|
405
|
+
main();
|
|
406
|
+
} catch (error) {
|
|
407
|
+
console.error(`Bikli Master error: ${error.message}`);
|
|
408
|
+
process.exitCode = error.exitCode || 1;
|
|
409
|
+
}
|
package/config.json
ADDED