v0.2.6-pre.012
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-wallet-desk/frontend/ts/main.ts
|
||||
// version: 12
|
||||
// version: 13
|
||||
|
||||
import { Modal } from "bootstrap";
|
||||
import DataTable from "datatables.net-bs5";
|
||||
@@ -10,9 +10,11 @@ import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||
import type { WalletBalanceDto } from "./bindings/ksp_app_wallet_desk/wallet_balance/WalletBalanceDto.ts";
|
||||
import type { CommandErrorDto } from "./bindings/ksp_app_wallet_desk/dto_common/CommandErrorDto.ts";
|
||||
import type { RuntimeStatusDto } from "./bindings/ksp_app_wallet_desk/dto_common/RuntimeStatusDto.ts";
|
||||
import type { WalletExportRequestDto } from "./bindings/ksp_app_wallet_desk/wallet_export/WalletExportRequestDto.ts";
|
||||
import type { WalletExportResultDto } from "./bindings/ksp_app_wallet_desk/wallet_export/WalletExportResultDto.ts";
|
||||
import type { WalletImportRequestDto } from "./bindings/ksp_app_wallet_desk/wallet_import/WalletImportRequestDto.ts";
|
||||
import type { WalletImportSourceRequestDto } from "./bindings/ksp_app_wallet_desk/wallet_import/WalletImportSourceRequestDto.ts";
|
||||
import type { WalletTransferFormatDto } from "./bindings/ksp_app_wallet_desk/wallet_import/WalletTransferFormatDto.ts";
|
||||
import type { WalletTransferFormatDto } from "./bindings/ksp_app_wallet_desk/wallet_transfer/WalletTransferFormatDto.ts";
|
||||
import type { WalletTransferInspectionDto } from "./bindings/ksp_app_wallet_desk/wallet_import/WalletTransferInspectionDto.ts";
|
||||
import type { LockedWalletDto } from "./bindings/ksp_app_wallet_desk/wallet_inventory/LockedWalletDto.ts";
|
||||
import type { WalletInventoryEntryDto } from "./bindings/ksp_app_wallet_desk/wallet_inventory/WalletInventoryEntryDto.ts";
|
||||
@@ -54,6 +56,7 @@ let authorizedWalletProjection: WalletAuthorizedDto | null = null;
|
||||
let configuredSecretCandidateCount = 0;
|
||||
let deleteNoteModal: Modal | null = null;
|
||||
let disableViewModal: Modal | null = null;
|
||||
let exportWalletModal: Modal | null = null;
|
||||
let recreateViewModal: Modal | null = null;
|
||||
let pendingDeleteNoteId: string | null = null;
|
||||
let stagedImportSource: WalletTransferInspectionDto | null = null;
|
||||
@@ -187,7 +190,7 @@ function initializeWalletTable(): void {
|
||||
zeroRecords: "Aucun wallet correspondant.",
|
||||
},
|
||||
});
|
||||
frontendDebug("main", "Wallet inventory DataTable initialized", { phase: "pre.011-strong-view-administration" });
|
||||
frontendDebug("main", "Wallet inventory DataTable initialized", { phase: "pre.012-owner-transfer-export" });
|
||||
}
|
||||
|
||||
function renderWalletInventory(entries: WalletInventoryEntryDto[]): void {
|
||||
@@ -227,6 +230,7 @@ function updateSessionActions(): void {
|
||||
updateOwnerMetadataActions();
|
||||
updateSecurityRotationActions();
|
||||
updateStrongViewSecurityActions();
|
||||
updateWalletExportActions();
|
||||
}
|
||||
|
||||
function updateOwnerMetadataActions(): void {
|
||||
@@ -259,6 +263,13 @@ function updateStrongViewSecurityActions(): void {
|
||||
});
|
||||
}
|
||||
|
||||
function updateWalletExportActions(): void {
|
||||
const ownerOpen = activeSessionState === "owner_open" && authorizedWalletProjection?.capability === "owner";
|
||||
document.querySelectorAll<HTMLSelectElement | HTMLButtonElement>("[data-owner-export-control]").forEach(control => {
|
||||
control.disabled = !ownerOpen;
|
||||
});
|
||||
}
|
||||
|
||||
function updateUnlockActions(): void {
|
||||
const locked = activeSessionState === "locked";
|
||||
const viewManual = document.querySelector<HTMLButtonElement>("#unlockViewManual");
|
||||
@@ -392,6 +403,7 @@ function clearAuthorizedProjection(): void {
|
||||
clearUnlockSensitiveInputs();
|
||||
setText("#rotationStatus", "Session OWNER requise.");
|
||||
setText("#viewSecurityStatus", "Session OWNER requise pour administrer fortement VIEW.");
|
||||
setText("#walletExportStatus", "Session OWNER requise. Aucun export texte ou clipboard n’est disponible.");
|
||||
}
|
||||
|
||||
function clearSelectedWallet(): void {
|
||||
@@ -430,6 +442,7 @@ function renderLockedWallet(wallet: LockedWalletDto): void {
|
||||
setText("#currentWalletSecretCandidates", configuredSecretCandidateCount.toString());
|
||||
setText("#unlockStatus", "Prêt pour une tentative explicite. Argon2 peut prendre plusieurs secondes.");
|
||||
setText("#viewSecurityStatus", "Unlock OWNER requis pour administrer fortement VIEW.");
|
||||
setText("#walletExportStatus", "Unlock OWNER requis pour exporter la keypair Solana.");
|
||||
updateSessionActions();
|
||||
frontendDebug("main", "Locked Wallet selection rendered", {
|
||||
configuredSecretCandidateCount,
|
||||
@@ -481,6 +494,12 @@ function renderAuthorizedWallet(wallet: WalletAuthorizedDto): void {
|
||||
: "OWNER ouvert : VIEW disabled. Strong recreate disponible."
|
||||
: "VIEW ouvert : l’administration forte VIEW est réservée à OWNER.",
|
||||
);
|
||||
setText(
|
||||
"#walletExportStatus",
|
||||
wallet.capability === "owner"
|
||||
? "OWNER ouvert : export fichier Solana CLI JSON ou Base58 disponible via save picker natif."
|
||||
: "VIEW ouvert : export de keypair interdit ; OWNER requis.",
|
||||
);
|
||||
updateSessionActions();
|
||||
frontendDebug("main", "Authorized Wallet session rendered", {
|
||||
capability: wallet.capability,
|
||||
@@ -1244,6 +1263,67 @@ function bindStrongViewSecurityActions(): void {
|
||||
frontendTrace("main", "Strong VIEW security action handlers installed");
|
||||
}
|
||||
|
||||
async function runWalletExport(walletId: string, format: WalletTransferFormatDto): Promise<void> {
|
||||
activeSessionState = "privileged_operation";
|
||||
setText("#currentWalletState", "OWNER export…");
|
||||
setText("#walletExportStatus", "Save picker natif / export secret en cours…");
|
||||
updateSessionActions();
|
||||
frontendDebug("main", "Wallet OWNER transfer export requested", { format, walletId });
|
||||
const request: WalletExportRequestDto = { format };
|
||||
try {
|
||||
const result = await invokeKsp<WalletExportResultDto | null>("main", "export_wallet_transfer", { request });
|
||||
if (activeWalletId !== walletId || authorizedWalletProjection?.capability !== "owner") {
|
||||
frontendWarn("main", "Stale Wallet export response ignored", { format, walletId });
|
||||
return;
|
||||
}
|
||||
activeSessionState = "owner_open";
|
||||
setText("#currentWalletState", "OWNER open");
|
||||
if (result === null) {
|
||||
setText("#walletExportStatus", "Export annulé dans le save picker natif ; aucun fichier créé.");
|
||||
updateSessionActions();
|
||||
frontendDebug("main", "Wallet OWNER transfer export cancelled", { format, walletId });
|
||||
return;
|
||||
}
|
||||
setText("#walletExportStatus", `Export ${importFormatLabel(result.format)} créé : ${result.destinationName}. Le chemin complet et le contenu secret n’ont pas traversé IPC.`);
|
||||
updateSessionActions();
|
||||
frontendInfo("main", "Wallet OWNER transfer export completed", { format: result.format, walletId });
|
||||
} catch {
|
||||
if (activeWalletId === walletId && authorizedWalletProjection?.capability === "owner") {
|
||||
activeSessionState = "owner_open";
|
||||
setText("#currentWalletState", "OWNER open");
|
||||
setText("#walletExportStatus", "Export refusé ou impossible ; aucun écrasement n’est autorisé et la session OWNER reste ouverte.");
|
||||
updateSessionActions();
|
||||
}
|
||||
frontendWarn("main", "Wallet OWNER transfer export failed", { format, walletId });
|
||||
}
|
||||
}
|
||||
|
||||
function bindWalletExportActions(): void {
|
||||
const modalElement = document.querySelector<HTMLElement>("#exportWalletKeypairModal");
|
||||
if (modalElement) {
|
||||
exportWalletModal = new Modal(modalElement);
|
||||
}
|
||||
document.querySelector<HTMLButtonElement>("#exportWalletKeypair")?.addEventListener("click", () => {
|
||||
if (!activeWalletId || activeSessionState !== "owner_open" || authorizedWalletProjection?.capability !== "owner") {
|
||||
setText("#walletExportStatus", "Session OWNER requise.");
|
||||
return;
|
||||
}
|
||||
frontendDebug("main", "Wallet OWNER transfer export confirmation opened", { walletId: activeWalletId });
|
||||
exportWalletModal?.show();
|
||||
});
|
||||
document.querySelector<HTMLButtonElement>("#confirmExportWalletKeypair")?.addEventListener("click", () => {
|
||||
const walletId = activeWalletId;
|
||||
const formatControl = document.querySelector<HTMLSelectElement>("#walletExportFormat");
|
||||
exportWalletModal?.hide();
|
||||
if (!walletId || activeSessionState !== "owner_open" || authorizedWalletProjection?.capability !== "owner" || !formatControl) {
|
||||
return;
|
||||
}
|
||||
const format = formatControl.value as WalletTransferFormatDto;
|
||||
void runWalletExport(walletId, format);
|
||||
});
|
||||
frontendTrace("main", "Wallet OWNER transfer export handlers installed");
|
||||
}
|
||||
|
||||
function bindRotationActions(): void {
|
||||
document.querySelector<HTMLButtonElement>("#rotateOwnerPasswordSubmit")?.addEventListener("click", () => {
|
||||
void rotateWalletPassword("owner");
|
||||
@@ -1357,7 +1437,7 @@ function renderRuntimeStatus(status: RuntimeStatusDto): void {
|
||||
setText("#runtimeEffectiveWalletsDirectory", status.effectiveWalletsDirectory);
|
||||
setText("#runtimeWalletDirectoryCreated", status.effectiveWalletsDirectoryCreatedOnStartup ? "oui" : "non, déjà présent");
|
||||
setText("#runtimeShellPhase", status.shellPhase);
|
||||
setText("#shellStatus", "Config/Transport résolus ; import, VIEW/OWNER, metadata, rotations, strong VIEW et getBalance prêts.");
|
||||
setText("#shellStatus", "Config/Transport résolus ; import/export, VIEW/OWNER, metadata, rotations, strong VIEW et getBalance prêts.");
|
||||
frontendTrace("main", "Wallet Desk runtime status rendered", {
|
||||
compositeProfile: status.activeCompositeProfile,
|
||||
fallbackLoggingActive: status.fallbackLoggingActive,
|
||||
@@ -1411,6 +1491,7 @@ async function initializeMain(): Promise<void> {
|
||||
bindOwnerMetadataActions();
|
||||
bindRotationActions();
|
||||
bindStrongViewSecurityActions();
|
||||
bindWalletExportActions();
|
||||
bindShellActions();
|
||||
clearSelectedWallet();
|
||||
activateView("dashboard", "startup");
|
||||
|
||||
Reference in New Issue
Block a user