mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-utils.git
synced 2026-11-06 09:11:06 +00:00
Root signing page and a root chain check for replacing the root keys (#81)
- signed_config.py root drafts a later root in docs/root-signing/proposals/, where wallets never look, and keeps the current targets key by default. - docs/root-signing/: a page for the Pezkuwi Wallet DApp browser that shows the proposal and its fingerprint, has the holder's wallet sign <Bytes>payload</Bytes>, checks every signature as the wallet will, collects signature codes and offers root.N.json once two current and two new holders have signed. Crypto bundles are served beside it. - scripts/root/verify_root.mjs checks every published signed/root.N.json the way installed wallets do; Code Quality runs it. Wallet 1.3.0 accepts sr25519 only under the substrate signing context, and a root it cannot verify stops its config refresh, so such a root must never reach master. - Draft root 2: three new holder accounts, threshold 2, five years.
This commit is contained in:
1 parent
7d53e16b76
commit
6864b8c0aa
13 files changed
+27902
-8
No files matched your search
Generated
+562
@@ -0,0 +1,562 @@
|
||||
{
|
||||
"name": "pezkuwi-wallet-utils-root",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pezkuwi-wallet-utils-root",
|
||||
"dependencies": {
|
||||
"@pezkuwi/util": "14.0.26",
|
||||
"@pezkuwi/util-crypto": "14.0.26",
|
||||
"@polkadot/util": "13.5.9",
|
||||
"@polkadot/util-crypto": "13.5.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/curves": {
|
||||
"version": "1.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz",
|
||||
"integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.21.3 || >=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
|
||||
"integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^14.21.3 || >=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/networks": {
|
||||
"version": "14.0.26",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/networks/-/networks-14.0.26.tgz",
|
||||
"integrity": "sha512-omDbJzFjDSm1FS32zebyNP1QGBk9/ZayM0YM0mUlOOwiLIP7iDVq3KQe2JdI7hm1dz01Lm68/hjerSoqiWEclA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@pezkuwi/util": "14.0.26",
|
||||
"@substrate/ss58-registry": "^1.51.0",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/scure-sr25519": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/scure-sr25519/-/scure-sr25519-0.2.1.tgz",
|
||||
"integrity": "sha512-KGxCR+fI4p8QyIpwmRNIj8fbq7O+yz0iZZ/O2HJBVE7O9D6ksBKwIILqODJfE6Qvrf3F8DyT6/3cPoR3e/s8iA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/curves": "~1.9.2",
|
||||
"@noble/hashes": "~1.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/util": {
|
||||
"version": "14.0.26",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/util/-/util-14.0.26.tgz",
|
||||
"integrity": "sha512-xV7uct4jtIqf+9LixcCoTgYz8JEZ2eK6aosMD92Zu5DRPSW87QcCYBQuq8Phec0LdjGvC/l7DgiloQODhTtHWA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@pezkuwi/x-bigint": "14.0.26",
|
||||
"@pezkuwi/x-global": "14.0.26",
|
||||
"@pezkuwi/x-textdecoder": "14.0.26",
|
||||
"@pezkuwi/x-textencoder": "14.0.26",
|
||||
"@types/bn.js": "^5.1.6",
|
||||
"bn.js": "^5.2.1",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/util-crypto": {
|
||||
"version": "14.0.26",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/util-crypto/-/util-crypto-14.0.26.tgz",
|
||||
"integrity": "sha512-YR+3N2FwKx3q9NF11q75O0lJ+SKpM9CNKPE7rLEoPvFt7wpHpB/GXOAekYhNtrotkcsI8v/WoyOi4RI9NiwYVQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@noble/curves": "^1.9.7",
|
||||
"@noble/hashes": "^1.8.0",
|
||||
"@pezkuwi/networks": "14.0.26",
|
||||
"@pezkuwi/scure-sr25519": "^0.2.1",
|
||||
"@pezkuwi/util": "14.0.26",
|
||||
"@pezkuwi/wasm-crypto": "^7.5.20",
|
||||
"@pezkuwi/wasm-util": "^7.5.20",
|
||||
"@pezkuwi/x-bigint": "14.0.26",
|
||||
"@pezkuwi/x-randomvalues": "14.0.26",
|
||||
"@scure/base": "^1.1.7",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pezkuwi/util": "14.0.26"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/wasm-bridge": {
|
||||
"version": "7.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/wasm-bridge/-/wasm-bridge-7.5.21.tgz",
|
||||
"integrity": "sha512-KVWLXpmVHpYo1+woN+o8OK03Kk8+VwUtF/Dn5pnsVXbsGbXM22HWbx36ChzdkjpW35a5Ukfk92H0aCy8klfeDg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@pezkuwi/wasm-util": "7.5.21",
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pezkuwi/util": "*",
|
||||
"@pezkuwi/x-randomvalues": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/wasm-crypto": {
|
||||
"version": "7.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/wasm-crypto/-/wasm-crypto-7.5.21.tgz",
|
||||
"integrity": "sha512-gL771hQsC0NXPFTX4+yKTPEMfX1svRAM1lzep+LkniQcYqpqI4AAxzUaOGZYj5lQzXKSkgYpcaLuTZ441zPXAg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "^1.3.3",
|
||||
"@pezkuwi/wasm-bridge": "7.5.21",
|
||||
"@pezkuwi/wasm-crypto-asmjs": "7.5.21",
|
||||
"@pezkuwi/wasm-crypto-init": "7.5.21",
|
||||
"@pezkuwi/wasm-crypto-wasm": "7.5.21",
|
||||
"@pezkuwi/wasm-util": "7.5.21",
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pezkuwi/util": "*",
|
||||
"@pezkuwi/x-randomvalues": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/wasm-crypto-asmjs": {
|
||||
"version": "7.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/wasm-crypto-asmjs/-/wasm-crypto-asmjs-7.5.21.tgz",
|
||||
"integrity": "sha512-uqhAR3slp6qbn2Cf7g72v4Ko0hxWm/NuZL2ZDH65QBSGP9jkSnAoBjm5L7AO739quEVA8rFsR8CxN5gvzERspA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pezkuwi/util": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/wasm-crypto-init": {
|
||||
"version": "7.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/wasm-crypto-init/-/wasm-crypto-init-7.5.21.tgz",
|
||||
"integrity": "sha512-pdgYqhsHIoxTdhwbxS8iacw4sFh3NLN9fJ3odzCAo4+QCr3xTU1FMjBiYJRkx6Q4BpthCjOWJPCwTEZnJ3lSCg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@pezkuwi/wasm-bridge": "7.5.21",
|
||||
"@pezkuwi/wasm-crypto-asmjs": "7.5.21",
|
||||
"@pezkuwi/wasm-crypto-wasm": "7.5.21",
|
||||
"@pezkuwi/wasm-util": "7.5.21",
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pezkuwi/util": "*",
|
||||
"@pezkuwi/x-randomvalues": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/wasm-crypto-wasm": {
|
||||
"version": "7.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/wasm-crypto-wasm/-/wasm-crypto-wasm-7.5.21.tgz",
|
||||
"integrity": "sha512-TR8hHkjY6oga4aI9Irlv/y00+KwiCBMt+EyXi3mTUVNn7qKE4DwXbDc/az4rLK8p5Kno4/iyCF6YXuHbjEK4Ag==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@pezkuwi/wasm-util": "7.5.21",
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pezkuwi/util": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/wasm-util": {
|
||||
"version": "7.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/wasm-util/-/wasm-util-7.5.21.tgz",
|
||||
"integrity": "sha512-KMiUHCEa6iFNLNWyw9GUf5/K2UP6RjCia2iSGjcazwBNofAQVpP6zfeLb9y5szpextKGkDsODxpcIFenJ3KcFQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pezkuwi/util": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/x-bigint": {
|
||||
"version": "14.0.26",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/x-bigint/-/x-bigint-14.0.26.tgz",
|
||||
"integrity": "sha512-TiCUVJiW07KurXot79AuKsqdIKGCtysMVDKLGlUc7mxlDJ+BCNJVmi9D0vvbB/gboxfJqONFQKt8eOXHKFg1iw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@pezkuwi/x-global": "14.0.26",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/x-global": {
|
||||
"version": "14.0.26",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/x-global/-/x-global-14.0.26.tgz",
|
||||
"integrity": "sha512-3D/dgFUugJfJ59JETey2EPpWL7X7NOrSEgNj1Rt3Vu9zR74QNocc5HEcyapFKj2hNNp5gPPDOOWbrLkkDnbdXw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/x-randomvalues": {
|
||||
"version": "14.0.26",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/x-randomvalues/-/x-randomvalues-14.0.26.tgz",
|
||||
"integrity": "sha512-9tQ5+e7b5sC6y7NWFojfkfKZNSmWBpB1dnuyMv5vJMPlBPlsscTYARfk8ln860XWLdemQBYBvYbibmEBtLFfSQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@pezkuwi/x-global": "14.0.26",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pezkuwi/util": "14.0.26",
|
||||
"@pezkuwi/wasm-util": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/x-textdecoder": {
|
||||
"version": "14.0.26",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/x-textdecoder/-/x-textdecoder-14.0.26.tgz",
|
||||
"integrity": "sha512-O3l/pcT+7q89COMe+h+Gr+HLLym3k0RfWXWwEg6RYGBHxp77GfixwqAR/o6k6rBXNfxlAY60RcYUqu+DGkKSZw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@pezkuwi/x-global": "14.0.26",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@pezkuwi/x-textencoder": {
|
||||
"version": "14.0.26",
|
||||
"resolved": "https://registry.npmjs.org/@pezkuwi/x-textencoder/-/x-textencoder-14.0.26.tgz",
|
||||
"integrity": "sha512-aUk+h0g5iO+V3CZV1vdlRy4G9MbE0SbomB5Lw/8IkuQ+wNPK9JQ1FlArMhxVBfXM9JD8DPih/ViZsaNhWfjVVw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@pezkuwi/x-global": "14.0.26",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/networks": {
|
||||
"version": "13.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/networks/-/networks-13.5.9.tgz",
|
||||
"integrity": "sha512-nmKUKJjiLgcih0MkdlJNMnhEYdwEml2rv/h59ll2+rAvpsVWMTLCb6Cq6q7UC44+8kiWK2UUJMkFU+3PFFxndA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@polkadot/util": "13.5.9",
|
||||
"@substrate/ss58-registry": "^1.51.0",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/util": {
|
||||
"version": "13.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/util/-/util-13.5.9.tgz",
|
||||
"integrity": "sha512-pIK3XYXo7DKeFRkEBNYhf3GbCHg6dKQisSvdzZwuyzA6m7YxQq4DFw4IE464ve4Z7WsJFt3a6C9uII36hl9EWw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@polkadot/x-bigint": "13.5.9",
|
||||
"@polkadot/x-global": "13.5.9",
|
||||
"@polkadot/x-textdecoder": "13.5.9",
|
||||
"@polkadot/x-textencoder": "13.5.9",
|
||||
"@types/bn.js": "^5.1.6",
|
||||
"bn.js": "^5.2.1",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/util-crypto": {
|
||||
"version": "13.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/util-crypto/-/util-crypto-13.5.9.tgz",
|
||||
"integrity": "sha512-foUesMhxkTk8CZ0/XEcfvHk6I0O+aICqqVJllhOpyp/ZVnrTBKBf59T6RpsXx2pCtBlMsLRvg/6Mw7RND1HqDg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@noble/curves": "^1.3.0",
|
||||
"@noble/hashes": "^1.3.3",
|
||||
"@polkadot/networks": "13.5.9",
|
||||
"@polkadot/util": "13.5.9",
|
||||
"@polkadot/wasm-crypto": "^7.5.3",
|
||||
"@polkadot/wasm-util": "^7.5.3",
|
||||
"@polkadot/x-bigint": "13.5.9",
|
||||
"@polkadot/x-randomvalues": "13.5.9",
|
||||
"@scure/base": "^1.1.7",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util": "13.5.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/wasm-bridge": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/wasm-bridge/-/wasm-bridge-7.5.4.tgz",
|
||||
"integrity": "sha512-6xaJVvoZbnbgpQYXNw9OHVNWjXmtcoPcWh7hlwx3NpfiLkkjljj99YS+XGZQlq7ks2fVCg7FbfknkNb8PldDaA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@polkadot/wasm-util": "7.5.4",
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util": "*",
|
||||
"@polkadot/x-randomvalues": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/wasm-crypto": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto/-/wasm-crypto-7.5.4.tgz",
|
||||
"integrity": "sha512-1seyClxa7Jd7kQjfnCzTTTfYhTa/KUTDUaD3DMHBk5Q4ZUN1D1unJgX+v1aUeXSPxmzocdZETPJJRZjhVOqg9g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@polkadot/wasm-bridge": "7.5.4",
|
||||
"@polkadot/wasm-crypto-asmjs": "7.5.4",
|
||||
"@polkadot/wasm-crypto-init": "7.5.4",
|
||||
"@polkadot/wasm-crypto-wasm": "7.5.4",
|
||||
"@polkadot/wasm-util": "7.5.4",
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util": "*",
|
||||
"@polkadot/x-randomvalues": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/wasm-crypto-asmjs": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-7.5.4.tgz",
|
||||
"integrity": "sha512-ZYwxQHAJ8pPt6kYk9XFmyuFuSS+yirJLonvP+DYbxOrARRUHfN4nzp4zcZNXUuaFhpbDobDSFn6gYzye6BUotA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/wasm-crypto-init": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-init/-/wasm-crypto-init-7.5.4.tgz",
|
||||
"integrity": "sha512-U6s4Eo2rHs2n1iR01vTz/sOQ7eOnRPjaCsGWhPV+ZC/20hkVzwPAhiizu/IqMEol4tO2yiSheD4D6bn0KxUJhg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@polkadot/wasm-bridge": "7.5.4",
|
||||
"@polkadot/wasm-crypto-asmjs": "7.5.4",
|
||||
"@polkadot/wasm-crypto-wasm": "7.5.4",
|
||||
"@polkadot/wasm-util": "7.5.4",
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util": "*",
|
||||
"@polkadot/x-randomvalues": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/wasm-crypto-wasm": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-7.5.4.tgz",
|
||||
"integrity": "sha512-PsHgLsVTu43eprwSvUGnxybtOEuHPES6AbApcs7y5ZbM2PiDMzYbAjNul098xJK/CPtrxZ0ePDFnaQBmIJyTFw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@polkadot/wasm-util": "7.5.4",
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/wasm-util": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/wasm-util/-/wasm-util-7.5.4.tgz",
|
||||
"integrity": "sha512-hqPpfhCpRAqCIn/CYbBluhh0TXmwkJnDRjxrU9Bnqtw9nMNa97D8JuOjdd2pi0rxm+eeLQ/f1rQMp71RMM9t4w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/x-bigint": {
|
||||
"version": "13.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/x-bigint/-/x-bigint-13.5.9.tgz",
|
||||
"integrity": "sha512-JVW6vw3e8fkcRyN9eoc6JIl63MRxNQCP/tuLdHWZts1tcAYao0hpWUzteqJY93AgvmQ91KPsC1Kf3iuuZCi74g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@polkadot/x-global": "13.5.9",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/x-global": {
|
||||
"version": "13.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/x-global/-/x-global-13.5.9.tgz",
|
||||
"integrity": "sha512-zSRWvELHd3Q+bFkkI1h2cWIqLo1ETm+MxkNXLec3lB56iyq/MjWBxfXnAFFYFayvlEVneo7CLHcp+YTFd9aVSA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/x-randomvalues": {
|
||||
"version": "13.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/x-randomvalues/-/x-randomvalues-13.5.9.tgz",
|
||||
"integrity": "sha512-Uuuz3oubf1JCCK97fsnVUnHvk4BGp/W91mQWJlgl5TIOUSSTIRr+lb5GurCfl4kgnQq53Zi5fJV+qR9YumbnZw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@polkadot/x-global": "13.5.9",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util": "13.5.9",
|
||||
"@polkadot/wasm-util": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/x-textdecoder": {
|
||||
"version": "13.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/x-textdecoder/-/x-textdecoder-13.5.9.tgz",
|
||||
"integrity": "sha512-W2HhVNUbC/tuFdzNMbnXAWsIHSg9SC9QWDNmFD3nXdSzlXNgL8NmuiwN2fkYvCQBtp/XSoy0gDLx0C+Fo19cfw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@polkadot/x-global": "13.5.9",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@polkadot/x-textencoder": {
|
||||
"version": "13.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@polkadot/x-textencoder/-/x-textencoder-13.5.9.tgz",
|
||||
"integrity": "sha512-SG0MHnLUgn1ZxFdm0KzMdTHJ47SfqFhdIPMcGA0Mg/jt2rwrfrP3jtEIJMsHfQpHvfsNPfv55XOMmoPWuQnP/Q==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@polkadot/x-global": "13.5.9",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@scure/base": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz",
|
||||
"integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@substrate/ss58-registry": {
|
||||
"version": "1.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@substrate/ss58-registry/-/ss58-registry-1.51.0.tgz",
|
||||
"integrity": "sha512-TWDurLiPxndFgKjVavCniytBIw+t4ViOi7TYp9h/D0NMmkEc9klFTo+827eyEJ0lELpqO207Ey7uGxUa+BS1jQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@types/bn.js": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.2.0.tgz",
|
||||
"integrity": "sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "26.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.6.tgz",
|
||||
"integrity": "sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~8.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bn.js": {
|
||||
"version": "5.2.5",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.5.tgz",
|
||||
"integrity": "sha512-Vq886eXykuP5E6HcKSSStP3bJgrE6In5WKxVUvJ8XGpWWYs2xZHWqUwzCtGgEtBcxyd57KBFDPFoUfNzdaHCNg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.9.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz",
|
||||
"integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "8.9.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz",
|
||||
"integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "pezkuwi-wallet-utils-root",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Verifies the signed config root chain as the wallet does",
|
||||
"dependencies": {
|
||||
"@pezkuwi/util": "14.0.26",
|
||||
"@pezkuwi/util-crypto": "14.0.26",
|
||||
"@polkadot/util": "13.5.9",
|
||||
"@polkadot/util-crypto": "13.5.9"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// Verifies the published root chain the way the wallet does, so a root that installed wallets would refuse
|
||||
// is never published: a root they cannot verify stops their config refresh.
|
||||
//
|
||||
// signed/root.json is the root the APK carries. Each signed/root.N.json after it must be the next version and
|
||||
// carry valid signatures from a threshold of the previous root's keys and of its own. An sr25519 key is a
|
||||
// wallet account and signs <Bytes>payload</Bytes>. Wallet 1.3.0 checks sr25519 under the "substrate" signing
|
||||
// context only, so that is what counts; a signature valid only under "bizinikiwi" is reported, not counted.
|
||||
//
|
||||
// node scripts/root/verify_root.mjs check the published chain
|
||||
// node scripts/root/verify_root.mjs FILE... also report the signatures on proposals
|
||||
|
||||
import { readFileSync, existsSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { cryptoWaitReady as polkadotReady, sr25519Verify as substrateVerify } from '@polkadot/util-crypto';
|
||||
import { cryptoWaitReady as pezkuwiReady, sr25519Verify as bizinikiwiVerify, ed25519Verify } from '@pezkuwi/util-crypto';
|
||||
|
||||
const REPO = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
||||
const SIGNED = join(REPO, 'signed');
|
||||
|
||||
const sha256Hex = (bytes) => createHash('sha256').update(bytes).digest('hex');
|
||||
const wrapBytes = (payload) => Buffer.concat([Buffer.from('<Bytes>'), payload, Buffer.from('</Bytes>')]);
|
||||
|
||||
function readEnvelope(path) {
|
||||
const envelope = JSON.parse(readFileSync(path, 'utf8'));
|
||||
const payload = Buffer.from(envelope.signed, 'base64');
|
||||
return { payload, root: JSON.parse(payload.toString('utf8')), signatures: envelope.signatures };
|
||||
}
|
||||
|
||||
function parseRoot(root) {
|
||||
if (root.type !== 'root') throw new Error(`type is ${root.type}, not root`);
|
||||
const keys = {};
|
||||
for (const [keyId, key] of Object.entries(root.keys)) {
|
||||
const bytes = Buffer.from(key.public, 'base64');
|
||||
if (bytes.length !== 32 || sha256Hex(bytes) !== keyId) throw new Error(`key ${keyId} does not match its id`);
|
||||
if (key.scheme !== 'sr25519' && key.scheme !== 'ed25519') throw new Error(`key ${keyId} has unknown scheme ${key.scheme}`);
|
||||
keys[keyId] = { scheme: key.scheme, bytes };
|
||||
}
|
||||
for (const role of ['root', 'targets']) {
|
||||
const { keyids, threshold } = root[role];
|
||||
if (threshold < 1 || threshold > keyids.length || !keyids.every((id) => id in keys)) throw new Error(`unusable ${role} role`);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
// keyId -> "substrate" | "bizinikiwi" | "ed25519" | null for each signature on payload
|
||||
function classify(payload, signatures, keys) {
|
||||
const result = new Map();
|
||||
for (const { keyid, sig } of signatures) {
|
||||
const key = keys[keyid];
|
||||
if (!key) continue;
|
||||
const signature = Buffer.from(sig, 'base64');
|
||||
let kind = null;
|
||||
if (key.scheme === 'ed25519') {
|
||||
if (ed25519Verify(payload, signature, key.bytes)) kind = 'ed25519';
|
||||
} else if (substrateVerify(wrapBytes(payload), signature, key.bytes)) {
|
||||
kind = 'substrate';
|
||||
} else if (bizinikiwiVerify(wrapBytes(payload), signature, key.bytes)) {
|
||||
kind = 'bizinikiwi';
|
||||
}
|
||||
if (!result.get(keyid)) result.set(keyid, kind);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function count(classified, keyIds) {
|
||||
const accepted = keyIds.filter((id) => ['substrate', 'ed25519'].includes(classified.get(id)));
|
||||
const contextOnly = keyIds.filter((id) => classified.get(id) === 'bizinikiwi');
|
||||
return { accepted: accepted.length, contextOnly: contextOnly.length };
|
||||
}
|
||||
|
||||
function checkNext(previous, path) {
|
||||
const next = readEnvelope(path);
|
||||
const nextKeys = parseRoot(next.root);
|
||||
if (next.root.version !== previous.root.version + 1) {
|
||||
throw new Error(`version ${next.root.version} does not follow ${previous.root.version}`);
|
||||
}
|
||||
const lines = [];
|
||||
let ok = true;
|
||||
for (const [label, keys, role] of [
|
||||
['previous root', previous.keys, previous.root.root],
|
||||
['its own root', nextKeys, next.root.root],
|
||||
]) {
|
||||
const { accepted, contextOnly } = count(classify(next.payload, next.signatures, keys), role.keyids);
|
||||
const met = accepted >= role.threshold;
|
||||
ok &&= met;
|
||||
lines.push(` ${label}: ${accepted} of ${role.threshold} required${contextOnly ? `, ${contextOnly} valid only under bizinikiwi (not accepted by wallet 1.3.0)` : ''}${met ? '' : ' <- NOT MET'}`);
|
||||
}
|
||||
return { ok, lines, next: { root: next.root, keys: nextKeys } };
|
||||
}
|
||||
|
||||
await polkadotReady();
|
||||
await pezkuwiReady();
|
||||
|
||||
let failed = false;
|
||||
const first = readEnvelope(join(SIGNED, 'root.json'));
|
||||
let current = { root: first.root, keys: parseRoot(first.root) };
|
||||
console.log(`root ${current.root.version}: carried by the APK`);
|
||||
|
||||
for (let version = current.root.version + 1; existsSync(join(SIGNED, `root.${version}.json`)); version++) {
|
||||
const path = join(SIGNED, `root.${version}.json`);
|
||||
try {
|
||||
const { ok, lines, next } = checkNext(current, path);
|
||||
console.log(`root ${version}: ${ok ? 'accepted' : 'REFUSED'}`);
|
||||
lines.forEach((line) => console.log(line));
|
||||
if (!ok) {
|
||||
console.log(`::error::signed/root.${version}.json would be refused by installed wallets and stop their config refresh`);
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
current = next;
|
||||
} catch (e) {
|
||||
console.log(`::error::signed/root.${version}.json: ${e.message}`);
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const proposal of process.argv.slice(2)) {
|
||||
try {
|
||||
const { ok, lines } = checkNext(current, proposal);
|
||||
console.log(`proposal ${proposal}: ${ok ? 'ready to publish' : 'not ready'}`);
|
||||
lines.forEach((line) => console.log(line));
|
||||
} catch (e) {
|
||||
console.log(`proposal ${proposal}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
process.exit(failed ? 1 : 0);
|
||||
Reference in new issue
Block a user