Skip to content

Commit

Permalink
feat: add ledger key ring protocol commands in cli
Browse files Browse the repository at this point in the history
  • Loading branch information
KVNLS committed Oct 2, 2024
1 parent f871795 commit 2f6defb
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 1 deletion.
19 changes: 19 additions & 0 deletions apps/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,25 @@ Usage: ledger-live i18n # Test e2e functionality for device localization s
Usage: ledger-live listApps # list all installed apps on the device
-d, --device <String> : provide a specific HID path of a device
Usage: ledger-live ledgerKeyRingProtocol # Ledger Key Ring Protocol command
-d, --device <String> : provide a specific HID path of a device
--initMemberCredentials : Init member credentials for Ledger Key Ring Protocol
--getKeyRingTree : Get or create a Ledger Key Ring Protocol Tree
--encryptUserData : Encrypt user data with the current private key secured by the Ledger Key Ring Protocol
--decryptUserData : Encrypt user data with the current private key secured by the Ledger Key Ring Protocol
--getMembers : Get members of the Ledger Key Ring Protocol Tree
--restoreKeyRingTree : Restore a Ledger Key Ring Protocol Tree
--destroyKeyRingTree : Destroy a Ledger Key Ring Protocol Tree
--pubKey <String> : pubkey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result
--privateKey <String> : privatekey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result
--rootId <String> : The immutable id of the Tree root retrieved from getKeyRingTree result
--walletSyncEncryptionKey <String>: The secret used to encrypt/decrypt the wallet sync data retrieved from getKeyRingTree result
--applicationPath <String>: privatekey for Ledger Key Ring Protocol Tree from initMemberCredentials result
--message <String> : message to be encrypted/decrypted
--applicationId <Number> : application identifier
--name <String> : name of the instance
--apiBaseUrl <String> : api base url for Ledger Key Ring Protocol
Usage: ledger-live liveData # utility for Ledger Live app.json file
-d, --device <String> : provide a specific HID path of a device
--xpub <String> : use an xpub (alternatively to --device) [DEPRECATED: prefer use of id]
Expand Down
2 changes: 2 additions & 0 deletions apps/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
"@ledgerhq/device-core": "workspace:^",
"@ledgerhq/devices": "workspace:^",
"@ledgerhq/errors": "workspace:^",
"@ledgerhq/ledger-key-ring-protocol": "workspace:^",
"@ledgerhq/hw-app-btc": "workspace:^",
"@ledgerhq/hw-ledger-key-ring-protocol": "workspace:^",
"@ledgerhq/hw-transport": "workspace:^",
"@ledgerhq/hw-transport-http": "workspace:^",
"@ledgerhq/hw-transport-mocker": "workspace:^",
Expand Down
2 changes: 2 additions & 0 deletions apps/cli/src/commands-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import balanceHistory from "./commands/live/balanceHistory";
import countervalues from "./commands/live/countervalues";
import envs from "./commands/live/envs";
import exportAccounts from "./commands/live/exportAccounts";
import ledgerKeyRingProtocol from "./commands/live/ledgerKeyRingProtocol";
import liveData from "./commands/live/liveData";
import portfolio from "./commands/live/portfolio";
import synchronousOnboarding from "./commands/live/synchronousOnboarding";
Expand Down Expand Up @@ -118,6 +119,7 @@ export default {
countervalues,
envs,
exportAccounts,
ledgerKeyRingProtocol,
liveData,
portfolio,
synchronousOnboarding,
Expand Down
195 changes: 195 additions & 0 deletions apps/cli/src/commands/live/ledgerKeyRingProtocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import { getSdk } from "@ledgerhq/ledger-key-ring-protocol/index";
import { crypto } from "@ledgerhq/hw-ledger-key-ring-protocol";
import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import { getEnv } from "@ledgerhq/live-env";
import { deviceOpt } from "../../scan";

export default {
description: "Ledger Key Ring Protocol command",
args: [
deviceOpt,
{
name: "initMemberCredentials",
type: Boolean,
desc: "Init member credentials for Ledger Key Ring Protocol",
},
{
name: "getKeyRingTree",
type: Boolean,
desc: "Get or create a Ledger Key Ring Protocol Tree",
},
{
name: "encryptUserData",
type: Boolean,
desc: "Encrypt user data with the current private key secured by the Ledger Key Ring Protocol",
},
{
name: "decryptUserData",
type: Boolean,
desc: "Encrypt user data with the current private key secured by the Ledger Key Ring Protocol",
},
{
name: "getMembers",
type: Boolean,
desc: "Get members of the Ledger Key Ring Protocol Tree",
},
{
name: "restoreKeyRingTree",
type: Boolean,
desc: "Restore a Ledger Key Ring Protocol Tree",
},
{
name: "destroyKeyRingTree",
type: Boolean,
desc: "Destroy a Ledger Key Ring Protocol Tree",
},
{
name: "pubKey",
type: String,
desc: "pubkey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result",
},
{
name: "privateKey",
type: String,
desc: "privatekey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result",
},
{
name: "rootId",
type: String,
desc: "The immutable id of the Tree root retrieved from getKeyRingTree result",
},
{
name: "walletSyncEncryptionKey",
type: String,
desc: "The secret used to encrypt/decrypt the wallet sync data retrieved from getKeyRingTree result",
},
{
name: "applicationPath",
type: String,
desc: "privatekey for Ledger Key Ring Protocol Tree from initMemberCredentials result",
},
{
name: "message",
type: String,
desc: "message to be encrypted/decrypted",
},
{
name: "applicationId",
type: Number,
default: 16,
desc: "application identifier",
},
{
name: "name",
type: String,
default: "CLI",
desc: "name of the instance",
},
{
name: "apiBaseUrl",
type: String,
default: getEnv("TRUSTCHAIN_API_STAGING"),
desc: "api base url for Ledger Key Ring Protocol",
},
],
job: ({
device,
initMemberCredentials,
getKeyRingTree,
encryptUserData,
decryptUserData,
getMembers,
restoreKeyRingTree,
destroyKeyRingTree,
pubKey,
privateKey,
rootId,
walletSyncEncryptionKey,
applicationPath,
message,
applicationId = 16,
name = "CLI",
apiBaseUrl = getEnv("TRUSTCHAIN_API_STAGING"),
}: Partial<{
device: string;
initMemberCredentials: boolean;
getKeyRingTree: boolean;
getMembers: boolean;
encryptUserData: boolean;
decryptUserData: boolean;
restoreKeyRingTree: boolean;
destroyKeyRingTree: boolean;
pubKey: string;
privateKey: string;
rootId: string;
walletSyncEncryptionKey: string;
applicationPath: string;
message: string;
applicationId: number;
name: string;
apiBaseUrl: string;
}>) => {
if (!applicationId) return "applicationId is required";
if (!name) return "name is required";
if (!apiBaseUrl) return "apiBaseUrl is required";

const context = {
applicationId,
name,
apiBaseUrl,
};
const sdk = getSdk(false, context, withDevice);

if (initMemberCredentials) {
return sdk.initMemberCredentials();
}

if (getKeyRingTree) {
if (!pubKey || !privateKey) return "pubKey and privateKey are required";
return sdk
.getOrCreateTrustchain(device || "", { pubkey: pubKey, privatekey: privateKey })
.then(result => result.trustchain);
}

if (getMembers || restoreKeyRingTree || destroyKeyRingTree) {
if (!pubKey || !privateKey) return "pubKey and privateKey are required";
if (!rootId) return "pubKey and privateKey are required";
if (!walletSyncEncryptionKey) return "walletSyncEncryptionKey is required";
if (!applicationPath) return "applicationPath is required";

const sdkMethod = getMembers
? "getMembers"
: restoreKeyRingTree
? "restoreTrustchain"
: "destroyTrustchain";
return sdk[sdkMethod](
{ rootId, walletSyncEncryptionKey, applicationPath },
{ pubkey: pubKey, privatekey: privateKey },
);
}

if (encryptUserData || decryptUserData) {
if (!rootId) return "rootId is required";
if (!walletSyncEncryptionKey) return "walletSyncEncryptionKey is required";
if (!applicationPath) return "applicationPath is required";
if (!message) return "message is required";

if (encryptUserData) {
return sdk
.encryptUserData(
{ rootId, walletSyncEncryptionKey, applicationPath },
new TextEncoder().encode(message),
)
.then(array => Buffer.from(array).toString("hex"));
}
return sdk
.decryptUserData(
{ rootId, walletSyncEncryptionKey, applicationPath },
crypto.from_hex(message),
)
.then(array => new TextDecoder().decode(array));
}

return "command does not exist";
},
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"doc:ljs": "pnpm turbo doc --no-daemon --filter=\"./libs/ledgerjs/**\"",
"watch:ljs": "pnpm turbo watch --no-daemon --filter=\"./libs/ledgerjs/**\"",
"watch:common": "pnpm turbo watch --no-daemon --filter=./libs/ledger-live-common",
"dev:cli": "pnpm turbo watch --no-daemon --filter=@ledgerhq/live-cli",
"dev:cli": "pnpm turbo watch --filter=@ledgerhq/live-cli",
"dev:lld": "pnpm turbo start --no-daemon --filter=ledger-live-desktop",
"dev:lld:debug": "DEV_TOOLS=1 LEDGER_INTERNAL_ARGS=--inspect ELECTRON_ARGS=--remote-debugging-port=8315 pnpm turbo start --no-daemon --filter=ledger-live-desktop",
"dev:llm": "pnpm turbo start --no-daemon --filter=live-mobile",
Expand Down
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2f6defb

Please sign in to comment.