From 02a3475a73ab21026d85564e1c0b07e47a5bd8ba Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Sun, 15 Oct 2023 12:44:52 -0500 Subject: [PATCH] feature(eth): db schema and api endpoints for ethereum groups/addresses --- package-lock.json | 324 +++++++++++++++++++++++++++++++++++++++++ package.json | 3 +- prisma/schema.prisma | 49 +++++-- src/endpoints/index.ts | 277 ++++++++++++++++++++++++++++------- src/types/index.ts | 2 +- 5 files changed, 586 insertions(+), 69 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3b361a7..d9dfce4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "discreetly-claimcodes": "^1.1.5", "discreetly-interfaces": "^0.1.39", "dotenv": "^16.3.1", + "ethereumjs-util": "^7.1.5", "express": "^4.18.2", "express-basic-auth": "^1.2.1", "ffjavascript": "^0.2.60", @@ -2079,6 +2080,14 @@ "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.3.tgz", "integrity": "sha512-XTnH9E/rp51aKGsiMtQCHV/owDLW2E9QAxI7ItpWWm6Gi6XO1e4o3VuEYDma0lbitj1vNOBj05Qk8l2BYoiN4A==" }, + "node_modules/@types/bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-dkpZu0szUtn9UXTmw+e0AJFd4D2XAxDnsCLdc05SfqpqzPEBft8eQr8uaFitfo/dUUOZERaLec2hHMG87A4Dxg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -2213,6 +2222,14 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==" }, + "node_modules/@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -2231,6 +2248,14 @@ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "dev": true }, + "node_modules/@types/secp256k1": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.4.tgz", + "integrity": "sha512-oN0PFsYxDZnX/qSJ5S5OwaEDTYfekhvaM5vqui2bu1AA39pKofmgL104Q29KiOXizXS2yLjSzc5YdTyMKdcy4A==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/semver": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", @@ -2943,6 +2968,14 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -3084,6 +3117,24 @@ "node": ">=8" } }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/browserslist": { "version": "4.21.10", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", @@ -3128,6 +3179,24 @@ "node": ">= 6" } }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, "node_modules/bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -3151,6 +3220,11 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + }, "node_modules/builtin-modules": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", @@ -3311,6 +3385,15 @@ "node": ">=8" } }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/circom_runtime": { "version": "0.1.22", "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.22.tgz", @@ -3516,6 +3599,31 @@ "node": ">= 0.10" } }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -3750,6 +3858,25 @@ "integrity": "sha512-IXTgg+bITkQv/FLP9FjX6f9KFCs5hQWeh5uNSKxB9mqYj/JXhHDbu+ekS43LVvbkL3eW6/oZy4+r9Om6lan1Uw==", "dev": true }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", @@ -4131,6 +4258,43 @@ "node": ">= 0.6" } }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/ethers": { "version": "6.6.2", "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.6.2.tgz", @@ -4188,6 +4352,15 @@ } } }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -4888,6 +5061,19 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -4914,6 +5100,16 @@ "node": ">=8" } }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -6065,6 +6261,25 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/keccak/node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -6197,6 +6412,16 @@ "tmpl": "1.0.5" } }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -6296,6 +6521,11 @@ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -6471,6 +6701,16 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/node-gyp-build": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -6781,6 +7021,21 @@ "node": ">=8" } }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -6998,6 +7253,14 @@ "wasmbuilder": "0.0.16" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -7164,6 +7427,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, "node_modules/rlnjs": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/rlnjs/-/rlnjs-3.2.0.tgz", @@ -7216,6 +7488,17 @@ "blakejs": "^1.1.0" } }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, "node_modules/rollup": { "version": "3.26.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.2.tgz", @@ -7365,6 +7648,30 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/secp256k1/node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -7426,11 +7733,28 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", diff --git a/package.json b/package.json index 93e8f48..14eba42 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "discreetly-claimcodes": "^1.1.5", "discreetly-interfaces": "^0.1.39", "dotenv": "^16.3.1", + "ethereumjs-util": "^7.1.5", "express": "^4.18.2", "express-basic-auth": "^1.2.1", "ffjavascript": "^0.2.60", @@ -70,4 +71,4 @@ "ts-node": "^10.9.1", "typescript": "^5.1.6" } -} \ No newline at end of file +} diff --git a/prisma/schema.prisma b/prisma/schema.prisma index edada38..109230a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -33,31 +33,48 @@ model Rooms { encrypted String @default("PLAINTEXT") gatewayIds String[] @default([]) @db.ObjectId gateways GateWayIdentity[] @relation(fields: [gatewayIds], references: [id]) + EthereumGroup EthereumGroup[] @relation(fields: [ethereumGroupIds], references: [id]) + ethereumGroupIds String[] @db.ObjectId } model GateWayIdentity { - id String @id @default(auto()) @map("_id") @db.ObjectId - semaphoreIdentity String @unique + id String @id @default(auto()) @map("_id") @db.ObjectId + semaphoreIdentity String @unique discordId String? jubmojii String[] steamId64 String? - ethereumAddresses String[] + roomIds String[] @default([]) @db.ObjectId + rooms Rooms[] @relation(fields: [roomIds], references: [id]) + usedClaimCodes String[] @default([]) @db.ObjectId + claimCodes ClaimCodes[] @relation(fields: [usedClaimCodes], references: [id]) + ethereumAddress EthereumAddress[] +} + +model EthereumGroup { + id String @id @default(auto()) @map("_id") @db.ObjectId + name String @unique roomIds String[] @default([]) @db.ObjectId rooms Rooms[] @relation(fields: [roomIds], references: [id]) - usedClaimCodes String[] @default([]) @db.ObjectId - claimCodes ClaimCodes[] @relation(fields: [usedClaimCodes], references: [id]) + ethereumAddresses String[] @default([]) +} + +model EthereumAddress { + id String @id @default(auto()) @map("_id") @db.ObjectId + ethereumAddress String @unique + gateways GateWayIdentity @relation(fields: [gatewayId], references: [id]) + gatewayId String @db.ObjectId } model ClaimCodes { - id String @id @default(auto()) @map("_id") @db.ObjectId - claimcode String @unique - roomIds String[] @default([]) @db.ObjectId - expiresAt Int @default(0) - usesLeft Int @default(-1) - rooms Rooms[] @relation(fields: [roomIds], references: [id]) - discordId String? - gatewayIds String[] @default([]) @db.ObjectId - gateways GateWayIdentity[] @relation(fields: [gatewayIds], references: [id]) + id String @id @default(auto()) @map("_id") @db.ObjectId + claimcode String @unique + roomIds String[] @default([]) @db.ObjectId + expiresAt Int @default(0) + usesLeft Int @default(-1) + rooms Rooms[] @relation(fields: [roomIds], references: [id]) + discordId String? + gatewayIds String[] @default([]) @db.ObjectId + gateways GateWayIdentity[] @relation(fields: [gatewayIds], references: [id]) } model Messages { @@ -81,8 +98,8 @@ model Epoch { } model Discord { - id String @id @default(auto()) @map("_id") @db.ObjectId - discordServerId String @unique + id String @id @default(auto()) @map("_id") @db.ObjectId + discordServerId String @unique roomsMapping DiscordRoleRoomMapping[] } diff --git a/src/endpoints/index.ts b/src/endpoints/index.ts index 7a78678..e3c964d 100644 --- a/src/endpoints/index.ts +++ b/src/endpoints/index.ts @@ -1,7 +1,7 @@ import type { Express, RequestHandler, Request, Response } from 'express'; import { PrismaClient } from '@prisma/client'; import { serverConfig } from '../config/serverConfig'; -import { genClaimCodeArray, pp } from '../utils'; +import { genClaimCodeArray, genMockUsers, pp } from '../utils'; import { findRoomById, findRoomsByIdentity, @@ -16,6 +16,15 @@ import { } from '../data/db/'; import { MessageI, RoomI } from 'discreetly-interfaces'; import { RLNFullProof } from 'rlnjs'; +import { + ecrecover, + pubToAddress, + bufferToHex, + fromRpcSig, + toBuffer, + hashPersonalMessage +} from 'ethereumjs-util'; + // import expressBasicAuth from 'express-basic-auth'; const prisma = new PrismaClient(); @@ -82,7 +91,6 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { if (membershipType === 'BANDADA_GROUP') { roomResult.bandadaAddress = bandadaAddress; roomResult.bandadaGroupId = bandadaGroupId; - } if (membershipType === 'IDENTITY_LIST') { roomResult.identities = identities; @@ -166,7 +174,11 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { return; } const roomIds = foundCode.roomIds; - const addedRooms = await updateRoomIdentities(idc, roomIds, foundCode.discordId!); + const addedRooms = await updateRoomIdentities( + idc, + roomIds, + foundCode.discordId! + ); const updatedRooms = await findUpdatedRooms(addedRooms as string[]); // Return the room ids of the updated rooms @@ -261,7 +273,7 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { bandadaGroupId, bandadaAPIKey, membershipType, - roomId, + roomId ) .then((result) => { const response = @@ -416,14 +428,15 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { ['/addcode', '/api/addcode'], adminAuth, asyncHandler(async (req: Request, res: Response) => { - const { numCodes, rooms, all, expiresAt, usesLeft, discordId } = req.body as { - numCodes: number; - rooms: string[]; - all: boolean; - expiresAt: number; - usesLeft: number; - discordId: string; - }; + const { numCodes, rooms, all, expiresAt, usesLeft, discordId } = + req.body as { + numCodes: number; + rooms: string[]; + all: boolean; + expiresAt: number; + usesLeft: number; + discordId: string; + }; const currentDate = new Date(); const threeMonthsLater = new Date(currentDate).setMonth( @@ -642,6 +655,147 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { }) ); + app.get(['/eth/groups/all', '/api/eth/groups/all'], adminAuth, (req, res) => { + prisma.ethereumGroup + .findMany({ + select: { + name: true + } + }) + .then((groups) => { + res.status(200).json(groups); + }) + .catch((err) => { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + }); + }); + + app.get(['/eth/group/:address', '/api/eth/group/:address'], (req, res) => { + const { address } = req.params as { address: string }; + prisma.ethereumGroup + .findMany({ + where: { + ethereumAddresses: { + has: address + } + }, + select: { + name: true + } + }) + .then((groups) => { + res.status(200).json(groups); + }) + .catch((err) => { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + }); + }); + + app.post( + ['/eth/group/create', '/api/eth/group/create'], + adminAuth, + asyncHandler(async (req: Request, res: Response) => { + const { name, roomIds } = req.body as { + name: string; + roomIds: string[]; + }; + const ethereumGroup = await prisma.ethereumGroup.create({ + data: { + name: name, + rooms: { + connect: roomIds.map((roomId) => ({ roomId })) + } + } + }); + res.json({ success: true, ethereumGroup }); + }) + ); + + app.post( + ['/eth/group/add', '/api/eth/group/add'], + adminAuth, + asyncHandler(async (req: Request, res: Response) => { + const { names, ethAddresses } = req.body as { + names: string[]; + ethAddresses: string[]; + }; + if (!names) return; + const groups = await prisma.ethereumGroup.updateMany({ + where: { + name: { + in: names + } + }, + data: { + ethereumAddresses: { + push: ethAddresses + } + } + }) + res.json({ success: true, groups }); + })); + + app.post( + ['/eth/group/edit', '/api/eth/group/edit'], + adminAuth, + (req, res) => { + const { name, ethAddresses, roomIds } = req.body as { + name: string; + ethAddresses: string[]; + roomIds: []; + }; + } + ); + + app.post( + ['/eth/group/delete', '/api/eth/group/delete'], + adminAuth, + (req, res) => { + const { name } = req.body as { name: string }; + prisma.ethereumGroup + .delete({ + where: { + name: name + } + }) + .then((group) => { + res.status(200).json(group); + }) + .catch((err) => { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + }); + } + ); + + app.post( + ['/eth/message/sign', '/api/eth/message/sign'], + adminAuth, + asyncHandler(async (req: Request, res: Response) => { + const { message, signature } = req.body as { + message: string; + signature: string; + }; + + try { + const msgHex = bufferToHex(Buffer.from(message)); + const msgBuffer = toBuffer(msgHex); + const msgHash = hashPersonalMessage(msgBuffer); + + const { v, r, s } = fromRpcSig(signature); + const publicKey = ecrecover(msgHash, v, r, s); + const address = pubToAddress(publicKey); + + const recoveredAddress = bufferToHex(address); + } catch (err) { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + } + }) + ); + /*---------------------DISCORD BOT APIS ---------------------*/ /** @@ -734,55 +888,71 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { * @returns {string[]} - An array of room ids * */ - app.post('/api/discord/getrooms', adminAuth, asyncHandler(async (req: Request, res: Response) => { - const { roles, discordId } = req.body as { roles: string[], discordId: string }; - if (roles.length === 0 || !discordId) { - res.status(400).json({ error: 'Bad Request' }); - return; - } - const rooms = await prisma.gateWayIdentity.findFirst({ - where: { - discordId: discordId - }, - include: { - rooms: true + app.post( + '/api/discord/getrooms', + adminAuth, + asyncHandler(async (req: Request, res: Response) => { + const { roles, discordId } = req.body as { + roles: string[]; + discordId: string; + }; + if (roles.length === 0 || !discordId) { + res.status(400).json({ error: 'Bad Request' }); + return; } - }) + const rooms = await prisma.gateWayIdentity.findFirst({ + where: { + discordId: discordId + }, + include: { + rooms: true + } + }); if (rooms) { const roomIds = rooms.rooms.map((room) => room.roomId); const filteredRooms: string[] = []; const filteredNames: string[] = []; for (const role of roles) { - const discordRoleRoomMapping = await prisma.discordRoleRoomMapping.findMany({ - where: { - roles: { - has: role + const discordRoleRoomMapping = + await prisma.discordRoleRoomMapping.findMany({ + where: { + roles: { + has: role + } } - } - }); - const mappingRoomIds = discordRoleRoomMapping.map((mapping) => mapping.roomId); - const newRooms = mappingRoomIds.filter((roomId) => roomIds.includes(roomId)); + }); + const mappingRoomIds = discordRoleRoomMapping.map( + (mapping) => mapping.roomId + ); + const newRooms = mappingRoomIds.filter((roomId) => + roomIds.includes(roomId) + ); const newRoomNames = newRooms.map((roomId) => { const room = rooms.rooms.find((room) => room.roomId === roomId); return room?.name; - }) + }); filteredRooms.push(...newRooms); - filteredNames.push(...newRoomNames as string[]); + filteredNames.push(...(newRoomNames as string[])); } - console.log(filteredRooms) - res.status(200).json({ rooms: filteredRooms, roomNames: filteredNames }); + console.log(filteredRooms); + res + .status(200) + .json({ rooms: filteredRooms, roomNames: filteredNames }); } else { const roomIds: string[] = []; for (const role of roles) { - const discordRoleRoomMapping = await prisma.discordRoleRoomMapping.findMany({ - where: { - roles: { - has: role + const discordRoleRoomMapping = + await prisma.discordRoleRoomMapping.findMany({ + where: { + roles: { + has: role + } } - } - }); - const mappingRoomIds = discordRoleRoomMapping.map((mapping) => mapping.roomId); + }); + const mappingRoomIds = discordRoleRoomMapping.map( + (mapping) => mapping.roomId + ); roomIds.push(...mappingRoomIds); } const roomNames = await prisma.rooms.findMany({ @@ -795,9 +965,13 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { name: true } }); - res.status(200).json({ rooms: roomIds, roomNames: roomNames.map((room) => room.name)}); + res.status(200).json({ + rooms: roomIds, + roomNames: roomNames.map((room) => room.name) + }); } - })); + }) + ); /** * This endpoint takes a discord user id and returns all rooms that the user is a part of. @@ -814,16 +988,17 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { discordId: discordUserId }, include: { - rooms: true, - } - }) + rooms: true + } + }) .then((identity) => { res.status(200).json(identity); - }).catch((err) => { + }) + .catch((err) => { console.error(err); res.status(500).json({ error: 'Internal Server Error' }); }); - }); + }); /** * This endpoint gets all the rooms that a user is allowed to access based on their discordId. * @params {string} discordId - The id of the discord user to get rooms for diff --git a/src/types/index.ts b/src/types/index.ts index 51b1b7d..b172142 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -21,7 +21,7 @@ export interface ClaimCodeI { } export interface GateWayIdentityI { - semaphoreIdentity: string; + semaphoreIdentity: string | null; roomIds: string[]; usedClaimCodes: string[]; }