lots of things that I forgot to commit 😂
This commit is contained in:
parent
59556e673b
commit
6f16cafd41
13 changed files with 395 additions and 130 deletions
|
|
@ -86,7 +86,11 @@ $ npm run nsecbunkerd start
|
||||||
|
|
||||||
## Testing with `nsecbunker-client`
|
## Testing with `nsecbunker-client`
|
||||||
|
|
||||||
|
nsecbunker ships with a simple client that can request signatures from an nsecbunkerd:
|
||||||
|
|
||||||
|
```
|
||||||
|
nsecbunker-client sign <target-npub> "hi, I'm signing from the command line with my nsecbunkerd!"
|
||||||
|
```
|
||||||
|
|
||||||
# Authors
|
# Authors
|
||||||
|
|
||||||
|
|
|
||||||
122
package-lock.json
generated
122
package-lock.json
generated
|
|
@ -1,27 +1,27 @@
|
||||||
{
|
{
|
||||||
"name": "nsecbunkerd",
|
"name": "nsecbunkerd",
|
||||||
"version": "0.6.1",
|
"version": "0.6.5",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "nsecbunkerd",
|
"name": "nsecbunkerd",
|
||||||
"version": "0.6.1",
|
"version": "0.6.5",
|
||||||
"license": "CC BY-NC-ND 4.0",
|
"license": "CC BY-NC-ND 4.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@inquirer/password": "^1.1.2",
|
"@inquirer/password": "^1.1.2",
|
||||||
"@inquirer/prompts": "^1.2.3",
|
"@inquirer/prompts": "^1.2.3",
|
||||||
"@nostr-dev-kit/ndk": "^0.6.0",
|
"@nostr-dev-kit/ndk": "^0.6.5",
|
||||||
"@prisma/client": "^4.16.1",
|
"@prisma/client": "^4.16.2",
|
||||||
"@scure/base": "^1.1.1",
|
"@scure/base": "^1.1.1",
|
||||||
"@types/yargs": "^17.0.24",
|
"@types/yargs": "^17.0.24",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.60.0",
|
|
||||||
"@typescript-eslint/parser": "^5.60.0",
|
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-import": "^2.27.5",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
|
"isomorphic-ws": "^5.0.0",
|
||||||
"websocket-polyfill": "^0.0.3",
|
"websocket-polyfill": "^0.0.3",
|
||||||
|
"ws": "^8.13.0",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/debug": "^4.1.8",
|
"@types/debug": "^4.1.8",
|
||||||
"@types/node": "^18.16.18",
|
"@types/node": "^18.16.18",
|
||||||
"prisma": "^4.16.1",
|
"prisma": "^4.16.2",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.1.3"
|
"typescript": "^5.1.3"
|
||||||
}
|
}
|
||||||
|
|
@ -961,9 +961,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@nostr-dev-kit/ndk": {
|
"node_modules/@nostr-dev-kit/ndk": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk/-/ndk-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk/-/ndk-0.6.5.tgz",
|
||||||
"integrity": "sha512-0ptE6OIZhFW+aRRIXAI8PvUIoVU6iQLpiwFtJj48XAUO2EC3WiSuqKLshjg6wj1bbo9qGs1PyFS9AUhUlWWJtg==",
|
"integrity": "sha512-D95sDEonyFJhdTM1YswPOAYKaScnOlvZcxoyt9SlXnibT+gC9AGLtwAmpziK9zPC2h5Hh2GX44BnYXUGolLjZw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/hashes": "^1.3.1",
|
"@noble/hashes": "^1.3.1",
|
||||||
"@noble/secp256k1": "^2.0.0",
|
"@noble/secp256k1": "^2.0.0",
|
||||||
|
|
@ -987,12 +987,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/client": {
|
"node_modules/@prisma/client": {
|
||||||
"version": "4.16.1",
|
"version": "4.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.16.2.tgz",
|
||||||
"integrity": "sha512-CoDHu7Bt+NuDo40ijoeHP79EHtECsPBTy3yte5Yo3op8TqXt/kV0OT5OrsWewKvQGKFMHhYQ+ePed3zzjYdGAw==",
|
"integrity": "sha512-qCoEyxv1ZrQ4bKy39GnylE8Zq31IRmm8bNhNbZx7bF2cU5aiCCnSa93J2imF88MBjn7J9eUQneNxUQVJdl/rPQ==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/engines-version": "4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c"
|
"@prisma/engines-version": "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.17"
|
"node": ">=14.17"
|
||||||
|
|
@ -1007,16 +1007,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/engines": {
|
"node_modules/@prisma/engines": {
|
||||||
"version": "4.16.1",
|
"version": "4.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.16.2.tgz",
|
||||||
"integrity": "sha512-gpZG0kGGxfemgvK/LghHdBIz+crHkZjzszja94xp4oytpsXrgt/Ice82MvPsWMleVIniKuARrowtsIsim0PFJQ==",
|
"integrity": "sha512-vx1nxVvN4QeT/cepQce68deh/Turxy5Mr+4L4zClFuK1GlxN3+ivxfuv+ej/gvidWn1cE1uAhW7ALLNlYbRUAw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"hasInstallScript": true
|
"hasInstallScript": true
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/engines-version": {
|
"node_modules/@prisma/engines-version": {
|
||||||
"version": "4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c",
|
"version": "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81.tgz",
|
||||||
"integrity": "sha512-tMWAF/qF00fbUH1HB4Yjmz6bjh7fzkb7Y3NRoUfMlHu6V+O45MGvqwYxqwBjn1BIUXkl3r04W351D4qdJjrgvA=="
|
"integrity": "sha512-q617EUWfRIDTriWADZ4YiWRZXCa/WuhNgLTVd+HqWLffjMSPzyM5uOWoauX91wvQClSKZU4pzI4JJLQ9Kl62Qg=="
|
||||||
},
|
},
|
||||||
"node_modules/@scure/base": {
|
"node_modules/@scure/base": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
|
|
@ -3159,6 +3159,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
|
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/isomorphic-ws": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"ws": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jest-diff": {
|
"node_modules/jest-diff": {
|
||||||
"version": "29.5.0",
|
"version": "29.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz",
|
||||||
|
|
@ -4006,13 +4014,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prisma": {
|
"node_modules/prisma": {
|
||||||
"version": "4.16.1",
|
"version": "4.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.16.2.tgz",
|
||||||
"integrity": "sha512-C2Xm7yxHxjFjjscBEW4tmoraPHH/Vyu/A0XABdbaFtoiOZARsxvOM7rwc2iZ0qVxbh0bGBGBWZUSXO/52/nHBQ==",
|
"integrity": "sha512-SYCsBvDf0/7XSJyf2cHTLjLeTLVXYfqp7pG5eEVafFLeT0u/hLFz/9W196nDRGUOo1JfPatAEb+uEnTQImQC1g==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/engines": "4.16.1"
|
"@prisma/engines": "4.16.2"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"prisma": "build/index.js",
|
"prisma": "build/index.js",
|
||||||
|
|
@ -4937,6 +4945,26 @@
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
|
||||||
|
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/y18n": {
|
"node_modules/y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
|
@ -5550,9 +5578,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@nostr-dev-kit/ndk": {
|
"@nostr-dev-kit/ndk": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk/-/ndk-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk/-/ndk-0.6.5.tgz",
|
||||||
"integrity": "sha512-0ptE6OIZhFW+aRRIXAI8PvUIoVU6iQLpiwFtJj48XAUO2EC3WiSuqKLshjg6wj1bbo9qGs1PyFS9AUhUlWWJtg==",
|
"integrity": "sha512-D95sDEonyFJhdTM1YswPOAYKaScnOlvZcxoyt9SlXnibT+gC9AGLtwAmpziK9zPC2h5Hh2GX44BnYXUGolLjZw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@noble/hashes": "^1.3.1",
|
"@noble/hashes": "^1.3.1",
|
||||||
"@noble/secp256k1": "^2.0.0",
|
"@noble/secp256k1": "^2.0.0",
|
||||||
|
|
@ -5576,23 +5604,23 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@prisma/client": {
|
"@prisma/client": {
|
||||||
"version": "4.16.1",
|
"version": "4.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.16.2.tgz",
|
||||||
"integrity": "sha512-CoDHu7Bt+NuDo40ijoeHP79EHtECsPBTy3yte5Yo3op8TqXt/kV0OT5OrsWewKvQGKFMHhYQ+ePed3zzjYdGAw==",
|
"integrity": "sha512-qCoEyxv1ZrQ4bKy39GnylE8Zq31IRmm8bNhNbZx7bF2cU5aiCCnSa93J2imF88MBjn7J9eUQneNxUQVJdl/rPQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@prisma/engines-version": "4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c"
|
"@prisma/engines-version": "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@prisma/engines": {
|
"@prisma/engines": {
|
||||||
"version": "4.16.1",
|
"version": "4.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.16.2.tgz",
|
||||||
"integrity": "sha512-gpZG0kGGxfemgvK/LghHdBIz+crHkZjzszja94xp4oytpsXrgt/Ice82MvPsWMleVIniKuARrowtsIsim0PFJQ==",
|
"integrity": "sha512-vx1nxVvN4QeT/cepQce68deh/Turxy5Mr+4L4zClFuK1GlxN3+ivxfuv+ej/gvidWn1cE1uAhW7ALLNlYbRUAw==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"@prisma/engines-version": {
|
"@prisma/engines-version": {
|
||||||
"version": "4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c",
|
"version": "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81.tgz",
|
||||||
"integrity": "sha512-tMWAF/qF00fbUH1HB4Yjmz6bjh7fzkb7Y3NRoUfMlHu6V+O45MGvqwYxqwBjn1BIUXkl3r04W351D4qdJjrgvA=="
|
"integrity": "sha512-q617EUWfRIDTriWADZ4YiWRZXCa/WuhNgLTVd+HqWLffjMSPzyM5uOWoauX91wvQClSKZU4pzI4JJLQ9Kl62Qg=="
|
||||||
},
|
},
|
||||||
"@scure/base": {
|
"@scure/base": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
|
|
@ -7121,6 +7149,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
|
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
|
||||||
},
|
},
|
||||||
|
"isomorphic-ws": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"jest-diff": {
|
"jest-diff": {
|
||||||
"version": "29.5.0",
|
"version": "29.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz",
|
||||||
|
|
@ -7722,12 +7756,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prisma": {
|
"prisma": {
|
||||||
"version": "4.16.1",
|
"version": "4.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.16.2.tgz",
|
||||||
"integrity": "sha512-C2Xm7yxHxjFjjscBEW4tmoraPHH/Vyu/A0XABdbaFtoiOZARsxvOM7rwc2iZ0qVxbh0bGBGBWZUSXO/52/nHBQ==",
|
"integrity": "sha512-SYCsBvDf0/7XSJyf2cHTLjLeTLVXYfqp7pG5eEVafFLeT0u/hLFz/9W196nDRGUOo1JfPatAEb+uEnTQImQC1g==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@prisma/engines": "4.16.1"
|
"@prisma/engines": "4.16.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"punycode": {
|
"punycode": {
|
||||||
|
|
@ -8369,6 +8403,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
},
|
},
|
||||||
|
"ws": {
|
||||||
|
"version": "8.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
|
||||||
|
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"y18n": {
|
"y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
|
|
||||||
10
package.json
10
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "nsecbunkerd",
|
"name": "nsecbunkerd",
|
||||||
"version": "0.6.4",
|
"version": "0.7.1",
|
||||||
"description": "nsecbunker daemon",
|
"description": "nsecbunker daemon",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -35,21 +35,23 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@inquirer/password": "^1.1.2",
|
"@inquirer/password": "^1.1.2",
|
||||||
"@inquirer/prompts": "^1.2.3",
|
"@inquirer/prompts": "^1.2.3",
|
||||||
"@nostr-dev-kit/ndk": "^0.6.5",
|
"@nostr-dev-kit/ndk": "^0.7.4",
|
||||||
"@prisma/client": "^4.16.1",
|
"@prisma/client": "^4.16.2",
|
||||||
"@scure/base": "^1.1.1",
|
"@scure/base": "^1.1.1",
|
||||||
"@types/yargs": "^17.0.24",
|
"@types/yargs": "^17.0.24",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-import": "^2.27.5",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
|
"isomorphic-ws": "^5.0.0",
|
||||||
"websocket-polyfill": "^0.0.3",
|
"websocket-polyfill": "^0.0.3",
|
||||||
|
"ws": "^8.13.0",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/debug": "^4.1.8",
|
"@types/debug": "^4.1.8",
|
||||||
"@types/node": "^18.16.18",
|
"@types/node": "^18.16.18",
|
||||||
"prisma": "^4.16.1",
|
"prisma": "^4.16.2",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.1.3"
|
"typescript": "^5.1.3"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
prisma/migrations/20230703092203_revokedat/migration.sql
Normal file
2
prisma/migrations/20230703092203_revokedat/migration.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "KeyUser" ADD COLUMN "revokedAt" DATETIME;
|
||||||
|
|
@ -13,6 +13,7 @@ model KeyUser {
|
||||||
userPubkey String
|
userPubkey String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
revokedAt DateTime?
|
||||||
lastUsedAt DateTime?
|
lastUsedAt DateTime?
|
||||||
description String?
|
description String?
|
||||||
logs Log[]
|
logs Log[]
|
||||||
|
|
|
||||||
109
src/client.ts
109
src/client.ts
|
|
@ -1,52 +1,129 @@
|
||||||
import NDK, { NDKUser, NDKEvent, NDKPrivateKeySigner, NDKNip46Signer, NostrEvent } from '@nostr-dev-kit/ndk';
|
import NDK, { NDKUser, NDKEvent, NDKPrivateKeySigner, NDKNip46Signer, NostrEvent } from '@nostr-dev-kit/ndk';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
const remotePubkey = process.argv[2];
|
const command = process.argv[2];
|
||||||
const content = process.argv[3];
|
const remotePubkey = process.argv[3];
|
||||||
|
const content = process.argv[4];
|
||||||
|
const dontPublish = process.argv.includes('--dont-publish');
|
||||||
|
const debug = process.argv.includes('--debug');
|
||||||
|
|
||||||
if (!content) {
|
if (!command) {
|
||||||
console.log('Usage: node src/client.js <remote-npub> <content>');
|
console.log('Usage: node src/client.js <command> <remote-npub> <content> [--dont-publish] [--debug] [--pk <key>]');
|
||||||
console.log('');
|
console.log('');
|
||||||
|
console.log(`\t<command>: command to run (ping, sign)`);
|
||||||
console.log(`\t<remote-npub>: npub that should be published as`);
|
console.log(`\t<remote-npub>: npub that should be published as`);
|
||||||
console.log(`\t<content>: event JSON to sign | or kind:1 content string to sign`);
|
console.log(`\t<content>: event JSON to sign (no need for pubkey or id fields) | or kind:1 content string to sign`);
|
||||||
|
console.log('\t--dont-publish: do not publish the event to the relay');
|
||||||
|
console.log('\t--debug: enable debug mode');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createNDK(): Promise<NDK> {
|
async function createNDK(): Promise<NDK> {
|
||||||
const ndk = new NDK({
|
const ndk = new NDK({
|
||||||
explicitRelayUrls: ['wss://nostr.vulpem.com', "wss://67aee52897df.ngrok.app"],
|
explicitRelayUrls: ['wss://nostr.vulpem.com', "wss://relay.nsecbunker.com"],
|
||||||
});
|
});
|
||||||
ndk.pool.on('relay:connect', () => console.log('✅ connected'));
|
if (debug) {
|
||||||
ndk.pool.on('relay:disconnect', () => console.log('❌ disconnected'));
|
ndk.pool.on('connect', () => console.log('✅ connected'));
|
||||||
|
ndk.pool.on('disconnect', () => console.log('❌ disconnected'));
|
||||||
|
}
|
||||||
await ndk.connect(5000);
|
await ndk.connect(5000);
|
||||||
|
|
||||||
return ndk;
|
return ndk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// switch (command) {
|
||||||
|
// case 'ping':
|
||||||
|
// ping(remotePubkey);
|
||||||
|
|
||||||
|
function getPrivateKeyPath() {
|
||||||
|
const home = process.env.HOME || process.env.USERPROFILE;
|
||||||
|
return `${home}/.nsecbunker-client-private.key`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function savePrivateKey(pk: string) {
|
||||||
|
const path = getPrivateKeyPath();
|
||||||
|
if (!fs.existsSync(path)) {
|
||||||
|
fs.mkdirSync(path);
|
||||||
|
}
|
||||||
|
fs.writeFileSync(`${path}/private.key`, pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPrivateKey(): string | undefined {
|
||||||
|
const path = getPrivateKeyPath();
|
||||||
|
if (!fs.existsSync(path)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return fs.readFileSync(`${path}/private.key`).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const remoteUser = new NDKUser({npub: remotePubkey});
|
const remoteUser = new NDKUser({npub: remotePubkey});
|
||||||
const ndk = await createNDK();
|
const ndk = await createNDK();
|
||||||
const localSigner = NDKPrivateKeySigner.generate();
|
|
||||||
// const localSigner = new NDKPrivateKeySigner('b8baad35c387d7cf84d52e0958d9a02aff214393a85b0703de4146c7a3697bb3');
|
const pk = loadPrivateKey();
|
||||||
|
let localSigner: NDKPrivateKeySigner;
|
||||||
|
|
||||||
|
if (pk) {
|
||||||
|
localSigner = new NDKPrivateKeySigner(pk);
|
||||||
|
} else {
|
||||||
|
localSigner = NDKPrivateKeySigner.generate();
|
||||||
|
savePrivateKey(localSigner.privateKey!);
|
||||||
|
}
|
||||||
|
|
||||||
const signer = new NDKNip46Signer(ndk, remoteUser.hexpubkey(), localSigner);
|
const signer = new NDKNip46Signer(ndk, remoteUser.hexpubkey(), localSigner);
|
||||||
console.log(`local pubkey`, (await signer.user()).npub);
|
if (debug) console.log(`local pubkey`, (await localSigner.user()).npub);
|
||||||
console.log(`remote pubkey`, remotePubkey);
|
if (debug) console.log(`remote pubkey`, remotePubkey);
|
||||||
ndk.signer = signer;
|
ndk.signer = signer;
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
if (debug) console.log(`waiting for authorization (check your nsecBunker)...`);
|
||||||
await signer.blockUntilReady();
|
await signer.blockUntilReady();
|
||||||
console.log(`authorized to sign as`, remotePubkey);
|
} catch(e) {
|
||||||
|
console.log('error:', e);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if (debug) console.log(`authorized to sign as`, remotePubkey);
|
||||||
|
|
||||||
const event = new NDKEvent(ndk, {
|
let event;
|
||||||
pubkey: remoteUser.hexpubkey(),
|
|
||||||
|
try {
|
||||||
|
const json = JSON.parse(content);
|
||||||
|
event = new NDKEvent(ndk, json);
|
||||||
|
if (!event.tags) { event.tags = []; }
|
||||||
|
if (!event.content) { event.content = ""; }
|
||||||
|
if (!event.kind) { throw "No kind on the event to sign!"; }
|
||||||
|
} catch (e) {
|
||||||
|
event = new NDKEvent(ndk, {
|
||||||
kind: 1,
|
kind: 1,
|
||||||
content,
|
content,
|
||||||
tags: [
|
tags: [
|
||||||
['client', 'nsecbunker-client']
|
['client', 'nsecbunker-client']
|
||||||
],
|
],
|
||||||
} as NostrEvent);
|
} as NostrEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
event.pubkey = remoteUser.hexpubkey();
|
||||||
|
|
||||||
|
try {
|
||||||
await event.sign();
|
await event.sign();
|
||||||
console.log('resulting event', JSON.stringify(await event.toNostrEvent()));
|
if (debug) {
|
||||||
|
console.log({
|
||||||
|
event: event.rawEvent(),
|
||||||
|
signature: event.sig,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log(event.sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dontPublish) {
|
||||||
await event.publish();
|
await event.publish();
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
|
} catch(e) {
|
||||||
|
console.log('sign error', e);
|
||||||
|
}
|
||||||
}, 2000);
|
}, 2000);
|
||||||
})();
|
})();
|
||||||
|
|
@ -18,7 +18,7 @@ interface IOpts {
|
||||||
export async function start(opts: IOpts) {
|
export async function start(opts: IOpts) {
|
||||||
const configData = await getCurrentConfig(opts.config);
|
const configData = await getCurrentConfig(opts.config);
|
||||||
|
|
||||||
if (opts.adminNpubs) {
|
if (opts.adminNpubs && opts.adminNpubs.length > 0) {
|
||||||
configData.admin.npubs = opts.adminNpubs;
|
configData.admin.npubs = opts.adminNpubs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,6 @@ async function setupSkeletonProfile(key: NDKPrivateKeySigner) {
|
||||||
['r', 'wss://relay.f7z.io'],
|
['r', 'wss://relay.f7z.io'],
|
||||||
['r', 'wss://relay.snort.social'],
|
['r', 'wss://relay.snort.social'],
|
||||||
['r', 'wss://relay.damus.io'],
|
['r', 'wss://relay.damus.io'],
|
||||||
['r', 'wss://relay.damus.io'],
|
|
||||||
],
|
],
|
||||||
pubkey: user.hexpubkey(),
|
pubkey: user.hexpubkey(),
|
||||||
} as NostrEvent);
|
} as NostrEvent);
|
||||||
|
|
|
||||||
24
src/daemon/admin/commands/revoke_user.ts
Normal file
24
src/daemon/admin/commands/revoke_user.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { NDKRpcRequest } from "@nostr-dev-kit/ndk";
|
||||||
|
import AdminInterface from "../index.js";
|
||||||
|
import prisma from "../../../db.js";
|
||||||
|
|
||||||
|
export default async function revokeUser(admin: AdminInterface, req: NDKRpcRequest) {
|
||||||
|
const [ keyUserId ] = req.params as [ string ];
|
||||||
|
|
||||||
|
if (!keyUserId) throw new Error("Invalid params");
|
||||||
|
|
||||||
|
const keyUserIdInt = parseInt(keyUserId);
|
||||||
|
if (isNaN(keyUserIdInt)) throw new Error("Invalid params");
|
||||||
|
|
||||||
|
await prisma.keyUser.update({
|
||||||
|
where: {
|
||||||
|
id: keyUserIdInt,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
revokedAt: new Date(),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = JSON.stringify(["ok"]);
|
||||||
|
return admin.rpc.sendResponse(req.id, req.pubkey, result, 24134);
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import NDK, { NDKPrivateKeySigner, NDKRpcRequest, NDKRpcResponse, NDKUser } from '@nostr-dev-kit/ndk';
|
import NDK, { NDKPrivateKeySigner, NDKRpcRequest, NDKRpcResponse, NDKUser, NostrEvent } from '@nostr-dev-kit/ndk';
|
||||||
import { NDKNostrRpc } from '@nostr-dev-kit/ndk';
|
import { NDKNostrRpc } from '@nostr-dev-kit/ndk';
|
||||||
import { debug } from 'debug';
|
import { debug } from 'debug';
|
||||||
import { Key, KeyUser } from '../run';
|
import { Key, KeyUser } from '../run';
|
||||||
|
|
@ -8,7 +8,10 @@ import createNewKey from './commands/create_new_key';
|
||||||
import createNewPolicy from './commands/create_new_policy';
|
import createNewPolicy from './commands/create_new_policy';
|
||||||
import createNewToken from './commands/create_new_token';
|
import createNewToken from './commands/create_new_token';
|
||||||
import unlockKey from './commands/unlock_key';
|
import unlockKey from './commands/unlock_key';
|
||||||
|
import revokeUser from './commands/revoke_user';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
import { validateRequestFromAdmin } from './validations/request-from-admin';
|
||||||
|
import { dmUser } from '../../utils/dm-user';
|
||||||
|
|
||||||
export type IAdminOpts = {
|
export type IAdminOpts = {
|
||||||
npubs: string[];
|
npubs: string[];
|
||||||
|
|
@ -43,7 +46,7 @@ class AdminInterface {
|
||||||
let connectionString = `bunker://${user.npub}`;
|
let connectionString = `bunker://${user.npub}`;
|
||||||
|
|
||||||
if (opts.adminRelays.length > 0) {
|
if (opts.adminRelays.length > 0) {
|
||||||
connectionString += `@${opts.adminRelays.join(',').replace(/wss:\/\//g, '')}`;
|
connectionString += '@' + encodeURIComponent(`${opts.adminRelays.join(',').replace(/wss:\/\//g, '')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`\n\nnsecBunker connection string:\n\n${connectionString}\n\n`);
|
console.log(`\n\nnsecBunker connection string:\n\n${connectionString}\n\n`);
|
||||||
|
|
@ -54,11 +57,25 @@ class AdminInterface {
|
||||||
this.signerUser = user;
|
this.signerUser = user;
|
||||||
|
|
||||||
this.connect();
|
this.connect();
|
||||||
|
|
||||||
|
this.notifyAdminsOfNewConnection(connectionString);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.rpc = new NDKNostrRpc(this.ndk, this.ndk.signer!, debug("ndk:rpc"));
|
this.rpc = new NDKNostrRpc(this.ndk, this.ndk.signer!, debug("ndk:rpc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async notifyAdminsOfNewConnection(connectionString: string) {
|
||||||
|
const blastrNdk = new NDK({
|
||||||
|
explicitRelayUrls: ['wss://blastr.f7z.xyz', 'wss://nostr.mutinywallet.com'],
|
||||||
|
signer: this.ndk.signer
|
||||||
|
});
|
||||||
|
await blastrNdk.connect(2500);
|
||||||
|
|
||||||
|
for (const npub of this.npubs) {
|
||||||
|
dmUser(blastrNdk, npub, `nsecBunker has started; use ${connectionString} to connect to it and unlock your key(s)`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the npub of the admin interface.
|
* Get the npub of the admin interface.
|
||||||
*/
|
*/
|
||||||
|
|
@ -75,10 +92,10 @@ class AdminInterface {
|
||||||
this.ndk.pool.on('relay:connect', () => console.log('✅ nsecBunker Admin Interface ready'));
|
this.ndk.pool.on('relay:connect', () => console.log('✅ nsecBunker Admin Interface ready'));
|
||||||
this.ndk.pool.on('relay:disconnect', () => console.log('❌ admin disconnected'));
|
this.ndk.pool.on('relay:disconnect', () => console.log('❌ admin disconnected'));
|
||||||
this.ndk.connect(2500).then(() => {
|
this.ndk.connect(2500).then(() => {
|
||||||
|
// connect for whitelisted admins
|
||||||
this.rpc.subscribe({
|
this.rpc.subscribe({
|
||||||
"kinds": [24134 as number], // 24134
|
"kinds": [24134 as number], // 24134
|
||||||
"#p": [this.signerUser!.hexpubkey()],
|
"#p": [this.signerUser!.hexpubkey()],
|
||||||
"authors": this.npubs.map((npub) => (new NDKUser({npub}).hexpubkey())),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.rpc.on('request', (req) => this.handleRequest(req));
|
this.rpc.on('request', (req) => this.handleRequest(req));
|
||||||
|
|
@ -89,30 +106,38 @@ class AdminInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleRequest(req: NDKRpcRequest) {
|
private async handleRequest(req: NDKRpcRequest) {
|
||||||
// await this.validateRequest(req);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
await this.validateRequest(req);
|
||||||
|
|
||||||
switch (req.method) {
|
switch (req.method) {
|
||||||
case 'get_keys': this.reqGetKeys(req); break;
|
case 'get_keys': await this.reqGetKeys(req); break;
|
||||||
case 'get_key_users': this.reqGetKeyUsers(req); break;
|
case 'get_key_users': await this.reqGetKeyUsers(req); break;
|
||||||
case 'get_key_tokens': this.reqGetKeyTokens(req); break;
|
case 'get_key_tokens': await this.reqGetKeyTokens(req); break;
|
||||||
case 'create_new_key': createNewKey(this, req); break;
|
case 'revoke_user': await revokeUser(this, req); break;
|
||||||
case 'unlock_key': unlockKey(this, req); break;
|
case 'create_new_key': await createNewKey(this, req); break;
|
||||||
case 'create_new_policy': createNewPolicy(this, req); break;
|
case 'unlock_key': await unlockKey(this, req); break;
|
||||||
case 'get_policies': this.reqListPolicies(req); break;
|
case 'create_new_policy': await createNewPolicy(this, req); break;
|
||||||
|
case 'get_policies': await this.reqListPolicies(req); break;
|
||||||
case 'create_new_token': createNewToken(this, req); break;
|
case 'create_new_token': await createNewToken(this, req); break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.log(`Unknown method ${req.method}`);
|
console.log(`Unknown method ${req.method}`);
|
||||||
|
return this.rpc.sendResponse(
|
||||||
|
req.id,
|
||||||
|
req.pubkey,
|
||||||
|
JSON.stringify(['error', `Unknown method ${req.method}`]),
|
||||||
|
24134
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error(`Error handling request ${req.method}: ${err.message}`, req.params);
|
console.error(`Error handling request ${req.method}: ${err.message}`, req.params);
|
||||||
|
return this.rpc.sendResponse(req.id, req.pubkey, JSON.stringify(['error', err?.message]), 24134);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async validateRequest(req: NDKRpcRequest) {
|
private async validateRequest(req: NDKRpcRequest): Promise<void> {
|
||||||
// TODO validate pubkey, validate signature
|
if (!await validateRequestFromAdmin(req, this.npubs)) {
|
||||||
|
throw new Error('You are not designated to administrate this bunker');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -220,13 +245,15 @@ class AdminInterface {
|
||||||
/**
|
/**
|
||||||
* This function is called when a request is received from a remote user that needs
|
* This function is called when a request is received from a remote user that needs
|
||||||
* to be approved by the admin interface.
|
* to be approved by the admin interface.
|
||||||
|
*
|
||||||
|
* @returns true if the request is approved, false if it is denied, undefined if it timedout
|
||||||
*/
|
*/
|
||||||
public async requestPermission(
|
public async requestPermission(
|
||||||
keyName: string,
|
keyName: string,
|
||||||
remotePubkey: string,
|
remotePubkey: string,
|
||||||
method: string,
|
method: string,
|
||||||
param: any
|
param: any
|
||||||
): Promise<boolean> {
|
): Promise<boolean | undefined> {
|
||||||
const keyUser = await prisma.keyUser.findUnique({
|
const keyUser = await prisma.keyUser.findUnique({
|
||||||
where: {
|
where: {
|
||||||
unique_key_user: {
|
unique_key_user: {
|
||||||
|
|
@ -254,21 +281,52 @@ class AdminInterface {
|
||||||
console.log(`param`, param);
|
console.log(`param`, param);
|
||||||
console.log(`keyUser`, keyUser);
|
console.log(`keyUser`, keyUser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If an admin doesn't respond within 10 seconds, report back to the user that the request timed out
|
||||||
|
*/
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(undefined);
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
for (const npub of this.npubs) {
|
for (const npub of this.npubs) {
|
||||||
const remoteUser = new NDKUser({npub});
|
const remoteUser = new NDKUser({npub});
|
||||||
console.log(`sending request to ${npub}`, remoteUser.hexpubkey());
|
console.log(`sending request to ${npub}`, remoteUser.hexpubkey());
|
||||||
this.rpc.sendRequest(
|
const params = JSON.stringify({
|
||||||
remoteUser.hexpubkey(),
|
|
||||||
'acl',
|
|
||||||
[JSON.stringify({
|
|
||||||
keyName,
|
keyName,
|
||||||
remotePubkey,
|
remotePubkey,
|
||||||
method,
|
method,
|
||||||
param,
|
param,
|
||||||
description: keyUser?.description,
|
description: keyUser?.description,
|
||||||
})],
|
});
|
||||||
24134, // 24134
|
|
||||||
|
this.rpc.sendRequest(
|
||||||
|
remoteUser.hexpubkey(),
|
||||||
|
'acl',
|
||||||
|
[params],
|
||||||
|
24134,
|
||||||
(res: NDKRpcResponse) => {
|
(res: NDKRpcResponse) => {
|
||||||
|
this.requestPermissionResponse(
|
||||||
|
remotePubkey,
|
||||||
|
keyName,
|
||||||
|
method,
|
||||||
|
param,
|
||||||
|
resolve,
|
||||||
|
res
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async requestPermissionResponse(
|
||||||
|
remotePubkey: string,
|
||||||
|
keyName: string,
|
||||||
|
method: string,
|
||||||
|
param: string,
|
||||||
|
resolve: (value: boolean) => void,
|
||||||
|
res: NDKRpcResponse
|
||||||
|
) {
|
||||||
let resObj;
|
let resObj;
|
||||||
try {
|
try {
|
||||||
resObj = JSON.parse(res.result);
|
resObj = JSON.parse(res.result);
|
||||||
|
|
@ -277,8 +335,6 @@ class AdminInterface {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('request result', resObj);
|
|
||||||
|
|
||||||
switch (resObj[0]) {
|
switch (resObj[0]) {
|
||||||
case 'always': {
|
case 'always': {
|
||||||
allowAllRequestsFromKey(
|
allowAllRequestsFromKey(
|
||||||
|
|
@ -288,19 +344,18 @@ class AdminInterface {
|
||||||
param,
|
param,
|
||||||
resObj[1],
|
resObj[1],
|
||||||
resObj[2]
|
resObj[2]
|
||||||
).then(() => {
|
);
|
||||||
resolve(true);
|
resolve(true);
|
||||||
});
|
break;
|
||||||
|
}
|
||||||
|
case 'never': {
|
||||||
|
console.log('not implemented');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
console.log('request result', res.result);
|
console.log('request result', res.result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AdminInterface;
|
export default AdminInterface;
|
||||||
18
src/daemon/admin/validations/request-from-admin.ts
Normal file
18
src/daemon/admin/validations/request-from-admin.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { NDKRpcRequest } from "@nostr-dev-kit/ndk";
|
||||||
|
import { nip19 } from "nostr-tools";
|
||||||
|
|
||||||
|
export async function validateRequestFromAdmin(
|
||||||
|
req: NDKRpcRequest,
|
||||||
|
npubs: string[],
|
||||||
|
): Promise<boolean> {
|
||||||
|
const hexpubkey = req.pubkey;
|
||||||
|
|
||||||
|
if (!hexpubkey) {
|
||||||
|
console.log('missing pubkey');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hexpubkeys = npubs.map((npub) => nip19.decode(npub).data as string);
|
||||||
|
|
||||||
|
return hexpubkeys.includes(hexpubkey);
|
||||||
|
}
|
||||||
|
|
@ -70,11 +70,13 @@ function getKeyUsers(config: IConfig) {
|
||||||
|
|
||||||
for (const user of users) {
|
for (const user of users) {
|
||||||
const keyUser = {
|
const keyUser = {
|
||||||
|
id: user.id,
|
||||||
name: user.keyName,
|
name: user.keyName,
|
||||||
pubkey: user.userPubkey,
|
pubkey: user.userPubkey,
|
||||||
description: user.description || undefined,
|
description: user.description || undefined,
|
||||||
createdAt: user.createdAt,
|
createdAt: user.createdAt,
|
||||||
lastUsedAt: user.lastUsedAt || undefined,
|
lastUsedAt: user.lastUsedAt || undefined,
|
||||||
|
revokedAt: user.revokedAt || undefined,
|
||||||
signingConditions: user.signingConditions, // Include signing conditions
|
signingConditions: user.signingConditions, // Include signing conditions
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -152,7 +154,13 @@ function callbackForKeyAdminInterface(keyName: string, adminInterface: AdminInte
|
||||||
return keyAllowed;
|
return keyAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return adminInterface.requestPermission(keyName, remotePubkey, method, param);
|
const requestedPerm = await adminInterface.requestPermission(keyName, remotePubkey, method, param);
|
||||||
|
|
||||||
|
if (requestedPerm === undefined) {
|
||||||
|
throw new Error('adminInterface.requestPermission returned undefined');
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestedPerm;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log('callbackForKey error:', e);
|
console.log('callbackForKey error:', e);
|
||||||
}
|
}
|
||||||
|
|
@ -205,8 +213,24 @@ class Daemon {
|
||||||
this.ndk = new NDK({
|
this.ndk = new NDK({
|
||||||
explicitRelayUrls: config.nostr.relays,
|
explicitRelayUrls: config.nostr.relays,
|
||||||
});
|
});
|
||||||
this.ndk.pool.on('connect', (r) => { console.log(`✅ Connected to ${r.url}`); });
|
this.ndk.pool.on('relay:connect', (r) => {
|
||||||
|
if (r) {
|
||||||
|
console.log(`✅ Connected to ${r.url}`);
|
||||||
|
} else {
|
||||||
|
console.log('✅ Connected to relays', this.ndk.pool.urls);
|
||||||
|
}
|
||||||
|
});
|
||||||
this.ndk.pool.on('notice', (n, r) => { console.log(`👀 Notice from ${r.url}`, n); });
|
this.ndk.pool.on('notice', (n, r) => { console.log(`👀 Notice from ${r.url}`, n); });
|
||||||
|
|
||||||
|
this.ndk.pool.on('relay:disconnect', (r) => {
|
||||||
|
console.log(`🚫 Disconnected from ${r.url}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
const stats = this.ndk.pool.stats();
|
||||||
|
|
||||||
|
console.log(`📡 ${stats.connected} connected, ${stats.disconnected} disconnected, ${stats.connecting} connecting`);
|
||||||
|
}, 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
|
|
|
||||||
19
src/utils/dm-user.ts
Normal file
19
src/utils/dm-user.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import NDK, { NDKUser, NDKEvent, NostrEvent } from "@nostr-dev-kit/ndk";
|
||||||
|
|
||||||
|
export async function dmUser(ndk: NDK, recipient: NDKUser | string, content: string): Promise<NDKEvent> {
|
||||||
|
let targetUser;
|
||||||
|
|
||||||
|
if (typeof recipient === 'string') {
|
||||||
|
targetUser = new NDKUser({ npub: recipient });
|
||||||
|
} else if (recipient instanceof NDKUser) {
|
||||||
|
targetUser = recipient;
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = new NDKEvent(ndk, { kind: 4, content } as NostrEvent);
|
||||||
|
event.tag(targetUser);
|
||||||
|
await event.encrypt(targetUser);
|
||||||
|
await event.sign();
|
||||||
|
await event.publish();
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue