From dcada888ccad52058a00ec48c43548569e397b3f Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Tue, 22 Jul 2025 10:38:15 +0200 Subject: [PATCH 01/13] =?UTF-8?q?=E2=9C=A8=20Adding=20accounts=20with=20pr?= =?UTF-8?q?ivate=20export=20as=20PDF=20with=20QRCode=20or=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- package-lock.json | 859 +++++++++++++++++++++++--- package.json | 4 +- src/commands/key/export.ts | 111 ++++ src/constants.ts | 11 + src/fixtures/fonts/roboto-regular.ttf | Bin 0 -> 152588 bytes src/utils/pdfExport.ts | 96 +++ src/utils/pubkeyToAccount.ts | 42 ++ src/utils/toText.ts | 8 + 9 files changed, 1060 insertions(+), 75 deletions(-) create mode 100644 src/commands/key/export.ts create mode 100644 src/fixtures/fonts/roboto-regular.ttf create mode 100644 src/utils/pdfExport.ts create mode 100644 src/utils/pubkeyToAccount.ts create mode 100644 src/utils/toText.ts diff --git a/.gitignore b/.gitignore index d153938..6f85038 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ /lib /tmp node_modules -tsconfig.tsbuildinfo \ No newline at end of file +tsconfig.tsbuildinfo + +.DS_Store \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 769bd03..64b8654 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "@proton/mnemonic": "^0.5.0", "@proton/signing-request": "^4.1.10", "@proton/wrap-constants": "^0.2.184", + "@types/pdfmake": "^0.2.11", "bignumber.js": "^9.0.2", "colors": "^1.4.0", "conf": "^10.1.2", @@ -33,6 +34,7 @@ "lodash.isequal": "^4.5.0", "open": "^8.4.0", "pako": "^2.0.4", + "pdfmake": "^0.2.20", "qrcode": "^1.5.0", "rimraf": "^3.0.2", "shelljs": "^0.8.5", @@ -647,6 +649,57 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/@foliojs-fork/fontkit": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@foliojs-fork/fontkit/-/fontkit-1.9.2.tgz", + "integrity": "sha512-IfB5EiIb+GZk+77TRB86AHroVaqfq8JRFlUbz0WEwsInyCG0epX2tCPOy+UfaWPju30DeVoUAXfzWXmhn753KA==", + "license": "MIT", + "dependencies": { + "@foliojs-fork/restructure": "^2.0.2", + "brotli": "^1.2.0", + "clone": "^1.0.4", + "deep-equal": "^1.0.0", + "dfa": "^1.2.0", + "tiny-inflate": "^1.0.2", + "unicode-properties": "^1.2.2", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/@foliojs-fork/linebreak": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@foliojs-fork/linebreak/-/linebreak-1.1.2.tgz", + "integrity": "sha512-ZPohpxxbuKNE0l/5iBJnOAfUaMACwvUIKCvqtWGKIMv1lPYoNjYXRfhi9FeeV9McBkBLxsMFWTVVhHJA8cyzvg==", + "license": "MIT", + "dependencies": { + "base64-js": "1.3.1", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/@foliojs-fork/linebreak/node_modules/base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "license": "MIT" + }, + "node_modules/@foliojs-fork/pdfkit": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/@foliojs-fork/pdfkit/-/pdfkit-0.15.3.tgz", + "integrity": "sha512-Obc0Wmy3bm7BINFVvPhcl2rnSSK61DQrlHU8aXnAqDk9LCjWdUOPwhgD8Ywz5VtuFjRxmVOM/kQ/XLIBjDvltw==", + "license": "MIT", + "dependencies": { + "@foliojs-fork/fontkit": "^1.9.2", + "@foliojs-fork/linebreak": "^1.1.1", + "crypto-js": "^4.2.0", + "jpeg-exif": "^1.1.4", + "png-js": "^1.0.0" + } + }, + "node_modules/@foliojs-fork/restructure": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@foliojs-fork/restructure/-/restructure-2.0.2.tgz", + "integrity": "sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA==", + "license": "MIT" + }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -1869,11 +1922,6 @@ "ripemd-ts": "0.0.2" } }, - "node_modules/@proton/js/node_modules/@bloks/constants": { - "version": "28.8.3", - "resolved": "https://registry.npmjs.org/@bloks/constants/-/constants-28.8.3.tgz", - "integrity": "sha512-9pTMxfij1Vwfhncl7NLvDUxPFAKzfVL2F8HVjHKj+mzBvKSCY+VOg2CM3Ob7TTo5PJD5MiH0VnHAYQLoLAp1Vw==" - }, "node_modules/@proton/js/node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", @@ -2247,6 +2295,25 @@ "@types/node": "*" } }, + "node_modules/@types/pdfkit": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/pdfkit/-/pdfkit-0.17.1.tgz", + "integrity": "sha512-zZW1cmTxWTGAfZSdFzxjTScHnzCdt2sn2YiPLxYOLFgL+S2liTTGE6p4tu8aYq+A+l1TymwR274qrmpT7CzRRw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/pdfmake": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@types/pdfmake/-/pdfmake-0.2.11.tgz", + "integrity": "sha512-gglgMQhnG6C2kco13DJlvokqTxL+XKxHwCejElH8fSCNF9ZCkRK6Mzo011jQ0zuug+YlIgn6BpcpZrARyWdW3Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/pdfkit": "*" + } + }, "node_modules/@types/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", @@ -3119,6 +3186,15 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.1.2" + } + }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -3319,16 +3395,44 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -3963,6 +4067,12 @@ "node": ">= 8" } }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" + }, "node_modules/dargs": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", @@ -4072,6 +4182,26 @@ "node": ">=0.12" } }, + "node_modules/deep-equal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", + "license": "MIT", + "dependencies": { + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.5.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -4132,6 +4262,23 @@ "node": ">=8" } }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4181,6 +4328,12 @@ "wrappy": "1" } }, + "node_modules/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", + "license": "MIT" + }, "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -4237,6 +4390,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ejs": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", @@ -4354,13 +4521,10 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -4374,6 +4538,18 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -5535,6 +5711,15 @@ "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "dev": true }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -5582,16 +5767,21 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5608,6 +5798,19 @@ "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -5739,12 +5942,12 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5825,10 +6028,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -5837,11 +6040,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { "node": ">= 0.4" }, @@ -6179,6 +6385,22 @@ "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", "dev": true }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -6220,6 +6442,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -6319,6 +6557,24 @@ "node": ">=0.10.0" } }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-retry-allowed": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", @@ -6604,6 +6860,12 @@ "node": ">= 0.6.0" } }, + "node_modules/jpeg-exif": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz", + "integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==", + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7000,6 +7262,15 @@ "node": ">= 10" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -8272,6 +8543,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/object-treeify": { "version": "1.1.33", "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", @@ -8813,6 +9109,33 @@ "node": ">=0.12" } }, + "node_modules/pdfmake": { + "version": "0.2.20", + "resolved": "https://registry.npmjs.org/pdfmake/-/pdfmake-0.2.20.tgz", + "integrity": "sha512-bGbxbGFP5p8PWNT3Phsu1ZcRLnRfF6jmnuKTkgmt6i5PZzSdX6JaB+NeTz9q+aocfW8SE9GUjL3o/5GroBqGcQ==", + "license": "MIT", + "dependencies": { + "@foliojs-fork/linebreak": "^1.1.2", + "@foliojs-fork/pdfkit": "^0.15.3", + "iconv-lite": "^0.6.3", + "xmldoc": "^2.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/pdfmake/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -8978,6 +9301,11 @@ "node": ">=4" } }, + "node_modules/png-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz", + "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==" + }, "node_modules/pngjs": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", @@ -9712,6 +10040,26 @@ "regexp-tree": "bin/regexp-tree" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -10039,6 +10387,21 @@ "node": ">= 0.4" } }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -10660,6 +11023,12 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, "node_modules/tiny-secp256k1": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.1.tgz", @@ -10884,6 +11253,32 @@ "node": ">=14.0.0" } }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, "node_modules/unique-filename": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", @@ -11256,6 +11651,24 @@ "node": ">=4.0" } }, + "node_modules/xmldoc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-2.0.2.tgz", + "integrity": "sha512-UiRwoSStEXS3R+YE8OqYv3jebza8cBBAI2y8g3B15XFkn3SbEOyyLnmPHjLBPZANrPJKEzxxB7A3XwcLikQVlQ==", + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/xmldoc/node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -12226,6 +12639,54 @@ } } }, + "@foliojs-fork/fontkit": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@foliojs-fork/fontkit/-/fontkit-1.9.2.tgz", + "integrity": "sha512-IfB5EiIb+GZk+77TRB86AHroVaqfq8JRFlUbz0WEwsInyCG0epX2tCPOy+UfaWPju30DeVoUAXfzWXmhn753KA==", + "requires": { + "@foliojs-fork/restructure": "^2.0.2", + "brotli": "^1.2.0", + "clone": "^1.0.4", + "deep-equal": "^1.0.0", + "dfa": "^1.2.0", + "tiny-inflate": "^1.0.2", + "unicode-properties": "^1.2.2", + "unicode-trie": "^2.0.0" + } + }, + "@foliojs-fork/linebreak": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@foliojs-fork/linebreak/-/linebreak-1.1.2.tgz", + "integrity": "sha512-ZPohpxxbuKNE0l/5iBJnOAfUaMACwvUIKCvqtWGKIMv1lPYoNjYXRfhi9FeeV9McBkBLxsMFWTVVhHJA8cyzvg==", + "requires": { + "base64-js": "1.3.1", + "unicode-trie": "^2.0.0" + }, + "dependencies": { + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + } + } + }, + "@foliojs-fork/pdfkit": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/@foliojs-fork/pdfkit/-/pdfkit-0.15.3.tgz", + "integrity": "sha512-Obc0Wmy3bm7BINFVvPhcl2rnSSK61DQrlHU8aXnAqDk9LCjWdUOPwhgD8Ywz5VtuFjRxmVOM/kQ/XLIBjDvltw==", + "requires": { + "@foliojs-fork/fontkit": "^1.9.2", + "@foliojs-fork/linebreak": "^1.1.1", + "crypto-js": "^4.2.0", + "jpeg-exif": "^1.1.4", + "png-js": "^1.0.0" + } + }, + "@foliojs-fork/restructure": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@foliojs-fork/restructure/-/restructure-2.0.2.tgz", + "integrity": "sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA==" + }, "@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -13284,11 +13745,6 @@ "ripemd-ts": "0.0.2" }, "dependencies": { - "@bloks/constants": { - "version": "28.8.3", - "resolved": "https://registry.npmjs.org/@bloks/constants/-/constants-28.8.3.tgz", - "integrity": "sha512-9pTMxfij1Vwfhncl7NLvDUxPFAKzfVL2F8HVjHKj+mzBvKSCY+VOg2CM3Ob7TTo5PJD5MiH0VnHAYQLoLAp1Vw==" - }, "bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", @@ -13639,6 +14095,23 @@ "@types/node": "*" } }, + "@types/pdfkit": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/pdfkit/-/pdfkit-0.17.1.tgz", + "integrity": "sha512-zZW1cmTxWTGAfZSdFzxjTScHnzCdt2sn2YiPLxYOLFgL+S2liTTGE6p4tu8aYq+A+l1TymwR274qrmpT7CzRRw==", + "requires": { + "@types/node": "*" + } + }, + "@types/pdfmake": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@types/pdfmake/-/pdfmake-0.2.11.tgz", + "integrity": "sha512-gglgMQhnG6C2kco13DJlvokqTxL+XKxHwCejElH8fSCNF9ZCkRK6Mzo011jQ0zuug+YlIgn6BpcpZrARyWdW3Q==", + "requires": { + "@types/node": "*", + "@types/pdfkit": "*" + } + }, "@types/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", @@ -14301,6 +14774,14 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" }, + "brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "requires": { + "base64-js": "^1.1.2" + } + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -14447,15 +14928,32 @@ } }, "call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "requires": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + } + }, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, + "call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" } }, "callsites": { @@ -14953,6 +15451,11 @@ "which": "^2.0.1" } }, + "crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, "dargs": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", @@ -15020,6 +15523,19 @@ "type-detect": "^4.0.0" } }, + "deep-equal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", + "requires": { + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.5.1" + } + }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -15064,6 +15580,16 @@ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -15103,6 +15629,11 @@ "wrappy": "1" } }, + "dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==" + }, "diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -15144,6 +15675,16 @@ "is-obj": "^2.0.0" } }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, "ejs": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", @@ -15247,18 +15788,23 @@ } }, "es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "requires": { - "get-intrinsic": "^1.2.4" - } + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" }, "es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "requires": { + "es-errors": "^1.3.0" + } + }, "es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -16131,6 +16677,11 @@ "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "dev": true }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + }, "gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -16166,15 +16717,20 @@ "dev": true }, "get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "requires": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" } }, "get-package-type": { @@ -16182,6 +16738,15 @@ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + } + }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -16275,12 +16840,9 @@ } }, "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "requires": { - "get-intrinsic": "^1.1.3" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" }, "graceful-fs": { "version": "4.2.10", @@ -16337,15 +16899,18 @@ "es-define-property": "^1.0.0" } }, - "has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" - }, "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "requires": { + "has-symbols": "^1.0.3" + } }, "has-unicode": { "version": "2.0.1", @@ -16598,6 +17163,15 @@ "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", "dev": true }, + "is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "requires": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -16630,6 +17204,15 @@ "has": "^1.0.3" } }, + "is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "requires": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + } + }, "is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -16691,6 +17274,17 @@ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true }, + "is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "requires": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + } + }, "is-retry-allowed": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", @@ -16905,6 +17499,11 @@ "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", "dev": true }, + "jpeg-exif": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz", + "integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -17217,6 +17816,11 @@ "ssri": "^8.0.0" } }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -18204,6 +18808,20 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" }, + "object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, "object-treeify": { "version": "1.1.33", "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", @@ -18617,6 +19235,27 @@ "sha.js": "^2.4.8" } }, + "pdfmake": { + "version": "0.2.20", + "resolved": "https://registry.npmjs.org/pdfmake/-/pdfmake-0.2.20.tgz", + "integrity": "sha512-bGbxbGFP5p8PWNT3Phsu1ZcRLnRfF6jmnuKTkgmt6i5PZzSdX6JaB+NeTz9q+aocfW8SE9GUjL3o/5GroBqGcQ==", + "requires": { + "@foliojs-fork/linebreak": "^1.1.2", + "@foliojs-fork/pdfkit": "^0.15.3", + "iconv-lite": "^0.6.3", + "xmldoc": "^2.0.1" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -18735,6 +19374,11 @@ "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true }, + "png-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz", + "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==" + }, "pngjs": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", @@ -19300,6 +19944,19 @@ "integrity": "sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==", "dev": true }, + "regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "requires": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -19531,6 +20188,17 @@ "has-property-descriptors": "^1.0.2" } }, + "set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + } + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -19989,6 +20657,11 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, + "tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + }, "tiny-secp256k1": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.1.tgz", @@ -20149,6 +20822,31 @@ "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz", "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==" }, + "unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "requires": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "requires": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + }, + "dependencies": { + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" + } + } + }, "unique-filename": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", @@ -20464,6 +21162,21 @@ "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==", "dev": true }, + "xmldoc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-2.0.2.tgz", + "integrity": "sha512-UiRwoSStEXS3R+YE8OqYv3jebza8cBBAI2y8g3B15XFkn3SbEOyyLnmPHjLBPZANrPJKEzxxB7A3XwcLikQVlQ==", + "requires": { + "sax": "^1.2.4" + }, + "dependencies": { + "sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + } + } + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 3051d5e..24cf0a5 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "@proton/mnemonic": "^0.5.0", "@proton/signing-request": "^4.1.10", "@proton/wrap-constants": "^0.2.184", + "@types/pdfmake": "^0.2.11", "bignumber.js": "^9.0.2", "colors": "^1.4.0", "conf": "^10.1.2", @@ -76,6 +77,7 @@ "lodash.isequal": "^4.5.0", "open": "^8.4.0", "pako": "^2.0.4", + "pdfmake": "^0.2.20", "qrcode": "^1.5.0", "rimraf": "^3.0.2", "shelljs": "^0.8.5", @@ -128,4 +130,4 @@ "engines": { "node": ">=14.0.0" } -} \ No newline at end of file +} diff --git a/src/commands/key/export.ts b/src/commands/key/export.ts new file mode 100644 index 0000000..f0eb391 --- /dev/null +++ b/src/commands/key/export.ts @@ -0,0 +1,111 @@ +import { Command } from "@oclif/command"; +import { CliUx } from "@oclif/core"; +import passwordManager from "../../storage/passwordManager"; +import { Key } from "@proton/js"; + +import { config } from "../../storage/config"; +import { lookupKey } from "../../utils/pubkeyToAccount"; +import { green, red } from "colors"; +import { createTxtFile } from "../../utils/toText"; +import { createPdf } from "../../utils/pdfExport"; +import inquirer from "inquirer"; + +export type ExportAccountType = { + chain: string; + accounts: string[] | null; + publicKey: string; + privateKey: string; +}; + +export default class ExportKeys extends Command { + static description = "Export keys to text or QR code in PDF"; + + async run() { + const privateKeys = await passwordManager.getPrivateKeys(); + const agree = await inquirer.prompt([ + { + name: "agree", + message: + "You are about to export accounts's sensitive information. Do you agree?", + type: "confirm", + }, + ]); + + if (!agree.agree) { + CliUx.ux.log(red("Canceled")); + return; + } + + const search = await inquirer.prompt([ + { + name: "search", + message: "Search for accounts (leave blank to export all accounts)", + type: "input", + }, + ]); + + const exportMode: any = await inquirer.prompt([ + { + name: "mode", + message: "Select export mode", + type: "list", + choices: ["text", "pdf"], + }, + ]); + + if (privateKeys.length > 0) { + CliUx.ux.action.start(green("Exporting keys")); + const chain = config.get("currentChain"); + + const accountsData = privateKeys.map(async (privateKey) => { + const parsedPrivateKey = Key.PrivateKey.fromString(privateKey); + const publicKey = parsedPrivateKey.getPublicKey().toString(); + const accounts = await lookupKey( + publicKey, + chain, + search.search === "" ? undefined : search.search + ); + return { + chain, + accounts, + publicKey, + privateKey: "PVT_K1_NOT_REVEALED_FOR_DEMO_DUH", + }; + }); + Promise.all(accountsData).then((data) => { + const exportedKeys = data.filter((item) => item.accounts !== null); + const pdfFileName = `${chain}_keys_${new Date().getFullYear()}_${new Date().getMonth()}_${new Date().getDate()}`; + if (exportMode.mode === "pdf") { + createPdf(exportedKeys, `${pdfFileName}.pdf`); + } + + if (exportMode.mode === "text") { + const txtContent = exportedKeys.map((item) => { + return `${JSON.stringify(item)}\n`; + }); + createTxtFile(txtContent.join(""), `${pdfFileName}.txt`); + } + + CliUx.ux.action.stop(green(`Done`)); + CliUx.ux.log( + green( + `Exported ${ + exportedKeys.length + } keys to ${process.cwd()}/${pdfFileName}.${ + exportMode.mode === "pdf" ? "pdf" : "txt" + }` + ) + ); + }); + } + // const displayKeys = privateKeys.map((privateKey) => { + // const parsedPrivateKey = Key.PrivateKey.fromString(privateKey); + + // return { + // publicKey: parsedPrivateKey.getPublicKey().toString(), + // privateKey: parsedPrivateKey.toString(), + // }; + // }); + //CliUx.ux.styledJSON(displayKeys); + } +} diff --git a/src/constants.ts b/src/constants.ts index 8d5b131..3b2409d 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -28,3 +28,14 @@ export const EP_DISCOVERY: ChainDiscoveryService[] = [ service_url: "https://danemarkbp.com/apis/get_json_testnet.php?type=ssl", }, ]; + +export const LIGHT_CLIENT_ENDPOINTS = [ + { + chain: "proton", + endpoints: "https://proton.light-api.net", + }, + { + chain: "proton-test", + endpoints: "https://testnet-lightapi.eosams.xeos.me", + }, +]; diff --git a/src/fixtures/fonts/roboto-regular.ttf b/src/fixtures/fonts/roboto-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..32daea3a2cb4cb7462688b6b8251726a9156f758 GIT binary patch literal 152588 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 z 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 exportAccount(account)), + styles: { + fieldHeader: { + fontSize: 10, + + color: "#737373", + }, + fieldValue: { + fontSize: 16, + }, + waLabel: { + align: "center", + background: "black", + color: "#FFFFFF", + }, + }, + }; + + const pdf = PdfPrinter.createPdfKitDocument(docDefinition); + pdf.pipe(fs.createWriteStream(fileName)); + pdf.end(); +} + +function exportAccount(account: ExportAccountType) { + return { + pageBreak: "after", + table: { + widths: ["100%"], + body: [ + [ + [ + { text: "Chain", style: "fieldHeader" }, + { text: account.chain, style: "filedValue" }, + ], + ], + [ + [ + { + qr: account.privateKey, + fit: 260, + margin: [40, 40, 40, 20], + }, + { + margin: [40, 0, 40, 40], + table: { + widths: ["100%"], + + body: [ + [ + { + text: "Scan with webauth in Import > Private Key", + style: "waLabel", + }, + ], + ], + }, + layout: { + fillColor: "#000000", + }, + }, + ], + ], + [ + [ + { text: "Accounts", style: "fieldHeader" }, + { text: account.accounts?.join(", "), style: "filedValue" }, + ], + ], + [ + [ + { text: "Public key", style: "fieldHeader" }, + { text: account.publicKey, style: "filedValue" }, + ], + ], + ], + }, + }; +} diff --git a/src/utils/pubkeyToAccount.ts b/src/utils/pubkeyToAccount.ts new file mode 100644 index 0000000..93bb933 --- /dev/null +++ b/src/utils/pubkeyToAccount.ts @@ -0,0 +1,42 @@ +import { LIGHT_CLIENT_ENDPOINTS } from "../constants"; + +type LookupKeyResponse = { + [key: "protontest" | "proton"]: { + accounts: { + [key: string]: []; + }; + }; +}; +export async function lookupKey( + publicKey: string, + chain: string, + accountFilter?: string +) { + const responseRoot = chain === "proton-test" ? "protontest" : "proton"; + const endpoint = LIGHT_CLIENT_ENDPOINTS.find( + (endpoint) => endpoint.chain === chain + )?.endpoints; + try { + return fetch(`${endpoint}/api/key/${publicKey}`) + .catch((err) => { + return null; + }) + .then((res) => res?.json() ?? null) + .then((data) => { + if (!data) return null; + if (!data[responseRoot] || !data[responseRoot].accounts) return null; + let accounts = Object.keys(data[responseRoot].accounts); + if (accounts.length === 0) return null; + if (accountFilter) { + const filteredAccounts = accounts.filter((account) => + account.includes(accountFilter) + ); + if (filteredAccounts.length === 0) return null; + accounts = filteredAccounts; + } + return accounts; + }); + } catch (err) { + return null; + } +} diff --git a/src/utils/toText.ts b/src/utils/toText.ts new file mode 100644 index 0000000..884fc67 --- /dev/null +++ b/src/utils/toText.ts @@ -0,0 +1,8 @@ +import { writeFile } from "node:fs/promises"; + +export async function createTxtFile( + content: string, + filename: string = "keys.txt" +): Promise { + await writeFile(filename, content, { encoding: "utf8" }); +} From 7c5458d24e5ad05b0d4743e88b01da265ec4d553 Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Tue, 22 Jul 2025 10:47:09 +0200 Subject: [PATCH 02/13] =?UTF-8?q?=F0=9F=9A=A7=20Clean=20up=20commented=20c?= =?UTF-8?q?ode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/key/export.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/commands/key/export.ts b/src/commands/key/export.ts index f0eb391..2475019 100644 --- a/src/commands/key/export.ts +++ b/src/commands/key/export.ts @@ -98,14 +98,5 @@ export default class ExportKeys extends Command { ); }); } - // const displayKeys = privateKeys.map((privateKey) => { - // const parsedPrivateKey = Key.PrivateKey.fromString(privateKey); - - // return { - // publicKey: parsedPrivateKey.getPublicKey().toString(), - // privateKey: parsedPrivateKey.toString(), - // }; - // }); - //CliUx.ux.styledJSON(displayKeys); } } From 563a203d338ea213bd8a2139408b65f8cbdc48a1 Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Tue, 22 Jul 2025 15:31:30 +0200 Subject: [PATCH 03/13] =?UTF-8?q?=F0=9F=9A=A7=20Added=20ability=20to=20exp?= =?UTF-8?q?ort=20JSON=20formated=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/key/export.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/commands/key/export.ts b/src/commands/key/export.ts index 2475019..364cfae 100644 --- a/src/commands/key/export.ts +++ b/src/commands/key/export.ts @@ -49,7 +49,7 @@ export default class ExportKeys extends Command { name: "mode", message: "Select export mode", type: "list", - choices: ["text", "pdf"], + choices: ["txt", "pdf", "json"], }, ]); @@ -79,21 +79,26 @@ export default class ExportKeys extends Command { createPdf(exportedKeys, `${pdfFileName}.pdf`); } - if (exportMode.mode === "text") { + if (exportMode.mode === "txt") { const txtContent = exportedKeys.map((item) => { return `${JSON.stringify(item)}\n`; }); createTxtFile(txtContent.join(""), `${pdfFileName}.txt`); } + if (exportMode.mode === "json") { + createTxtFile( + JSON.stringify(exportedKeys, null, 2), + `${pdfFileName}.json` + ); + } + CliUx.ux.action.stop(green(`Done`)); CliUx.ux.log( green( `Exported ${ exportedKeys.length - } keys to ${process.cwd()}/${pdfFileName}.${ - exportMode.mode === "pdf" ? "pdf" : "txt" - }` + } keys to ${process.cwd()}/${pdfFileName}.${exportMode.mode}` ) ); }); From 2c318f8f87b21dce0ff4f719457d6f097748e587 Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Tue, 22 Jul 2025 23:39:05 +0200 Subject: [PATCH 04/13] =?UTF-8?q?=F0=9F=9A=A7=20Adding=20option=20to=20pri?= =?UTF-8?q?nt=20private=20key=20as=20plain=20text=20in=20PDF=20file.=20Add?= =?UTF-8?q?ing=20password=20protection=20as=20an=20option=20for=20PDF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/key/export.ts | 58 +++++++++++++++++++++++++++++++++----- src/utils/pdfExport.ts | 39 ++++++++++++++++++++++--- 2 files changed, 86 insertions(+), 11 deletions(-) diff --git a/src/commands/key/export.ts b/src/commands/key/export.ts index 364cfae..0fe8a76 100644 --- a/src/commands/key/export.ts +++ b/src/commands/key/export.ts @@ -17,16 +17,26 @@ export type ExportAccountType = { privateKey: string; }; +export type ExportConfig = { + mode: "txt" | "pdf" | "json"; + showPrivateKey: boolean; + search?: string; + password?: string; + exportPath?: string; +}; + export default class ExportKeys extends Command { static description = "Export keys to text or QR code in PDF"; async run() { const privateKeys = await passwordManager.getPrivateKeys(); + const chain = config.get("currentChain"); + const pdfFileName = `${chain}_keys_${new Date().getFullYear()}_${new Date().getMonth()}_${new Date().getDate()}`; const agree = await inquirer.prompt([ { name: "agree", message: - "You are about to export accounts's sensitive information. Do you agree?", + "You are about to export accounts's sensitive information. Do you agree ?", type: "confirm", }, ]); @@ -36,6 +46,11 @@ export default class ExportKeys extends Command { return; } + const exportConfig: ExportConfig = { + mode: "txt", + showPrivateKey: false, + }; + const search = await inquirer.prompt([ { name: "search", @@ -44,18 +59,42 @@ export default class ExportKeys extends Command { }, ]); + exportConfig.search = search.search; + const exportMode: any = await inquirer.prompt([ { name: "mode", - message: "Select export mode", + message: "Select the export format", type: "list", choices: ["txt", "pdf", "json"], }, ]); + exportConfig.mode = exportMode.mode; + + if (exportConfig.mode === "pdf") { + const displayPrivateKey = await inquirer.prompt([ + { + name: "displayPrivateKey", + message: "Show private key as plain text in the file?", + type: "confirm", + }, + ]); + + exportConfig.showPrivateKey = displayPrivateKey.displayPrivateKey; + + const password = await inquirer.prompt([ + { + name: "password", + message: "File protection password (leave blank for no protection)", + type: "input", + }, + ]); + exportConfig.password = password.password; + } + if (privateKeys.length > 0) { CliUx.ux.action.start(green("Exporting keys")); - const chain = config.get("currentChain"); const accountsData = privateKeys.map(async (privateKey) => { const parsedPrivateKey = Key.PrivateKey.fromString(privateKey); @@ -74,19 +113,24 @@ export default class ExportKeys extends Command { }); Promise.all(accountsData).then((data) => { const exportedKeys = data.filter((item) => item.accounts !== null); - const pdfFileName = `${chain}_keys_${new Date().getFullYear()}_${new Date().getMonth()}_${new Date().getDate()}`; + if (exportMode.mode === "pdf") { - createPdf(exportedKeys, `${pdfFileName}.pdf`); + createPdf( + exportedKeys, + `${pdfFileName}.pdf`, + exportConfig.password, + exportConfig.showPrivateKey + ); } - if (exportMode.mode === "txt") { + if (exportConfig.mode === "txt") { const txtContent = exportedKeys.map((item) => { return `${JSON.stringify(item)}\n`; }); createTxtFile(txtContent.join(""), `${pdfFileName}.txt`); } - if (exportMode.mode === "json") { + if (exportConfig.mode === "json") { createTxtFile( JSON.stringify(exportedKeys, null, 2), `${pdfFileName}.json` diff --git a/src/utils/pdfExport.ts b/src/utils/pdfExport.ts index 1064424..14168b1 100644 --- a/src/utils/pdfExport.ts +++ b/src/utils/pdfExport.ts @@ -12,11 +12,23 @@ const fonts = { }, }; -export function createPdf(accounts: ExportAccountType[], fileName: string) { +export function createPdf( + accounts: ExportAccountType[], + fileName: string, + password?: string, + showPrivateKey?: boolean +) { const PdfPrinter = new pdfMake(fonts); const docDefinition = { pageSize: "A5", - content: accounts.map((account) => exportAccount(account)), + content: [ + { text: "WARNING." }, + { + text: "This following documents contains highly sensitive informations, make sure to store it securely. If you print it, store it into a secure vault and delete the file.", + pageBreak: "after", + }, + ...accounts.map((account) => exportAccount(account, showPrivateKey)), + ], styles: { fieldHeader: { fontSize: 10, @@ -34,13 +46,23 @@ export function createPdf(accounts: ExportAccountType[], fileName: string) { }, }; + if (password) { + docDefinition.userPassword = password; + docDefinition.ownerPassword = password; + docDefinition.permissions = { + modifying: false, + copying: false, + annotating: false, + }; + } + const pdf = PdfPrinter.createPdfKitDocument(docDefinition); pdf.pipe(fs.createWriteStream(fileName)); pdf.end(); } -function exportAccount(account: ExportAccountType) { - return { +function exportAccount(account: ExportAccountType, showPrivateKey?: boolean) { + const definition = { pageBreak: "after", table: { widths: ["100%"], @@ -93,4 +115,13 @@ function exportAccount(account: ExportAccountType) { ], }, }; + if (showPrivateKey) { + definition.table.body.push([ + [ + { text: "Private key", style: "fieldHeader" }, + { text: account.privateKey, style: "filedValue" }, + ], + ]); + } + return definition; } From ae59eaf6d0aab92eb9129f7ffa87d3e4c2fc9bf8 Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Wed, 23 Jul 2025 13:37:06 +0200 Subject: [PATCH 05/13] =?UTF-8?q?=F0=9F=9A=A7=20Enforce=20PDF=20security?= =?UTF-8?q?=20encryption=20to=20AES=20256.=20Force=20user=20to=20provide?= =?UTF-8?q?=20a=20strong=20password?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/key/export.ts | 53 ++++++++++++++++++++++++++++++++------ src/utils/pdfExport.ts | 1 + 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/commands/key/export.ts b/src/commands/key/export.ts index 0fe8a76..0cb8930 100644 --- a/src/commands/key/export.ts +++ b/src/commands/key/export.ts @@ -9,6 +9,23 @@ import { green, red } from "colors"; import { createTxtFile } from "../../utils/toText"; import { createPdf } from "../../utils/pdfExport"; import inquirer from "inquirer"; +import { z } from "zod"; + +const passwordValidator = z + .string() + .min(16) + .refine((val) => /[a-z]/.test(val), { + message: "Password must contain at least one lowercase letter", + }) + .refine((val) => /[A-Z]/.test(val), { + message: "Password must contain at least one uppercase letter", + }) + .refine((val) => /\d/.test(val), { + message: "Password must contain at least one digit", + }) + .refine((val) => /[@_#!?*&$]/.test(val), { + message: "Password must contain at least one special character (@_#!?*&$)", + }); export type ExportAccountType = { chain: string; @@ -21,6 +38,7 @@ export type ExportConfig = { mode: "txt" | "pdf" | "json"; showPrivateKey: boolean; search?: string; + protectFile?: boolean; password?: string; exportPath?: string; }; @@ -66,7 +84,7 @@ export default class ExportKeys extends Command { name: "mode", message: "Select the export format", type: "list", - choices: ["txt", "pdf", "json"], + choices: ["pdf", "txt", "json"], }, ]); @@ -81,16 +99,35 @@ export default class ExportKeys extends Command { }, ]); - exportConfig.showPrivateKey = displayPrivateKey.displayPrivateKey; - - const password = await inquirer.prompt([ + const protectFile = await inquirer.prompt([ { - name: "password", - message: "File protection password (leave blank for no protection)", - type: "input", + name: "protectFile", + message: "Protect the file with a password?", + type: "confirm", }, ]); - exportConfig.password = password.password; + + exportConfig.protectFile = protectFile.protectFile; + + if (exportConfig.protectFile) { + const password = await inquirer.prompt([ + { + name: "password", + message: + "Your 16 chars password with uppercase, lowercase, digits and special character (@_#!?*&$)", + type: "input", + validate: async (input: string) => { + const result = passwordValidator.safeParse(input); + if (!result.success) { + return result.error.format()._errors.join("\n"); + } else { + return true; + } + }, + }, + ]); + exportConfig.password = password.password; + } } if (privateKeys.length > 0) { diff --git a/src/utils/pdfExport.ts b/src/utils/pdfExport.ts index 14168b1..60779eb 100644 --- a/src/utils/pdfExport.ts +++ b/src/utils/pdfExport.ts @@ -20,6 +20,7 @@ export function createPdf( ) { const PdfPrinter = new pdfMake(fonts); const docDefinition = { + version: "1.7ext3", pageSize: "A5", content: [ { text: "WARNING." }, From 7aa456df575a49a82915c8be94d0979ad8420d45 Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Wed, 23 Jul 2025 13:46:13 +0200 Subject: [PATCH 06/13] =?UTF-8?q?=F0=9F=9A=A7=20Adding=20information=20on?= =?UTF-8?q?=20security=20for=20file=20export=20formats=20option?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/key/export.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/commands/key/export.ts b/src/commands/key/export.ts index 0cb8930..92ce771 100644 --- a/src/commands/key/export.ts +++ b/src/commands/key/export.ts @@ -84,7 +84,11 @@ export default class ExportKeys extends Command { name: "mode", message: "Select the export format", type: "list", - choices: ["pdf", "txt", "json"], + choices: [ + { name: "PDF (with secure option)", value: "pdf" }, + { name: "Text file (no secure option)", value: "txt" }, + { name: "JSON file (no secure option)", value: "json" }, + ], }, ]); From dadd8171c0e0137072d0399b68690cd456ece924 Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Thu, 24 Jul 2025 23:04:04 +0200 Subject: [PATCH 07/13] =?UTF-8?q?=F0=9F=9A=A7=20Renamed=20lookup=20utils?= =?UTF-8?q?=20to=20pubKeyToAccount.=20Remove=20console=20log.=20Improve=20?= =?UTF-8?q?UX=20message.=20Print=20private?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/key/export.ts | 25 +++++++++++++++++-------- src/utils/pubkeyToAccount.ts | 9 +++++---- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/commands/key/export.ts b/src/commands/key/export.ts index 92ce771..f27f2b8 100644 --- a/src/commands/key/export.ts +++ b/src/commands/key/export.ts @@ -4,7 +4,7 @@ import passwordManager from "../../storage/passwordManager"; import { Key } from "@proton/js"; import { config } from "../../storage/config"; -import { lookupKey } from "../../utils/pubkeyToAccount"; +import { pubKeyToaccount } from "../../utils/pubkeyToAccount"; import { green, red } from "colors"; import { createTxtFile } from "../../utils/toText"; import { createPdf } from "../../utils/pdfExport"; @@ -135,12 +135,12 @@ export default class ExportKeys extends Command { } if (privateKeys.length > 0) { - CliUx.ux.action.start(green("Exporting keys")); + CliUx.ux.action.start(green("Exporting keys (this may take a bit)")); const accountsData = privateKeys.map(async (privateKey) => { const parsedPrivateKey = Key.PrivateKey.fromString(privateKey); const publicKey = parsedPrivateKey.getPublicKey().toString(); - const accounts = await lookupKey( + const accounts = await pubKeyToaccount( publicKey, chain, search.search === "" ? undefined : search.search @@ -149,15 +149,24 @@ export default class ExportKeys extends Command { chain, accounts, publicKey, - privateKey: "PVT_K1_NOT_REVEALED_FOR_DEMO_DUH", + privateKey, }; }); Promise.all(accountsData).then((data) => { const exportedKeys = data.filter((item) => item.accounts !== null); + // Remove duplicated public keys from the exportedKeys + const seenPublicKeys = new Set(); + const uniqueExportedKeys = []; + for (const item of exportedKeys) { + if (!seenPublicKeys.has(item.publicKey)) { + seenPublicKeys.add(item.publicKey); + uniqueExportedKeys.push(item); + } + } if (exportMode.mode === "pdf") { createPdf( - exportedKeys, + uniqueExportedKeys, `${pdfFileName}.pdf`, exportConfig.password, exportConfig.showPrivateKey @@ -165,7 +174,7 @@ export default class ExportKeys extends Command { } if (exportConfig.mode === "txt") { - const txtContent = exportedKeys.map((item) => { + const txtContent = uniqueExportedKeys.map((item) => { return `${JSON.stringify(item)}\n`; }); createTxtFile(txtContent.join(""), `${pdfFileName}.txt`); @@ -173,7 +182,7 @@ export default class ExportKeys extends Command { if (exportConfig.mode === "json") { createTxtFile( - JSON.stringify(exportedKeys, null, 2), + JSON.stringify(uniqueExportedKeys, null, 2), `${pdfFileName}.json` ); } @@ -182,7 +191,7 @@ export default class ExportKeys extends Command { CliUx.ux.log( green( `Exported ${ - exportedKeys.length + uniqueExportedKeys.length } keys to ${process.cwd()}/${pdfFileName}.${exportMode.mode}` ) ); diff --git a/src/utils/pubkeyToAccount.ts b/src/utils/pubkeyToAccount.ts index 93bb933..5aaa9c9 100644 --- a/src/utils/pubkeyToAccount.ts +++ b/src/utils/pubkeyToAccount.ts @@ -1,4 +1,5 @@ import { LIGHT_CLIENT_ENDPOINTS } from "../constants"; +import { wait } from "./wait"; type LookupKeyResponse = { [key: "protontest" | "proton"]: { @@ -7,7 +8,7 @@ type LookupKeyResponse = { }; }; }; -export async function lookupKey( +export async function pubKeyToAccount( publicKey: string, chain: string, accountFilter?: string @@ -28,9 +29,9 @@ export async function lookupKey( let accounts = Object.keys(data[responseRoot].accounts); if (accounts.length === 0) return null; if (accountFilter) { - const filteredAccounts = accounts.filter((account) => - account.includes(accountFilter) - ); + const filteredAccounts = accounts.filter((account) => { + return account.includes(accountFilter); + }); if (filteredAccounts.length === 0) return null; accounts = filteredAccounts; } From e2c702f47681d050e0ad66cbb2b8f50c4719d1db Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Thu, 24 Jul 2025 23:11:28 +0200 Subject: [PATCH 08/13] Fix missing "print private key as plain text" when export in PDF --- src/commands/key/export.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/commands/key/export.ts b/src/commands/key/export.ts index f27f2b8..6cad8a1 100644 --- a/src/commands/key/export.ts +++ b/src/commands/key/export.ts @@ -4,7 +4,7 @@ import passwordManager from "../../storage/passwordManager"; import { Key } from "@proton/js"; import { config } from "../../storage/config"; -import { pubKeyToaccount } from "../../utils/pubkeyToAccount"; +import { pubKeyToAccount } from "../../utils/pubkeyToAccount"; import { green, red } from "colors"; import { createTxtFile } from "../../utils/toText"; import { createPdf } from "../../utils/pdfExport"; @@ -103,6 +103,8 @@ export default class ExportKeys extends Command { }, ]); + exportConfig.showPrivateKey = displayPrivateKey.displayPrivateKey; + const protectFile = await inquirer.prompt([ { name: "protectFile", @@ -140,7 +142,7 @@ export default class ExportKeys extends Command { const accountsData = privateKeys.map(async (privateKey) => { const parsedPrivateKey = Key.PrivateKey.fromString(privateKey); const publicKey = parsedPrivateKey.getPublicKey().toString(); - const accounts = await pubKeyToaccount( + const accounts = await pubKeyToAccount( publicKey, chain, search.search === "" ? undefined : search.search From fbf5fb0536effcc2763d78098ae57301fe7c8687 Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Thu, 24 Jul 2025 23:23:59 +0200 Subject: [PATCH 09/13] =?UTF-8?q?=F0=9F=90=9B=20Fix=20type=20inference=20i?= =?UTF-8?q?ssues=20with=20PDFmake?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 235 ++++++++++++++++++----------------- src/utils/pdfExport.ts | 20 ++- src/utils/pubkeyToAccount.ts | 8 -- 3 files changed, 138 insertions(+), 125 deletions(-) diff --git a/README.md b/README.md index 6c373b0..4acb773 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ Proton CLI [![License](https://img.shields.io/npm/l/@proton/cli.svg)](https://github.com/ProtonProtocol/proton-cli/blob/master/package.json) - -- [Installation](#installation) -- [Install NodeJS](#install-nodejs) -- [Usage](#usage) -- [Commands](#commands) +* [@proton/cli](#protoncli) +* [Installation](#installation) +* [Install NodeJS](#install-nodejs) +* [Usage](#usage) +* [Commands](#commands) # Installation @@ -62,77 +62,75 @@ nvm use 16 # Usage - ```sh-session $ npm install -g @proton/cli $ proton COMMAND running command... $ proton (--version) -@proton/cli/0.1.95 darwin-arm64 node-v22.14.0 +@proton/cli/0.1.96 darwin-arm64 node-v22.14.0 $ proton --help [COMMAND] USAGE $ proton COMMAND ... ``` - # Commands - -- [`proton account ACCOUNT`](#proton-account-account) -- [`proton account:create ACCOUNT`](#proton-accountcreate-account) -- [`proton action CONTRACT [ACTION] [DATA] [AUTHORIZATION]`](#proton-action-contract-action-data-authorization) -- [`proton block:get BLOCKNUMBER`](#proton-blockget-blocknumber) -- [`proton boilerplate [FOLDER]`](#proton-boilerplate-folder) -- [`proton chain:get`](#proton-chainget) -- [`proton chain:info`](#proton-chaininfo) -- [`proton chain:list`](#proton-chainlist) -- [`proton chain:set [CHAIN]`](#proton-chainset-chain) -- [`proton contract:abi ACCOUNT`](#proton-contractabi-account) -- [`proton contract:clear ACCOUNT`](#proton-contractclear-account) -- [`proton contract:enableinline ACCOUNT`](#proton-contractenableinline-account) -- [`proton contract:set ACCOUNT SOURCE`](#proton-contractset-account-source) -- [`proton encode:name ACCOUNT`](#proton-encodename-account) -- [`proton encode:symbol SYMBOL PRECISION`](#proton-encodesymbol-symbol-precision) -- [`proton endpoint`](#proton-endpoint) -- [`proton endpoint:default [ENDPOINT]`](#proton-endpointdefault-endpoint) -- [`proton endpoint:get`](#proton-endpointget) -- [`proton endpoint:set [ENDPOINT]`](#proton-endpointset-endpoint) -- [`proton faucet`](#proton-faucet) -- [`proton faucet:claim SYMBOL AUTHORIZATION`](#proton-faucetclaim-symbol-authorization) -- [`proton generate:action`](#proton-generateaction) -- [`proton generate:contract CONTRACTNAME`](#proton-generatecontract-contractname) -- [`proton generate:inlineaction ACTIONNAME`](#proton-generateinlineaction-actionname) -- [`proton generate:table TABLENAME`](#proton-generatetable-tablename) -- [`proton help [COMMAND]`](#proton-help-command) -- [`proton key:add [PRIVATEKEY]`](#proton-keyadd-privatekey) -- [`proton key:generate`](#proton-keygenerate) -- [`proton key:get PUBLICKEY`](#proton-keyget-publickey) -- [`proton key:list`](#proton-keylist) -- [`proton key:lock`](#proton-keylock) -- [`proton key:remove [PRIVATEKEY]`](#proton-keyremove-privatekey) -- [`proton key:reset`](#proton-keyreset) -- [`proton key:unlock [PASSWORD]`](#proton-keyunlock-password) -- [`proton msig:approve PROPOSER PROPOSAL AUTH`](#proton-msigapprove-proposer-proposal-auth) -- [`proton msig:cancel PROPOSALNAME AUTH`](#proton-msigcancel-proposalname-auth) -- [`proton msig:exec PROPOSER PROPOSAL AUTH`](#proton-msigexec-proposer-proposal-auth) -- [`proton msig:propose PROPOSALNAME ACTIONS AUTH`](#proton-msigpropose-proposalname-actions-auth) -- [`proton network`](#proton-network) -- [`proton permission ACCOUNT`](#proton-permission-account) -- [`proton permission:link ACCOUNT PERMISSION CONTRACT [ACTION]`](#proton-permissionlink-account-permission-contract-action) -- [`proton permission:unlink ACCOUNT CONTRACT [ACTION]`](#proton-permissionunlink-account-contract-action) -- [`proton psr URI`](#proton-psr-uri) -- [`proton ram`](#proton-ram) -- [`proton ram:buy BUYER RECEIVER BYTES`](#proton-rambuy-buyer-receiver-bytes) -- [`proton rpc:accountsbyauthorizers AUTHORIZATIONS [KEYS]`](#proton-rpcaccountsbyauthorizers-authorizations-keys) -- [`proton scan ACCOUNT`](#proton-scan-account) -- [`proton table CONTRACT [TABLE] [SCOPE]`](#proton-table-contract-table-scope) -- [`proton transaction JSON`](#proton-transaction-json) -- [`proton transaction:get ID`](#proton-transactionget-id) -- [`proton transaction:push TRANSACTION`](#proton-transactionpush-transaction) -- [`proton version`](#proton-version) +* [`proton account ACCOUNT`](#proton-account-account) +* [`proton account:create ACCOUNT`](#proton-accountcreate-account) +* [`proton action CONTRACT [ACTION] [DATA] [AUTHORIZATION]`](#proton-action-contract-action-data-authorization) +* [`proton block:get BLOCKNUMBER`](#proton-blockget-blocknumber) +* [`proton boilerplate [FOLDER]`](#proton-boilerplate-folder) +* [`proton chain:get`](#proton-chainget) +* [`proton chain:info`](#proton-chaininfo) +* [`proton chain:list`](#proton-chainlist) +* [`proton chain:set [CHAIN]`](#proton-chainset-chain) +* [`proton contract:abi ACCOUNT`](#proton-contractabi-account) +* [`proton contract:clear ACCOUNT`](#proton-contractclear-account) +* [`proton contract:enableinline ACCOUNT`](#proton-contractenableinline-account) +* [`proton contract:set ACCOUNT SOURCE`](#proton-contractset-account-source) +* [`proton encode:name ACCOUNT`](#proton-encodename-account) +* [`proton encode:symbol SYMBOL PRECISION`](#proton-encodesymbol-symbol-precision) +* [`proton endpoint`](#proton-endpoint) +* [`proton endpoint:default [ENDPOINT]`](#proton-endpointdefault-endpoint) +* [`proton endpoint:get`](#proton-endpointget) +* [`proton endpoint:set [ENDPOINT]`](#proton-endpointset-endpoint) +* [`proton faucet`](#proton-faucet) +* [`proton faucet:claim SYMBOL AUTHORIZATION`](#proton-faucetclaim-symbol-authorization) +* [`proton generate:action`](#proton-generateaction) +* [`proton generate:contract CONTRACTNAME`](#proton-generatecontract-contractname) +* [`proton generate:inlineaction ACTIONNAME`](#proton-generateinlineaction-actionname) +* [`proton generate:table TABLENAME`](#proton-generatetable-tablename) +* [`proton help [COMMAND]`](#proton-help-command) +* [`proton key:add [PRIVATEKEY]`](#proton-keyadd-privatekey) +* [`proton key:export`](#proton-keyexport) +* [`proton key:generate`](#proton-keygenerate) +* [`proton key:get PUBLICKEY`](#proton-keyget-publickey) +* [`proton key:list`](#proton-keylist) +* [`proton key:lock`](#proton-keylock) +* [`proton key:remove [PRIVATEKEY]`](#proton-keyremove-privatekey) +* [`proton key:reset`](#proton-keyreset) +* [`proton key:unlock [PASSWORD]`](#proton-keyunlock-password) +* [`proton msig:approve PROPOSER PROPOSAL AUTH`](#proton-msigapprove-proposer-proposal-auth) +* [`proton msig:cancel PROPOSALNAME AUTH`](#proton-msigcancel-proposalname-auth) +* [`proton msig:exec PROPOSER PROPOSAL AUTH`](#proton-msigexec-proposer-proposal-auth) +* [`proton msig:propose PROPOSALNAME ACTIONS AUTH`](#proton-msigpropose-proposalname-actions-auth) +* [`proton network`](#proton-network) +* [`proton permission ACCOUNT`](#proton-permission-account) +* [`proton permission:link ACCOUNT PERMISSION CONTRACT [ACTION]`](#proton-permissionlink-account-permission-contract-action) +* [`proton permission:unlink ACCOUNT CONTRACT [ACTION]`](#proton-permissionunlink-account-contract-action) +* [`proton psr URI`](#proton-psr-uri) +* [`proton ram`](#proton-ram) +* [`proton ram:buy BUYER RECEIVER BYTES`](#proton-rambuy-buyer-receiver-bytes) +* [`proton rpc:accountsbyauthorizers AUTHORIZATIONS [KEYS]`](#proton-rpcaccountsbyauthorizers-authorizations-keys) +* [`proton scan ACCOUNT`](#proton-scan-account) +* [`proton table CONTRACT [TABLE] [SCOPE]`](#proton-table-contract-table-scope) +* [`proton transaction JSON`](#proton-transaction-json) +* [`proton transaction:get ID`](#proton-transactionget-id) +* [`proton transaction:push TRANSACTION`](#proton-transactionpush-transaction) +* [`proton version`](#proton-version) ## `proton account ACCOUNT` @@ -150,7 +148,7 @@ DESCRIPTION Get Account Information ``` -_See code: [lib/commands/account/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/account/index.js)_ +_See code: [lib/commands/account/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/account/index.js)_ ## `proton account:create ACCOUNT` @@ -164,7 +162,7 @@ DESCRIPTION Create New Account ``` -_See code: [lib/commands/account/create.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/account/create.js)_ +_See code: [lib/commands/account/create.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/account/create.js)_ ## `proton action CONTRACT [ACTION] [DATA] [AUTHORIZATION]` @@ -184,7 +182,7 @@ DESCRIPTION Execute Action ``` -_See code: [lib/commands/action/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/action/index.js)_ +_See code: [lib/commands/action/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/action/index.js)_ ## `proton block:get BLOCKNUMBER` @@ -198,7 +196,7 @@ DESCRIPTION Get Block ``` -_See code: [lib/commands/block/get.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/block/get.js)_ +_See code: [lib/commands/block/get.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/block/get.js)_ ## `proton boilerplate [FOLDER]` @@ -215,7 +213,7 @@ DESCRIPTION Boilerplate a new Proton Project with contract, frontend and tests ``` -_See code: [lib/commands/boilerplate.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/boilerplate.js)_ +_See code: [lib/commands/boilerplate.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/boilerplate.js)_ ## `proton chain:get` @@ -232,7 +230,7 @@ ALIASES $ proton network ``` -_See code: [lib/commands/chain/get.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/chain/get.js)_ +_See code: [lib/commands/chain/get.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/chain/get.js)_ ## `proton chain:info` @@ -246,7 +244,7 @@ DESCRIPTION Get Chain Info ``` -_See code: [lib/commands/chain/info.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/chain/info.js)_ +_See code: [lib/commands/chain/info.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/chain/info.js)_ ## `proton chain:list` @@ -260,7 +258,7 @@ DESCRIPTION All Networks ``` -_See code: [lib/commands/chain/list.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/chain/list.js)_ +_See code: [lib/commands/chain/list.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/chain/list.js)_ ## `proton chain:set [CHAIN]` @@ -277,7 +275,7 @@ DESCRIPTION Set Chain ``` -_See code: [lib/commands/chain/set.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/chain/set.js)_ +_See code: [lib/commands/chain/set.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/chain/set.js)_ ## `proton contract:abi ACCOUNT` @@ -291,7 +289,7 @@ DESCRIPTION Get Contract ABI ``` -_See code: [lib/commands/contract/abi.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/contract/abi.js)_ +_See code: [lib/commands/contract/abi.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/contract/abi.js)_ ## `proton contract:clear ACCOUNT` @@ -309,7 +307,7 @@ DESCRIPTION Clean Contract ``` -_See code: [lib/commands/contract/clear.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/contract/clear.js)_ +_See code: [lib/commands/contract/clear.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/contract/clear.js)_ ## `proton contract:enableinline ACCOUNT` @@ -329,7 +327,7 @@ DESCRIPTION Enable Inline Actions on a Contract ``` -_See code: [lib/commands/contract/enableinline.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/contract/enableinline.js)_ +_See code: [lib/commands/contract/enableinline.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/contract/enableinline.js)_ ## `proton contract:set ACCOUNT SOURCE` @@ -349,7 +347,7 @@ DESCRIPTION Deploy Contract (WASM + ABI) ``` -_See code: [lib/commands/contract/set.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/contract/set.js)_ +_See code: [lib/commands/contract/set.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/contract/set.js)_ ## `proton encode:name ACCOUNT` @@ -363,7 +361,7 @@ DESCRIPTION Encode Name ``` -_See code: [lib/commands/encode/name.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/encode/name.js)_ +_See code: [lib/commands/encode/name.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/encode/name.js)_ ## `proton encode:symbol SYMBOL PRECISION` @@ -377,7 +375,7 @@ DESCRIPTION Encode Symbol ``` -_See code: [lib/commands/encode/symbol.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/encode/symbol.js)_ +_See code: [lib/commands/encode/symbol.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/encode/symbol.js)_ ## `proton endpoint` @@ -403,13 +401,13 @@ USAGE $ proton endpoint:default [ENDPOINT] ARGUMENTS - ENDPOINT Specific endpoint + ENDPOINT Restore default endpoints DESCRIPTION Restore default enpoint ``` -_See code: [lib/commands/endpoint/default.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/endpoint/default.js)_ +_See code: [lib/commands/endpoint/default.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/endpoint/default.js)_ ## `proton endpoint:get` @@ -426,7 +424,7 @@ ALIASES $ proton endpoint ``` -_See code: [lib/commands/endpoint/get.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/endpoint/get.js)_ +_See code: [lib/commands/endpoint/get.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/endpoint/get.js)_ ## `proton endpoint:set [ENDPOINT]` @@ -443,7 +441,7 @@ DESCRIPTION Set current enpoint ``` -_See code: [lib/commands/endpoint/set.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/endpoint/set.js)_ +_See code: [lib/commands/endpoint/set.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/endpoint/set.js)_ ## `proton faucet` @@ -457,7 +455,7 @@ DESCRIPTION List all faucets ``` -_See code: [lib/commands/faucet/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/faucet/index.js)_ +_See code: [lib/commands/faucet/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/faucet/index.js)_ ## `proton faucet:claim SYMBOL AUTHORIZATION` @@ -475,7 +473,7 @@ DESCRIPTION Claim faucet ``` -_See code: [lib/commands/faucet/claim.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/faucet/claim.js)_ +_See code: [lib/commands/faucet/claim.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/faucet/claim.js)_ ## `proton generate:action` @@ -494,7 +492,7 @@ DESCRIPTION Add extra actions to the smart contract ``` -_See code: [lib/commands/generate/action.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/generate/action.js)_ +_See code: [lib/commands/generate/action.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/generate/action.js)_ ## `proton generate:contract CONTRACTNAME` @@ -514,7 +512,7 @@ DESCRIPTION Create new smart contract ``` -_See code: [lib/commands/generate/contract.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/generate/contract.js)_ +_See code: [lib/commands/generate/contract.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/generate/contract.js)_ ## `proton generate:inlineaction ACTIONNAME` @@ -536,7 +534,7 @@ DESCRIPTION Add inline action for the smart contract ``` -_See code: [lib/commands/generate/inlineaction.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/generate/inlineaction.js)_ +_See code: [lib/commands/generate/inlineaction.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/generate/inlineaction.js)_ ## `proton generate:table TABLENAME` @@ -560,7 +558,7 @@ DESCRIPTION Add table for the smart contract ``` -_See code: [lib/commands/generate/table.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/generate/table.js)_ +_See code: [lib/commands/generate/table.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/generate/table.js)_ ## `proton help [COMMAND]` @@ -594,7 +592,21 @@ DESCRIPTION Manage Keys ``` -_See code: [lib/commands/key/add.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/key/add.js)_ +_See code: [lib/commands/key/add.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/key/add.js)_ + +## `proton key:export` + +Export keys to text or QR code in PDF + +``` +USAGE + $ proton key:export + +DESCRIPTION + Export keys to text or QR code in PDF +``` + +_See code: [lib/commands/key/export.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/key/export.js)_ ## `proton key:generate` @@ -608,7 +620,7 @@ DESCRIPTION Generate Key ``` -_See code: [lib/commands/key/generate.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/key/generate.js)_ +_See code: [lib/commands/key/generate.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/key/generate.js)_ ## `proton key:get PUBLICKEY` @@ -622,7 +634,7 @@ DESCRIPTION Find private key for public key ``` -_See code: [lib/commands/key/get.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/key/get.js)_ +_See code: [lib/commands/key/get.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/key/get.js)_ ## `proton key:list` @@ -636,7 +648,7 @@ DESCRIPTION List All Key ``` -_See code: [lib/commands/key/list.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/key/list.js)_ +_See code: [lib/commands/key/list.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/key/list.js)_ ## `proton key:lock` @@ -650,7 +662,7 @@ DESCRIPTION Lock Keys with password ``` -_See code: [lib/commands/key/lock.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/key/lock.js)_ +_See code: [lib/commands/key/lock.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/key/lock.js)_ ## `proton key:remove [PRIVATEKEY]` @@ -664,7 +676,7 @@ DESCRIPTION Remove Key ``` -_See code: [lib/commands/key/remove.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/key/remove.js)_ +_See code: [lib/commands/key/remove.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/key/remove.js)_ ## `proton key:reset` @@ -678,7 +690,7 @@ DESCRIPTION Reset password (Caution: deletes all private keys stored) ``` -_See code: [lib/commands/key/reset.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/key/reset.js)_ +_See code: [lib/commands/key/reset.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/key/reset.js)_ ## `proton key:unlock [PASSWORD]` @@ -692,7 +704,7 @@ DESCRIPTION Unlock all keys (Caution: Your keys will be stored in plaintext on disk) ``` -_See code: [lib/commands/key/unlock.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/key/unlock.js)_ +_See code: [lib/commands/key/unlock.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/key/unlock.js)_ ## `proton msig:approve PROPOSER PROPOSAL AUTH` @@ -706,7 +718,7 @@ DESCRIPTION Multisig Approve ``` -_See code: [lib/commands/msig/approve.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/msig/approve.js)_ +_See code: [lib/commands/msig/approve.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/msig/approve.js)_ ## `proton msig:cancel PROPOSALNAME AUTH` @@ -720,7 +732,7 @@ DESCRIPTION Multisig Cancel ``` -_See code: [lib/commands/msig/cancel.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/msig/cancel.js)_ +_See code: [lib/commands/msig/cancel.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/msig/cancel.js)_ ## `proton msig:exec PROPOSER PROPOSAL AUTH` @@ -734,7 +746,7 @@ DESCRIPTION Multisig Execute ``` -_See code: [lib/commands/msig/exec.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/msig/exec.js)_ +_See code: [lib/commands/msig/exec.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/msig/exec.js)_ ## `proton msig:propose PROPOSALNAME ACTIONS AUTH` @@ -752,7 +764,7 @@ DESCRIPTION Multisig Propose ``` -_See code: [lib/commands/msig/propose.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/msig/propose.js)_ +_See code: [lib/commands/msig/propose.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/msig/propose.js)_ ## `proton network` @@ -784,7 +796,7 @@ DESCRIPTION Update Permission ``` -_See code: [lib/commands/permission/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/permission/index.js)_ +_See code: [lib/commands/permission/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/permission/index.js)_ ## `proton permission:link ACCOUNT PERMISSION CONTRACT [ACTION]` @@ -801,7 +813,7 @@ DESCRIPTION Link Auth ``` -_See code: [lib/commands/permission/link.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/permission/link.js)_ +_See code: [lib/commands/permission/link.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/permission/link.js)_ ## `proton permission:unlink ACCOUNT CONTRACT [ACTION]` @@ -818,7 +830,7 @@ DESCRIPTION Unlink Auth ``` -_See code: [lib/commands/permission/unlink.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/permission/unlink.js)_ +_See code: [lib/commands/permission/unlink.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/permission/unlink.js)_ ## `proton psr URI` @@ -832,7 +844,7 @@ DESCRIPTION Create Session ``` -_See code: [lib/commands/psr/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/psr/index.js)_ +_See code: [lib/commands/psr/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/psr/index.js)_ ## `proton ram` @@ -846,7 +858,7 @@ DESCRIPTION List Ram price ``` -_See code: [lib/commands/ram/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/ram/index.js)_ +_See code: [lib/commands/ram/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/ram/index.js)_ ## `proton ram:buy BUYER RECEIVER BYTES` @@ -868,7 +880,7 @@ DESCRIPTION Claim faucet ``` -_See code: [lib/commands/ram/buy.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/ram/buy.js)_ +_See code: [lib/commands/ram/buy.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/ram/buy.js)_ ## `proton rpc:accountsbyauthorizers AUTHORIZATIONS [KEYS]` @@ -882,7 +894,7 @@ DESCRIPTION Get Accounts by Authorization ``` -_See code: [lib/commands/rpc/accountsbyauthorizers.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/rpc/accountsbyauthorizers.js)_ +_See code: [lib/commands/rpc/accountsbyauthorizers.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/rpc/accountsbyauthorizers.js)_ ## `proton scan ACCOUNT` @@ -896,7 +908,7 @@ DESCRIPTION Open Account in Proton Scan ``` -_See code: [lib/commands/scan/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/scan/index.js)_ +_See code: [lib/commands/scan/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/scan/index.js)_ ## `proton table CONTRACT [TABLE] [SCOPE]` @@ -920,7 +932,7 @@ DESCRIPTION Get Table Storage Rows ``` -_See code: [lib/commands/table/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/table/index.js)_ +_See code: [lib/commands/table/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/table/index.js)_ ## `proton transaction JSON` @@ -934,7 +946,7 @@ DESCRIPTION Execute Transaction ``` -_See code: [lib/commands/transaction/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/transaction/index.js)_ +_See code: [lib/commands/transaction/index.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/transaction/index.js)_ ## `proton transaction:get ID` @@ -948,7 +960,7 @@ DESCRIPTION Get Transaction by Transaction ID ``` -_See code: [lib/commands/transaction/get.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/transaction/get.js)_ +_See code: [lib/commands/transaction/get.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/transaction/get.js)_ ## `proton transaction:push TRANSACTION` @@ -965,7 +977,7 @@ DESCRIPTION Push Transaction ``` -_See code: [lib/commands/transaction/push.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/transaction/push.js)_ +_See code: [lib/commands/transaction/push.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/transaction/push.js)_ ## `proton version` @@ -979,6 +991,5 @@ DESCRIPTION Version of CLI ``` -_See code: [lib/commands/version.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.95/lib/commands/version.js)_ - +_See code: [lib/commands/version.js](https://github.com/ProtonProtocol/proton-cli/blob/v0.1.96/lib/commands/version.js)_ diff --git a/src/utils/pdfExport.ts b/src/utils/pdfExport.ts index 60779eb..84d3dcc 100644 --- a/src/utils/pdfExport.ts +++ b/src/utils/pdfExport.ts @@ -2,6 +2,11 @@ import pdfMake from "pdfmake"; import fs from "fs"; import path from "path"; import { ExportAccountType } from "../commands/key/export"; +import { + CanvasElement, + Content, + TDocumentDefinitions, +} from "pdfmake/interfaces"; const longText = "The amount of data that can be stored in the QR code symbol depends on the datatype (mode, or input character set), version (1, …, 40, indicating the overall dimensions of the symbol), and error correction level. The maximum storage capacities occur for 40-L symbols (version 40, error correction level L):"; @@ -19,7 +24,7 @@ export function createPdf( showPrivateKey?: boolean ) { const PdfPrinter = new pdfMake(fonts); - const docDefinition = { + const docDefinition: TDocumentDefinitions = { version: "1.7ext3", pageSize: "A5", content: [ @@ -28,7 +33,9 @@ export function createPdf( text: "This following documents contains highly sensitive informations, make sure to store it securely. If you print it, store it into a secure vault and delete the file.", pageBreak: "after", }, - ...accounts.map((account) => exportAccount(account, showPrivateKey)), + ...(accounts.map((account) => + exportAccount(account, showPrivateKey) + ) as Content[]), ], styles: { fieldHeader: { @@ -40,7 +47,7 @@ export function createPdf( fontSize: 16, }, waLabel: { - align: "center", + alignment: "center" as const, background: "black", color: "#FFFFFF", }, @@ -62,7 +69,10 @@ export function createPdf( pdf.end(); } -function exportAccount(account: ExportAccountType, showPrivateKey?: boolean) { +function exportAccount( + account: ExportAccountType, + showPrivateKey?: boolean +): Content { const definition = { pageBreak: "after", table: { @@ -124,5 +134,5 @@ function exportAccount(account: ExportAccountType, showPrivateKey?: boolean) { ], ]); } - return definition; + return definition as Content; } diff --git a/src/utils/pubkeyToAccount.ts b/src/utils/pubkeyToAccount.ts index 5aaa9c9..22a8df0 100644 --- a/src/utils/pubkeyToAccount.ts +++ b/src/utils/pubkeyToAccount.ts @@ -1,13 +1,5 @@ import { LIGHT_CLIENT_ENDPOINTS } from "../constants"; -import { wait } from "./wait"; -type LookupKeyResponse = { - [key: "protontest" | "proton"]: { - accounts: { - [key: string]: []; - }; - }; -}; export async function pubKeyToAccount( publicKey: string, chain: string, From 0bcbb028dac63221f0621d9227502b765e5de4eb Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Thu, 24 Jul 2025 23:24:45 +0200 Subject: [PATCH 10/13] =?UTF-8?q?=F0=9F=94=96=20=20Bump=20to=200.1.96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 24cf0a5..22fcf57 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@proton/cli", "description": "Proton CLI", - "version": "0.1.95", + "version": "0.1.96", "author": "Syed Jafri @jafri", "contributors": [ "Rockerone @superstrongBE", From 3d7cb0d88b57418e763695e45db8ac5b2efddee3 Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Fri, 25 Jul 2025 12:50:11 +0200 Subject: [PATCH 11/13] =?UTF-8?q?=F0=9F=93=A6=20=20Fix=20missing=20fixutre?= =?UTF-8?q?s=20on=20build.=20Bump=20node=20min=20version.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 22fcf57..2c83286 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "build": "npm run prepack && npm run postpack", "postpack": "rm -f oclif.manifest.json", "posttest": "eslint . --ext .ts --config .eslintrc", - "prepack": "rm -rf lib && tsc -b && npx oclif manifest && npx oclif readme && shx cp -r src/templates lib", + "prepack": "rm -rf lib && tsc -b && npx oclif manifest && npx oclif readme && shx cp -r src/templates src/fixtures lib", "testbase": "nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\"", "test": "npm run testbase -- \"test/**/*.test.ts\"", "testsome": "nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\" --exclude \"**/boilerplate.test.ts\"", @@ -128,6 +128,6 @@ } }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" } } From bdb9307216a958b68305315dcccb862914d1d9ce Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Fri, 25 Jul 2025 12:51:44 +0200 Subject: [PATCH 12/13] =?UTF-8?q?=F0=9F=9A=B8=20Adding=20file=20name=20pro?= =?UTF-8?q?mpt=20with=20default=20including=20minutes=20and=20seconds.=20R?= =?UTF-8?q?emove=20orphan=20pages.=20Per=20page=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/key/export.ts | 29 +++++++++++++++++++-------- src/utils/pdfExport.ts | 40 +++++++++++++++++++------------------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/commands/key/export.ts b/src/commands/key/export.ts index 6cad8a1..f405d9d 100644 --- a/src/commands/key/export.ts +++ b/src/commands/key/export.ts @@ -41,6 +41,7 @@ export type ExportConfig = { protectFile?: boolean; password?: string; exportPath?: string; + fileName?: string; }; export default class ExportKeys extends Command { @@ -49,12 +50,12 @@ export default class ExportKeys extends Command { async run() { const privateKeys = await passwordManager.getPrivateKeys(); const chain = config.get("currentChain"); - const pdfFileName = `${chain}_keys_${new Date().getFullYear()}_${new Date().getMonth()}_${new Date().getDate()}`; + const pdfFileName = `${chain}_keys_${new Date().getFullYear()}_${new Date().getMonth()}_${new Date().getDate()}_${new Date().getHours()}_${new Date().getMinutes()}`; const agree = await inquirer.prompt([ { name: "agree", message: - "You are about to export accounts's sensitive information. Do you agree ?", + "You are about to export accounts's sensitive information. Do you agree?", type: "confirm", }, ]); @@ -67,6 +68,7 @@ export default class ExportKeys extends Command { const exportConfig: ExportConfig = { mode: "txt", showPrivateKey: false, + fileName: pdfFileName, }; const search = await inquirer.prompt([ @@ -94,6 +96,17 @@ export default class ExportKeys extends Command { exportConfig.mode = exportMode.mode; + const fileName = await inquirer.prompt([ + { + name: "fileName", + message: "Enter the file name (default: " + pdfFileName + ")", + type: "input", + default: pdfFileName, + }, + ]); + + exportConfig.fileName = fileName.fileName; + if (exportConfig.mode === "pdf") { const displayPrivateKey = await inquirer.prompt([ { @@ -169,7 +182,7 @@ export default class ExportKeys extends Command { if (exportMode.mode === "pdf") { createPdf( uniqueExportedKeys, - `${pdfFileName}.pdf`, + `${exportConfig.fileName}.pdf`, exportConfig.password, exportConfig.showPrivateKey ); @@ -179,22 +192,22 @@ export default class ExportKeys extends Command { const txtContent = uniqueExportedKeys.map((item) => { return `${JSON.stringify(item)}\n`; }); - createTxtFile(txtContent.join(""), `${pdfFileName}.txt`); + createTxtFile(txtContent.join(""), `${exportConfig.fileName}.txt`); } if (exportConfig.mode === "json") { createTxtFile( JSON.stringify(uniqueExportedKeys, null, 2), - `${pdfFileName}.json` + `${exportConfig.fileName}.json` ); } CliUx.ux.action.stop(green(`Done`)); CliUx.ux.log( green( - `Exported ${ - uniqueExportedKeys.length - } keys to ${process.cwd()}/${pdfFileName}.${exportMode.mode}` + `Exported ${uniqueExportedKeys.length} keys to ${process.cwd()}/${ + exportConfig.fileName + }.${exportMode.mode}` ) ); }); diff --git a/src/utils/pdfExport.ts b/src/utils/pdfExport.ts index 84d3dcc..1f2318c 100644 --- a/src/utils/pdfExport.ts +++ b/src/utils/pdfExport.ts @@ -2,13 +2,7 @@ import pdfMake from "pdfmake"; import fs from "fs"; import path from "path"; import { ExportAccountType } from "../commands/key/export"; -import { - CanvasElement, - Content, - TDocumentDefinitions, -} from "pdfmake/interfaces"; -const longText = - "The amount of data that can be stored in the QR code symbol depends on the datatype (mode, or input character set), version (1, …, 40, indicating the overall dimensions of the symbol), and error correction level. The maximum storage capacities occur for 40-L symbols (version 40, error correction level L):"; +import { Content, TDocumentDefinitions } from "pdfmake/interfaces"; const fonts = { Roboto: { @@ -28,23 +22,21 @@ export function createPdf( version: "1.7ext3", pageSize: "A5", content: [ - { text: "WARNING." }, - { - text: "This following documents contains highly sensitive informations, make sure to store it securely. If you print it, store it into a secure vault and delete the file.", - pageBreak: "after", - }, - ...(accounts.map((account) => - exportAccount(account, showPrivateKey) + ...(accounts.map((account, index) => + exportAccount(account, showPrivateKey, index < accounts.length - 1) ) as Content[]), ], styles: { fieldHeader: { fontSize: 10, - color: "#737373", }, + warning: { + fontSize: 10, + color: "#FF0000", + }, fieldValue: { - fontSize: 16, + fontSize: 12, }, waLabel: { alignment: "center" as const, @@ -71,13 +63,21 @@ export function createPdf( function exportAccount( account: ExportAccountType, - showPrivateKey?: boolean + showPrivateKey?: boolean, + breakPage?: boolean ): Content { const definition = { - pageBreak: "after", + pageBreak: breakPage ? "after" : undefined, + table: { widths: ["100%"], body: [ + [ + { + text: "This following documents contains highly sensitive informations, make sure to store it securely. If you print it, store it into a secure vault and delete the file.", + style: "warning", + }, + ], [ [ { text: "Chain", style: "fieldHeader" }, @@ -88,8 +88,8 @@ function exportAccount( [ { qr: account.privateKey, - fit: 260, - margin: [40, 40, 40, 20], + fit: 200, + margin: [70, 20, 40, 20], }, { margin: [40, 0, 40, 40], From 58c5ea60ea32ccb100cf072039274e38007473df Mon Sep 17 00:00:00 2001 From: Remy Chauveau Date: Mon, 11 Aug 2025 19:47:43 +0200 Subject: [PATCH 13/13] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fixed=20typo=20from?= =?UTF-8?q?=20external=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/pdfExport.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/pdfExport.ts b/src/utils/pdfExport.ts index 1f2318c..4b7fc62 100644 --- a/src/utils/pdfExport.ts +++ b/src/utils/pdfExport.ts @@ -81,7 +81,7 @@ function exportAccount( [ [ { text: "Chain", style: "fieldHeader" }, - { text: account.chain, style: "filedValue" }, + { text: account.chain, style: "fieldValue" }, ], ], [ @@ -114,13 +114,13 @@ function exportAccount( [ [ { text: "Accounts", style: "fieldHeader" }, - { text: account.accounts?.join(", "), style: "filedValue" }, + { text: account.accounts?.join(", "), style: "fieldValue" }, ], ], [ [ { text: "Public key", style: "fieldHeader" }, - { text: account.publicKey, style: "filedValue" }, + { text: account.publicKey, style: "fieldValue" }, ], ], ], @@ -130,7 +130,7 @@ function exportAccount( definition.table.body.push([ [ { text: "Private key", style: "fieldHeader" }, - { text: account.privateKey, style: "filedValue" }, + { text: account.privateKey, style: "fieldValue" }, ], ]); }