@wlfi-agent/cli 1.4.18 → 1.4.19
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/cli.cjs +93 -4
- package/dist/cli.cjs.map +1 -1
- package/package.json +1 -1
- package/src/lib/admin-reset.ts +86 -3
- package/src/lib/admin-setup.ts +39 -0
package/package.json
CHANGED
package/src/lib/admin-reset.ts
CHANGED
|
@@ -165,6 +165,24 @@ const sudoSession = createSudoSession({
|
|
|
165
165
|
),
|
|
166
166
|
});
|
|
167
167
|
|
|
168
|
+
function isSudoWrappedInvocation(): boolean {
|
|
169
|
+
return (
|
|
170
|
+
typeof process.geteuid === 'function' &&
|
|
171
|
+
process.geteuid() === 0 &&
|
|
172
|
+
typeof process.env.SUDO_UID === 'string' &&
|
|
173
|
+
process.env.SUDO_UID.trim().length > 0
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function assertNotInvokedViaSudo(commandName: string): void {
|
|
178
|
+
if (!isSudoWrappedInvocation()) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
throw new Error(
|
|
182
|
+
`run \`wlfi-agent ${commandName}\` as your normal macOS user, not with sudo; the CLI prompts for sudo internally and running it as root can target the wrong local WLFI home`,
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
168
186
|
function createProgress(message: string, enabled = true): ProgressHandle {
|
|
169
187
|
if (!enabled) {
|
|
170
188
|
return {
|
|
@@ -226,6 +244,51 @@ function print(payload: unknown, asJson: boolean | undefined): void {
|
|
|
226
244
|
/* c8 ignore stop */
|
|
227
245
|
}
|
|
228
246
|
|
|
247
|
+
async function managedPathExists(targetPath: string): Promise<boolean> {
|
|
248
|
+
const result = await sudoSession.run(['/bin/test', '-e', targetPath]);
|
|
249
|
+
if (result.code === 0) {
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
if (
|
|
253
|
+
result.code === 1 &&
|
|
254
|
+
!/password is required|try again|authentication failed|sorry/iu.test(result.stderr)
|
|
255
|
+
) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
throw new Error(
|
|
259
|
+
result.stderr.trim() ||
|
|
260
|
+
result.stdout.trim() ||
|
|
261
|
+
`failed to inspect managed path '${targetPath}' (exit code ${result.code})`,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async function assertManagedUninstallArtifactsRemoved(targetPaths: string[]): Promise<void> {
|
|
266
|
+
const remaining: string[] = [];
|
|
267
|
+
for (const targetPath of targetPaths) {
|
|
268
|
+
if (await managedPathExists(targetPath)) {
|
|
269
|
+
remaining.push(targetPath);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (remaining.length > 0) {
|
|
273
|
+
throw new Error(
|
|
274
|
+
`admin uninstall left managed root-owned files behind: ${remaining.join(', ')}`,
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function assertLocalUninstallArtifactsRemoved(result: CleanupLocalAdminUninstallStateResult): void {
|
|
280
|
+
const remaining: string[] = [];
|
|
281
|
+
if (result.config.existed && fs.existsSync(result.config.path)) {
|
|
282
|
+
remaining.push(result.config.path);
|
|
283
|
+
}
|
|
284
|
+
if (result.wlfiHome.existed && fs.existsSync(result.wlfiHome.path)) {
|
|
285
|
+
remaining.push(result.wlfiHome.path);
|
|
286
|
+
}
|
|
287
|
+
if (remaining.length > 0) {
|
|
288
|
+
throw new Error(`admin uninstall left local WLFI files behind: ${remaining.join(', ')}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
229
292
|
function printResetSummary(result: {
|
|
230
293
|
daemon: {
|
|
231
294
|
label: string;
|
|
@@ -456,6 +519,7 @@ async function confirmReset(options: AdminResetOptions): Promise<void> {
|
|
|
456
519
|
}
|
|
457
520
|
|
|
458
521
|
async function runAdminReset(options: AdminResetOptions): Promise<void> {
|
|
522
|
+
assertNotInvokedViaSudo('admin reset');
|
|
459
523
|
await confirmReset(options);
|
|
460
524
|
const showProgress = !options.json;
|
|
461
525
|
const keychainAccount = os.userInfo().username;
|
|
@@ -607,6 +671,7 @@ function printUninstallSummary(result: {
|
|
|
607
671
|
}
|
|
608
672
|
|
|
609
673
|
async function runAdminUninstall(options: AdminUninstallOptions): Promise<void> {
|
|
674
|
+
assertNotInvokedViaSudo('admin uninstall');
|
|
610
675
|
await confirmUninstall(options);
|
|
611
676
|
const showProgress = !options.json;
|
|
612
677
|
const keychainAccount = os.userInfo().username;
|
|
@@ -670,11 +735,29 @@ async function runAdminUninstall(options: AdminUninstallOptions): Promise<void>
|
|
|
670
735
|
|| `failed to delete managed root-owned files (exit code ${deleteRootArtifactsResult.code})`,
|
|
671
736
|
);
|
|
672
737
|
}
|
|
673
|
-
|
|
738
|
+
try {
|
|
739
|
+
await assertManagedUninstallArtifactsRemoved([
|
|
740
|
+
DEFAULT_LAUNCH_DAEMON_PLIST,
|
|
741
|
+
DEFAULT_MANAGED_ROOT_DIR,
|
|
742
|
+
DEFAULT_MANAGED_STATE_DIR,
|
|
743
|
+
DEFAULT_MANAGED_LOG_DIR,
|
|
744
|
+
]);
|
|
745
|
+
rootProgress.succeed('Managed root-owned files removed');
|
|
746
|
+
} catch (error) {
|
|
747
|
+
rootProgress.fail();
|
|
748
|
+
throw error;
|
|
749
|
+
}
|
|
674
750
|
|
|
675
751
|
const localProgress = createProgress('Removing local WLFI files and credentials', showProgress);
|
|
676
|
-
|
|
677
|
-
|
|
752
|
+
let local: CleanupLocalAdminUninstallStateResult;
|
|
753
|
+
try {
|
|
754
|
+
local = cleanupLocalAdminUninstallState();
|
|
755
|
+
assertLocalUninstallArtifactsRemoved(local);
|
|
756
|
+
localProgress.succeed('Local WLFI files and credentials removed');
|
|
757
|
+
} catch (error) {
|
|
758
|
+
localProgress.fail();
|
|
759
|
+
throw error;
|
|
760
|
+
}
|
|
678
761
|
|
|
679
762
|
const result = {
|
|
680
763
|
command: 'uninstall',
|
package/src/lib/admin-setup.ts
CHANGED
|
@@ -393,6 +393,35 @@ function resolveStateFile(): string {
|
|
|
393
393
|
return path.resolve(DEFAULT_MANAGED_STATE_FILE);
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
+
function resolveDefaultActiveChainForFreshSetup(
|
|
397
|
+
config: WlfiConfig,
|
|
398
|
+
): { chainId: number; chainName: string; rpcUrl?: string } | null {
|
|
399
|
+
try {
|
|
400
|
+
const profile = resolveCliNetworkProfile('bsc', config);
|
|
401
|
+
return {
|
|
402
|
+
chainId: profile.chainId,
|
|
403
|
+
chainName: profile.key?.trim() || profile.name.trim().toLowerCase() || 'bsc',
|
|
404
|
+
...(profile.rpcUrl?.trim() ? { rpcUrl: profile.rpcUrl.trim() } : {}),
|
|
405
|
+
};
|
|
406
|
+
} catch {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function shouldSeedDefaultActiveChain(
|
|
412
|
+
options: Pick<AdminSetupOptions, 'network' | 'rpcUrl' | 'chainName'>,
|
|
413
|
+
config: WlfiConfig,
|
|
414
|
+
): boolean {
|
|
415
|
+
return (
|
|
416
|
+
!options.network &&
|
|
417
|
+
!options.rpcUrl &&
|
|
418
|
+
!options.chainName &&
|
|
419
|
+
config.chainId === undefined &&
|
|
420
|
+
!config.chainName?.trim() &&
|
|
421
|
+
!config.rpcUrl?.trim()
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
396
425
|
export function createAdminSetupPlan(
|
|
397
426
|
options: AdminSetupOptions,
|
|
398
427
|
deps: CreateAdminSetupPlanDeps = {},
|
|
@@ -1293,6 +1322,9 @@ async function runAdminSetup(options: AdminSetupOptions): Promise<void> {
|
|
|
1293
1322
|
const config = readConfig();
|
|
1294
1323
|
const daemonSocket = resolveDaemonSocket(options.daemonSocket);
|
|
1295
1324
|
const stateFile = resolveStateFile();
|
|
1325
|
+
const defaultActiveChain = shouldSeedDefaultActiveChain(options, config)
|
|
1326
|
+
? resolveDefaultActiveChainForFreshSetup(config)
|
|
1327
|
+
: null;
|
|
1296
1328
|
const reusableWallet = options.reuseExistingWallet
|
|
1297
1329
|
? resolveReusableWalletSetupTarget(config)
|
|
1298
1330
|
: null;
|
|
@@ -1588,6 +1620,13 @@ async function runAdminSetup(options: AdminSetupOptions): Promise<void> {
|
|
|
1588
1620
|
const persistedConfig = writeConfig({
|
|
1589
1621
|
daemonSocket,
|
|
1590
1622
|
stateFile,
|
|
1623
|
+
...(defaultActiveChain
|
|
1624
|
+
? {
|
|
1625
|
+
chainId: defaultActiveChain.chainId,
|
|
1626
|
+
chainName: defaultActiveChain.chainName,
|
|
1627
|
+
...(defaultActiveChain.rpcUrl ? { rpcUrl: defaultActiveChain.rpcUrl } : {}),
|
|
1628
|
+
}
|
|
1629
|
+
: {}),
|
|
1591
1630
|
});
|
|
1592
1631
|
|
|
1593
1632
|
printCliPayload(
|