mirror of
https://github.com/PretendoNetwork/account.git
synced 2026-09-30 06:12:26 -05:00
Added gRPC service for the API (for future use)
This commit is contained in:
3
SETUP.md
3
SETUP.md
@@ -75,6 +75,7 @@ Configurations are loaded through environment variables. `.env` files are suppor
|
||||
| `PN_ACT_CONFIG_CDN_BASE_URL` | URL for serving CDN contents (usually the same as s3 endpoint) | No |
|
||||
| `PN_ACT_CONFIG_WEBSITE_BASE` | Website URL | Yes |
|
||||
| `PN_ACT_CONFIG_AES_KEY` | AES-256 key used for encrypting tokens | No |
|
||||
| `PN_ACT_CONFIG_GRPC_API_KEY` | gRPC API key that other clients use to interact with this server | No |
|
||||
| `PN_ACT_CONFIG_GRPC_MASTER_API_KEY_ACCOUNT` | Master API key to interact with the account gRPC service | No |
|
||||
| `PN_ACT_CONFIG_GRPC_MASTER_API_KEY_API` | Master API key to interact with the API gRPC service | No |
|
||||
| `PN_ACT_CONFIG_GRPC_PORT` | gRPC server port | No |
|
||||
| `PN_ACT_CONFIG_STRIPE_SECRET_KEY` | Stripe API key. Used to cancel subscriptions when scrubbing PNIDs | Yes |
|
||||
321
package-lock.json
generated
321
package-lock.json
generated
@@ -92,23 +92,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/regexpp": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz",
|
||||
"integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==",
|
||||
"version": "4.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz",
|
||||
"integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz",
|
||||
"integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz",
|
||||
"integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
"espree": "^9.5.1",
|
||||
"espree": "^9.5.2",
|
||||
"globals": "^13.19.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
@@ -124,9 +124,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "8.39.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz",
|
||||
"integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==",
|
||||
"version": "8.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz",
|
||||
"integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -145,15 +145,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@grpc/proto-loader": {
|
||||
"version": "0.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.6.tgz",
|
||||
"integrity": "sha512-QyAXR8Hyh7uMDmveWxDSUcJr9NAWaZ2I6IXgAYvQmfflwouTM+rArE2eEaCtLlRqO81j7pRLCt81IefUei6Zbw==",
|
||||
"version": "0.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.7.tgz",
|
||||
"integrity": "sha512-1TIeXOi8TuSCQprPItwoMymZXxWT0CPxUhkrkeCUH+D8U7QDwQ6b7SUz2MaLuWM2llT+J/TVFLmQI5KtML3BhQ==",
|
||||
"dependencies": {
|
||||
"@types/long": "^4.0.1",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"long": "^4.0.0",
|
||||
"protobufjs": "^7.0.0",
|
||||
"yargs": "^16.2.0"
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
"proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
|
||||
@@ -686,9 +686,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
|
||||
"integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
|
||||
"version": "18.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.7.tgz",
|
||||
"integrity": "sha512-MFg7ua/bRtnA1hYE3pVyWxGd/r7aMqjNOdHvlSsXV3n8iaeGKkOaPzpJh6/ovf4bEXWcojkeMJpTsq3mzXW4IQ=="
|
||||
},
|
||||
"node_modules/@types/node-rsa": {
|
||||
"version": "1.1.1",
|
||||
@@ -729,9 +729,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
||||
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz",
|
||||
"integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/send": {
|
||||
@@ -755,9 +755,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/validator": {
|
||||
"version": "13.7.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.15.tgz",
|
||||
"integrity": "sha512-yeinDVQunb03AEP8luErFcyf/7Lf7AzKCD0NXfgVoGCCQDNpZET8Jgq74oBgqKld3hafLbfzt/3inUdQvaFeXQ==",
|
||||
"version": "13.7.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.17.tgz",
|
||||
"integrity": "sha512-aqayTNmeWrZcvnG2MG9eGYI6b7S5fl+yKgPs6bAjOTwPS316R5SxBGKvtSExfyoJU7pIeHJfsHI0Ji41RVMkvQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/webidl-conversions": {
|
||||
@@ -775,15 +775,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.1.tgz",
|
||||
"integrity": "sha512-AVi0uazY5quFB9hlp2Xv+ogpfpk77xzsgsIEWyVS7uK/c7MZ5tw7ZPbapa0SbfkqE0fsAMkz5UwtgMLVk2BQAg==",
|
||||
"version": "5.59.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz",
|
||||
"integrity": "sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "5.59.1",
|
||||
"@typescript-eslint/type-utils": "5.59.1",
|
||||
"@typescript-eslint/utils": "5.59.1",
|
||||
"@typescript-eslint/scope-manager": "5.59.5",
|
||||
"@typescript-eslint/type-utils": "5.59.5",
|
||||
"@typescript-eslint/utils": "5.59.5",
|
||||
"debug": "^4.3.4",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
"ignore": "^5.2.0",
|
||||
@@ -809,14 +809,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "5.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.1.tgz",
|
||||
"integrity": "sha512-nzjFAN8WEu6yPRDizIFyzAfgK7nybPodMNFGNH0M9tei2gYnYszRDqVA0xlnRjkl7Hkx2vYrEdb6fP2a21cG1g==",
|
||||
"version": "5.59.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.5.tgz",
|
||||
"integrity": "sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.59.1",
|
||||
"@typescript-eslint/types": "5.59.1",
|
||||
"@typescript-eslint/typescript-estree": "5.59.1",
|
||||
"@typescript-eslint/scope-manager": "5.59.5",
|
||||
"@typescript-eslint/types": "5.59.5",
|
||||
"@typescript-eslint/typescript-estree": "5.59.5",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -836,13 +836,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.1.tgz",
|
||||
"integrity": "sha512-mau0waO5frJctPuAzcxiNWqJR5Z8V0190FTSqRw1Q4Euop6+zTwHAf8YIXNwDOT29tyUDrQ65jSg9aTU/H0omA==",
|
||||
"version": "5.59.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz",
|
||||
"integrity": "sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.59.1",
|
||||
"@typescript-eslint/visitor-keys": "5.59.1"
|
||||
"@typescript-eslint/types": "5.59.5",
|
||||
"@typescript-eslint/visitor-keys": "5.59.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -853,13 +853,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "5.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.1.tgz",
|
||||
"integrity": "sha512-ZMWQ+Oh82jWqWzvM3xU+9y5U7MEMVv6GLioM3R5NJk6uvP47kZ7YvlgSHJ7ERD6bOY7Q4uxWm25c76HKEwIjZw==",
|
||||
"version": "5.59.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz",
|
||||
"integrity": "sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "5.59.1",
|
||||
"@typescript-eslint/utils": "5.59.1",
|
||||
"@typescript-eslint/typescript-estree": "5.59.5",
|
||||
"@typescript-eslint/utils": "5.59.5",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
@@ -880,9 +880,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "5.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.1.tgz",
|
||||
"integrity": "sha512-dg0ICB+RZwHlysIy/Dh1SP+gnXNzwd/KS0JprD3Lmgmdq+dJAJnUPe1gNG34p0U19HvRlGX733d/KqscrGC1Pg==",
|
||||
"version": "5.59.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.5.tgz",
|
||||
"integrity": "sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -893,13 +893,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "5.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.1.tgz",
|
||||
"integrity": "sha512-lYLBBOCsFltFy7XVqzX0Ju+Lh3WPIAWxYpmH/Q7ZoqzbscLiCW00LeYCdsUnnfnj29/s1WovXKh2gwCoinHNGA==",
|
||||
"version": "5.59.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz",
|
||||
"integrity": "sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.59.1",
|
||||
"@typescript-eslint/visitor-keys": "5.59.1",
|
||||
"@typescript-eslint/types": "5.59.5",
|
||||
"@typescript-eslint/visitor-keys": "5.59.5",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -920,17 +920,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "5.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.1.tgz",
|
||||
"integrity": "sha512-MkTe7FE+K1/GxZkP5gRj3rCztg45bEhsd8HYjczBuYm+qFHP5vtZmjx3B0yUCDotceQ4sHgTyz60Ycl225njmA==",
|
||||
"version": "5.59.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.5.tgz",
|
||||
"integrity": "sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.59.1",
|
||||
"@typescript-eslint/types": "5.59.1",
|
||||
"@typescript-eslint/typescript-estree": "5.59.1",
|
||||
"@typescript-eslint/scope-manager": "5.59.5",
|
||||
"@typescript-eslint/types": "5.59.5",
|
||||
"@typescript-eslint/typescript-estree": "5.59.5",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"semver": "^7.3.7"
|
||||
},
|
||||
@@ -946,12 +946,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.1.tgz",
|
||||
"integrity": "sha512-6waEYwBTCWryx0VJmP7JaM4FpipLsFl9CvYf2foAE8Qh/Y0s+bxWysciwOs0LTBED4JCaNxTZ5rGadB14M6dwA==",
|
||||
"version": "5.59.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz",
|
||||
"integrity": "sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.59.1",
|
||||
"@typescript-eslint/types": "5.59.5",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1202,9 +1202,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/aws-sdk": {
|
||||
"version": "2.1368.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1368.0.tgz",
|
||||
"integrity": "sha512-Yc3s8PqdcYG4wyCOpDj4TwXacGZGDgZBJ/XAtzMLKW2wN2c4uu7GwSosLxZ8ejzbAbcqjf080odPuD8P0819tw==",
|
||||
"version": "2.1376.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1376.0.tgz",
|
||||
"integrity": "sha512-ja/Xnft8BDcDEz786VJFPrWpuWpOgsA+QzBAwzsjYeIolQ/vEs/bbXkoS085fOoeAPEhYWQh9wog7cVvrQPJFQ==",
|
||||
"dependencies": {
|
||||
"buffer": "4.9.2",
|
||||
"events": "1.1.1",
|
||||
@@ -1231,6 +1231,11 @@
|
||||
"isarray": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/aws-sdk/node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||
},
|
||||
"node_modules/aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
@@ -1387,13 +1392,38 @@
|
||||
}
|
||||
},
|
||||
"node_modules/bson": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-5.2.0.tgz",
|
||||
"integrity": "sha512-HevkSpDbpUfsrHWmWiAsNavANKYIErV2ePXllp1bwq5CDreAaFVj6RVlZpJnxK4WWDCJ/5jMUpaY6G526q3Hjg==",
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-5.3.0.tgz",
|
||||
"integrity": "sha512-ukmCZMneMlaC5ebPHXIkP8YJzNl5DC41N5MAIvKDqLggdao342t4McltoJBQfQya/nHBWAcSsYRqlXPoQkTJag==",
|
||||
"engines": {
|
||||
"node": ">=14.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-crc32": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
@@ -1425,6 +1455,27 @@
|
||||
"resolved": "https://registry.npmjs.org/buffer-to-uint8array/-/buffer-to-uint8array-1.1.0.tgz",
|
||||
"integrity": "sha512-JVTSbtA6YuOGdu5NL0ffizsBwuwbTXfV7OC91FhazMz9UKP/KlDS+Z7wuiSRClbnTQz52fJgVXI9YDXQRVl2sQ=="
|
||||
},
|
||||
"node_modules/buffer/node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
@@ -1514,13 +1565,16 @@
|
||||
"integrity": "sha512-nJ22fZvCwkJfMppkOEE7GciLX08rDnVzEJ+U46kBFZtwNzH2V4tNxMWa9Tc365WspCxy1c3NtGJ5EeT4SgjmCA=="
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/clone-response": {
|
||||
@@ -1604,6 +1658,11 @@
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-stream/node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||
},
|
||||
"node_modules/concat-stream/node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
@@ -1906,6 +1965,11 @@
|
||||
"readable-stream": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/duplexer2/node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||
},
|
||||
"node_modules/duplexer2/node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
@@ -2148,15 +2212,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.39.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz",
|
||||
"integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==",
|
||||
"version": "8.40.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz",
|
||||
"integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.4.0",
|
||||
"@eslint/eslintrc": "^2.0.2",
|
||||
"@eslint/js": "8.39.0",
|
||||
"@eslint/eslintrc": "^2.0.3",
|
||||
"@eslint/js": "8.40.0",
|
||||
"@humanwhocodes/config-array": "^0.11.8",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
@@ -2167,8 +2231,8 @@
|
||||
"doctrine": "^3.0.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^7.2.0",
|
||||
"eslint-visitor-keys": "^3.4.0",
|
||||
"espree": "^9.5.1",
|
||||
"eslint-visitor-keys": "^3.4.1",
|
||||
"espree": "^9.5.2",
|
||||
"esquery": "^1.4.2",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
@@ -2218,9 +2282,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-visitor-keys": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
|
||||
"integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz",
|
||||
"integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -2255,14 +2319,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz",
|
||||
"integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==",
|
||||
"version": "9.5.2",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz",
|
||||
"integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.8.0",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^3.4.0"
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -3359,9 +3423,9 @@
|
||||
"integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
@@ -3729,9 +3793,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
|
||||
"integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -3820,9 +3884,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.1.0.tgz",
|
||||
"integrity": "sha512-shoo9z/7o96Ojx69wpJn65+EC+Mt3q1SWTducW+F2Y4ieCXo0lZwpCZedgC841MIvJ7V8o6gmzoN1NfcnOTOuw==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.1.1.tgz",
|
||||
"integrity": "sha512-AIxaWwGY+td7QOMk4NgK6fbRuGovFyDzv65nU1uj1DsUh3lpjfP3iFYHSR+sUKrs7nbp19ksLlRXkmInBteSCA==",
|
||||
"dependencies": {
|
||||
"bson": "^5.2.0",
|
||||
"kareem": "2.5.1",
|
||||
@@ -3997,9 +4061,9 @@
|
||||
"integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA=="
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
|
||||
"integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
|
||||
"version": "2.6.11",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
|
||||
"integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
@@ -4043,9 +4107,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "6.9.1",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.1.tgz",
|
||||
"integrity": "sha512-qHw7dOiU5UKNnQpXktdgQ1d3OFgRAekuvbJLcdG5dnEo/GtcTHRYM7+UfJARdOFU9WUQO8OiIamgWPmiSFHYAA==",
|
||||
"version": "6.9.2",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.2.tgz",
|
||||
"integrity": "sha512-4+TYaa/e1nIxQfyw/WzNPYTEZ5OvHIDEnmjs4LPmIfccPQN+2CYKmGHjWixn/chzD3bmUTu5FMfpltizMxqzdg==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
@@ -4311,7 +4375,7 @@
|
||||
},
|
||||
"node_modules/pretendo-grpc-ts": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "git+ssh://git@github.com/PretendoNetwork/grpc-ts.git#028bc63602eb3cf33ea5e775face04b4c586399c",
|
||||
"resolved": "git+ssh://git@github.com/PretendoNetwork/grpc-ts.git#b7bcb0d691cec3f88ff0627cb7431c14dd2d2d1d",
|
||||
"hasInstallScript": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
@@ -4524,11 +4588,6 @@
|
||||
"string_decoder": "~0.10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream/node_modules/isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
|
||||
},
|
||||
"node_modules/redis": {
|
||||
"version": "4.6.6",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-4.6.6.tgz",
|
||||
@@ -5006,6 +5065,11 @@
|
||||
"through2": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/static-module/node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||
},
|
||||
"node_modules/static-module/node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
@@ -5105,9 +5169,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/stripe": {
|
||||
"version": "12.3.0",
|
||||
"resolved": "https://registry.npmjs.org/stripe/-/stripe-12.3.0.tgz",
|
||||
"integrity": "sha512-B9Q1b0gbKY/Z4fQc1Y82VpHTFLh8A67D6kdcFtgpGfTovVkI7SamE66vmVaWNHgcUjPqI8x6wVvksdRf/ucTDw==",
|
||||
"version": "12.4.0",
|
||||
"resolved": "https://registry.npmjs.org/stripe/-/stripe-12.4.0.tgz",
|
||||
"integrity": "sha512-QjZRzKi3wf8TsuJf/fd6/ejfPgwNptDIzFogRWaRzP3oMJnSD73I2YxR0Eje5zfrU8FmddYWZYawoUejqN+o1w==",
|
||||
"dependencies": {
|
||||
"@types/node": ">=8.1.0",
|
||||
"qs": "^6.11.0"
|
||||
@@ -5140,13 +5204,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "6.1.13",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz",
|
||||
"integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==",
|
||||
"version": "6.1.14",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.14.tgz",
|
||||
"integrity": "sha512-piERznXu0U7/pW7cdSn7hjqySIVTYT6F76icmFk7ptU7dDYlXTm5r9A6K04R2vU3olYgoKeo1Cg3eeu5nhftAw==",
|
||||
"dependencies": {
|
||||
"chownr": "^2.0.0",
|
||||
"fs-minipass": "^2.0.0",
|
||||
"minipass": "^4.0.0",
|
||||
"minipass": "^5.0.0",
|
||||
"minizlib": "^2.1.1",
|
||||
"mkdirp": "^1.0.3",
|
||||
"yallist": "^4.0.0"
|
||||
@@ -5195,6 +5259,11 @@
|
||||
"xtend": "~4.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/through2/node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||
},
|
||||
"node_modules/through2/node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
@@ -5685,28 +5754,28 @@
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dependencies": {
|
||||
"cliui": "^7.0.2",
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.0",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^20.2.2"
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "20.2.9",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yesno": {
|
||||
|
||||
@@ -67,7 +67,10 @@ export const config: Config = {
|
||||
website_base: process.env.PN_ACT_CONFIG_WEBSITE_BASE || '',
|
||||
aes_key: process.env.PN_ACT_CONFIG_AES_KEY || '',
|
||||
grpc: {
|
||||
api_key: process.env.PN_ACT_CONFIG_GRPC_API_KEY || '',
|
||||
master_api_keys: {
|
||||
account: process.env.PN_ACT_CONFIG_GRPC_MASTER_API_KEY_ACCOUNT || '',
|
||||
api: process.env.PN_ACT_CONFIG_GRPC_MASTER_API_KEY_API || '',
|
||||
},
|
||||
port: Number(process.env.PN_ACT_CONFIG_GRPC_PORT || ''),
|
||||
}
|
||||
};
|
||||
@@ -180,8 +183,13 @@ if (!config.aes_key) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.grpc.api_key) {
|
||||
LOG_ERROR('gRPC API key is not set. Set the PN_ACT_CONFIG_GRPC_API_KEY environment variable');
|
||||
if (!config.grpc.master_api_keys.account) {
|
||||
LOG_ERROR('Master gRPC API key for the account service is not set. Set the PN_ACT_CONFIG_GRPC_MASTER_API_KEY_ACCOUNT environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.grpc.master_api_keys.api) {
|
||||
LOG_ERROR('Master gRPC API key for the api service is not set. Set the PN_ACT_CONFIG_GRPC_MASTER_API_KEY_API environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import assets from '@/services/assets';
|
||||
|
||||
import { config } from '@/config-manager';
|
||||
|
||||
const app = express();
|
||||
const app: express.Express = express();
|
||||
|
||||
// START APPLICATION
|
||||
|
||||
|
||||
16
src/services/grpc/account/api-key-middleware.ts
Normal file
16
src/services/grpc/account/api-key-middleware.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Status, ServerMiddlewareCall, CallContext, ServerError } from 'nice-grpc';
|
||||
import { config } from '@/config-manager';
|
||||
|
||||
export async function* apiKeyMiddleware<Request, Response>(
|
||||
call: ServerMiddlewareCall<Request, Response>,
|
||||
context: CallContext,
|
||||
): AsyncGenerator<Response, Response | void, undefined> {
|
||||
console.log(call.method);
|
||||
const apiKey: string | undefined = context.metadata.get('X-API-Key');
|
||||
|
||||
if (!apiKey || apiKey !== config.grpc.master_api_keys.account) {
|
||||
throw new ServerError(Status.UNAUTHENTICATED, 'Missing or invalid API key');
|
||||
}
|
||||
|
||||
return yield* call.next(call.request, context);
|
||||
}
|
||||
6
src/services/grpc/account/implementation.ts
Normal file
6
src/services/grpc/account/implementation.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { AccountServiceImplementation } from 'pretendo-grpc-ts/dist/account/account_service';
|
||||
import { getUserData } from '@/services/grpc/account/get-user-data';
|
||||
|
||||
export const accountServiceImplementation: AccountServiceImplementation = {
|
||||
getUserData,
|
||||
};
|
||||
@@ -7,11 +7,8 @@ export async function* apiKeyMiddleware<Request, Response>(
|
||||
): AsyncGenerator<Response, Response | void, undefined> {
|
||||
const apiKey: string | undefined = context.metadata.get('X-API-Key');
|
||||
|
||||
if (!apiKey || apiKey !== config.grpc.api_key) {
|
||||
throw new ServerError(
|
||||
Status.UNAUTHENTICATED,
|
||||
'Missing or invalid API key',
|
||||
);
|
||||
if (!apiKey || apiKey !== config.grpc.master_api_keys.api) {
|
||||
throw new ServerError(Status.UNAUTHENTICATED, 'Missing or invalid API key');
|
||||
}
|
||||
|
||||
return yield* call.next(call.request, context);
|
||||
55
src/services/grpc/api/authentication-middleware.ts
Normal file
55
src/services/grpc/api/authentication-middleware.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Status, ServerMiddlewareCall, CallContext, ServerError } from 'nice-grpc';
|
||||
import { getPNIDByBearerAuth } from '@/database';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
// * These paths require that a token be present
|
||||
const TOKEN_REQUIRED_PATHS: string[] = [
|
||||
'/api.API/GetUserData',
|
||||
'/api.API/UpdateUserData',
|
||||
'/api.API/ResetPassword', // * This paths token is not an authentication token, it is a password reset token
|
||||
'/api.API/SetDiscordConnectionData',
|
||||
'/api.API/SetStripeConnectionData',
|
||||
'/api.API/RemoveConnection'
|
||||
];
|
||||
|
||||
export type AuthenticationCallContextExt = {
|
||||
pnid: HydratedPNIDDocument | null;
|
||||
};
|
||||
|
||||
export async function* authenticationMiddleware<Request, Response>(
|
||||
call: ServerMiddlewareCall<Request, Response, AuthenticationCallContextExt>,
|
||||
context: CallContext,
|
||||
): AsyncGenerator<Response, Response | void, undefined> {
|
||||
const token: string | undefined = context.metadata.get('X-Token')?.trim();
|
||||
|
||||
if (!token && TOKEN_REQUIRED_PATHS.includes(call.method.path)) {
|
||||
throw new ServerError(Status.UNAUTHENTICATED, 'Missing or invalid authentication token');
|
||||
}
|
||||
|
||||
try {
|
||||
let pnid: HydratedPNIDDocument | null = null;
|
||||
|
||||
if (token) {
|
||||
pnid = await getPNIDByBearerAuth(token);
|
||||
}
|
||||
|
||||
if (!pnid && TOKEN_REQUIRED_PATHS.includes(call.method.path)) {
|
||||
throw new ServerError(Status.UNAUTHENTICATED, 'Missing or invalid authentication token');
|
||||
}
|
||||
|
||||
return yield* call.next(call.request, {
|
||||
...context,
|
||||
pnid
|
||||
});
|
||||
} catch (error) {
|
||||
let message: string = 'Unknown server error';
|
||||
|
||||
console.log(error);
|
||||
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
}
|
||||
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, message);
|
||||
}
|
||||
}
|
||||
29
src/services/grpc/api/forgot-password.ts
Normal file
29
src/services/grpc/api/forgot-password.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import validator from 'validator';
|
||||
import { ForgotPasswordRequest } from 'pretendo-grpc-ts/dist/api/forgot_password_rpc';
|
||||
import { getPNIDByEmailAddress, getPNIDByUsername } from '@/database';
|
||||
import { sendForgotPasswordEmail } from '@/util';
|
||||
import type { Empty } from 'pretendo-grpc-ts/dist/api/google/protobuf/empty';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
export async function forgotPassword(request: ForgotPasswordRequest): Promise<Empty> {
|
||||
const input: string = request.emailAddressOrUsername.trim();
|
||||
|
||||
if (!input) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Invalid or missing input');
|
||||
}
|
||||
|
||||
let pnid: HydratedPNIDDocument | null;
|
||||
|
||||
if (validator.isEmail(input)) {
|
||||
pnid = await getPNIDByEmailAddress(input);
|
||||
} else {
|
||||
pnid = await getPNIDByUsername(input);
|
||||
}
|
||||
|
||||
if (pnid) {
|
||||
await sendForgotPasswordEmail(pnid);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
46
src/services/grpc/api/get-user-data.ts
Normal file
46
src/services/grpc/api/get-user-data.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { CallContext } from 'nice-grpc';
|
||||
import { GetUserDataResponse, DeepPartial } from 'pretendo-grpc-ts/dist/api/get_user_data_rpc';
|
||||
import { config } from '@/config-manager';
|
||||
import type { Empty } from 'pretendo-grpc-ts/dist/api/google/protobuf/empty';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/api/authentication-middleware';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
export async function getUserData(_request: Empty, context: CallContext & AuthenticationCallContextExt): Promise<DeepPartial<GetUserDataResponse>> {
|
||||
// * This is asserted in authentication-middleware, we know this is never null
|
||||
const pnid: HydratedPNIDDocument = context.pnid!;
|
||||
|
||||
return {
|
||||
deleted: pnid.deleted,
|
||||
creationDate: pnid.creation_date,
|
||||
updatedDate: pnid.updated,
|
||||
pid: pnid.pid,
|
||||
username: pnid.username,
|
||||
accessLevel: pnid.access_level,
|
||||
serverAccessLevel: pnid.server_access_level,
|
||||
mii: {
|
||||
name: pnid.mii.name,
|
||||
data: pnid.mii.data,
|
||||
url: `${config.cdn.base_url}/mii/${pnid.pid}/standard.tga`,
|
||||
},
|
||||
birthday: pnid.birthdate,
|
||||
gender: pnid.gender,
|
||||
country: pnid.country,
|
||||
timezone: pnid.timezone.name,
|
||||
language: pnid.language,
|
||||
emailAddress: pnid.email.address,
|
||||
connections: {
|
||||
discord: {
|
||||
id: pnid.connections.discord.id
|
||||
},
|
||||
stripe: {
|
||||
customerId: pnid.connections.stripe.customer_id,
|
||||
subscriptionId: pnid.connections.stripe.subscription_id,
|
||||
priceId: pnid.connections.stripe.price_id,
|
||||
tierLevel: pnid.connections.stripe.tier_level,
|
||||
tierName: pnid.connections.stripe.tier_name,
|
||||
latestWebhookTimestamp: pnid.connections.stripe.latest_webhook_timestamp
|
||||
}
|
||||
},
|
||||
marketingFlag: pnid.flags.marketing
|
||||
};
|
||||
}
|
||||
20
src/services/grpc/api/implementation.ts
Normal file
20
src/services/grpc/api/implementation.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { APIServiceImplementation } from 'pretendo-grpc-ts/dist/api/api_service';
|
||||
import { register } from '@/services/grpc/api/register';
|
||||
import { login } from '@/services/grpc/api/login';
|
||||
import { getUserData } from '@/services/grpc/api/get-user-data';
|
||||
import { updateUserData } from '@/services/grpc/api/update-user-data';
|
||||
import { forgotPassword } from '@/services/grpc/api/forgot-password';
|
||||
import { resetPassword } from '@/services/grpc/api/reset-password';
|
||||
import { setDiscordConnectionData } from '@/services/grpc/api/set-discord-connection-data';
|
||||
import { setStripeConnectionData } from '@/services/grpc/api/set-stripe-connection-data';
|
||||
|
||||
export const apiServiceImplementation: APIServiceImplementation = {
|
||||
register,
|
||||
login,
|
||||
getUserData,
|
||||
updateUserData,
|
||||
forgotPassword,
|
||||
resetPassword,
|
||||
setDiscordConnectionData,
|
||||
setStripeConnectionData
|
||||
};
|
||||
90
src/services/grpc/api/login.ts
Normal file
90
src/services/grpc/api/login.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { LoginRequest, LoginResponse, DeepPartial } from 'pretendo-grpc-ts/dist/api/login_rpc';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { getPNIDByUsername, getPNIDByBearerAuth } from '@/database';
|
||||
import { nintendoPasswordHash, generateToken} from '@/util';
|
||||
import { config } from '@/config-manager';
|
||||
import type { TokenOptions } from '@/types/common/token-options';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
export async function login(request: LoginRequest): Promise<DeepPartial<LoginResponse>> {
|
||||
const grantType: string = request.grantType?.trim();
|
||||
const username: string | undefined = request.username?.trim();
|
||||
const password: string | undefined = request.password?.trim();
|
||||
const refreshToken: string | undefined = request.refreshToken?.trim();
|
||||
|
||||
if (!['password', 'refresh_token'].includes(grantType)) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Invalid grant type');
|
||||
}
|
||||
|
||||
if (grantType === 'password' && !username) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Invalid or missing username');
|
||||
}
|
||||
|
||||
if (grantType === 'password' && !password) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Invalid or missing password');
|
||||
}
|
||||
|
||||
if (grantType === 'refresh_token' && !refreshToken) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Invalid or missing refresh token');
|
||||
}
|
||||
|
||||
let pnid: HydratedPNIDDocument | null;
|
||||
|
||||
if (grantType === 'password') {
|
||||
pnid = await getPNIDByUsername(username!); // * We know username will never be null here
|
||||
|
||||
if (!pnid) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'User not found');
|
||||
}
|
||||
|
||||
const hashedPassword: string = nintendoPasswordHash(password!, pnid.pid); // * We know password will never be null here
|
||||
|
||||
if (!bcrypt.compareSync(hashedPassword, pnid.password)) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Password is incorrect');
|
||||
}
|
||||
} else {
|
||||
pnid = await getPNIDByBearerAuth(refreshToken!); // * We know refreshToken will never be null here
|
||||
|
||||
if (!pnid) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Invalid or missing refresh token');
|
||||
}
|
||||
}
|
||||
|
||||
if (pnid.deleted) {
|
||||
throw new ServerError(Status.UNAUTHENTICATED, 'Account has been deleted');
|
||||
}
|
||||
|
||||
const accessTokenOptions: TokenOptions = {
|
||||
system_type: 0x3, // * API
|
||||
token_type: 0x1, // * OAuth Access
|
||||
pid: pnid.pid,
|
||||
access_level: pnid.access_level,
|
||||
title_id: BigInt(0),
|
||||
expire_time: BigInt(Date.now() + (3600 * 1000))
|
||||
};
|
||||
|
||||
const refreshTokenOptions: TokenOptions = {
|
||||
system_type: 0x3, // * API
|
||||
token_type: 0x2, // * OAuth Refresh
|
||||
pid: pnid.pid,
|
||||
access_level: pnid.access_level,
|
||||
title_id: BigInt(0),
|
||||
expire_time: BigInt(Date.now() + (3600 * 1000))
|
||||
};
|
||||
|
||||
const accessTokenBuffer: Buffer | null = await generateToken(config.aes_key, accessTokenOptions);
|
||||
const refreshTokenBuffer: Buffer | null = await generateToken(config.aes_key, refreshTokenOptions);
|
||||
|
||||
const accessToken: string = accessTokenBuffer ? accessTokenBuffer.toString('hex') : '';
|
||||
const newRefreshToken: string = refreshTokenBuffer ? refreshTokenBuffer.toString('hex') : '';
|
||||
|
||||
// TODO - Handle null tokens
|
||||
|
||||
return {
|
||||
accessToken: accessToken,
|
||||
tokenType: 'Bearer',
|
||||
expiresIn: 3600,
|
||||
refreshToken: newRefreshToken
|
||||
};
|
||||
}
|
||||
266
src/services/grpc/api/register.ts
Normal file
266
src/services/grpc/api/register.ts
Normal file
@@ -0,0 +1,266 @@
|
||||
import crypto from 'node:crypto';
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { RegisterRequest, DeepPartial } from 'pretendo-grpc-ts/dist/api/register_rpc';
|
||||
import { LoginResponse } from 'pretendo-grpc-ts/dist/api/login_rpc';
|
||||
import emailvalidator from 'email-validator';
|
||||
import bcrypt from 'bcrypt';
|
||||
import moment from 'moment';
|
||||
import hcaptcha from 'hcaptcha';
|
||||
import Mii from 'mii-js';
|
||||
import mongoose from 'mongoose';
|
||||
import { doesPNIDExist, connection as databaseConnection } from '@/database';
|
||||
import { nintendoPasswordHash, sendConfirmationEmail, generateToken } from '@/util';
|
||||
import { LOG_ERROR } from '@/logger';
|
||||
import { PNID } from '@/models/pnid';
|
||||
import { NEXAccount } from '@/models/nex-account';
|
||||
import { config, disabledFeatures } from '@/config-manager';
|
||||
import type { TokenOptions } from '@/types/common/token-options';
|
||||
import type { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
const PNID_VALID_CHARACTERS_REGEX: RegExp = /^[\w\-.]*$/;
|
||||
const PNID_PUNCTUATION_START_REGEX: RegExp = /^[_\-.]/;
|
||||
const PNID_PUNCTUATION_END_REGEX: RegExp = /[_\-.]$/;
|
||||
const PNID_PUNCTUATION_DUPLICATE_REGEX: RegExp = /[_\-.]{2,}/;
|
||||
|
||||
// This sucks
|
||||
const PASSWORD_WORD_OR_NUMBER_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*\d).*/;
|
||||
const PASSWORD_WORD_OR_PUNCTUATION_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*[_\-.]).*/;
|
||||
const PASSWORD_NUMBER_OR_PUNCTUATION_REGEX: RegExp = /(?=.*\d)(?=.*[_\-.]).*/;
|
||||
const PASSWORD_REPEATED_CHARACTER_REGEX: RegExp = /(.)\1\1/;
|
||||
|
||||
const DEFAULT_MII_DATA: Buffer = Buffer.from('AwAAQOlVognnx0GC2/uogAOzuI0n2QAAAEBEAGUAZgBhAHUAbAB0AAAAAAAAAEBAAAAhAQJoRBgmNEYUgRIXaA0AACkAUkhQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGm9', 'base64');
|
||||
|
||||
export async function register(request: RegisterRequest): Promise<DeepPartial<LoginResponse>> {
|
||||
const email: string = request.email?.trim();
|
||||
const username: string = request.username?.trim();
|
||||
const miiName: string = request.miiName?.trim();
|
||||
const password: string = request.password?.trim();
|
||||
const passwordConfirm: string = request.passwordConfirm?.trim();
|
||||
const captchaResponse: string | undefined = request.captchaResponse?.trim();
|
||||
|
||||
// * Only validate the captcha if that's enabled
|
||||
if (!disabledFeatures.captcha) {
|
||||
if (!captchaResponse) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Must fill in captcha');
|
||||
}
|
||||
|
||||
const captchaVerify: VerifyResponse = await hcaptcha.verify(config.hcaptcha.secret, captchaResponse);
|
||||
|
||||
if (!captchaVerify.success) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Captcha verification failed');
|
||||
}
|
||||
}
|
||||
|
||||
if (!email) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Must enter an email address');
|
||||
}
|
||||
|
||||
if (!emailvalidator.validate(email)) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Invalid email address');
|
||||
}
|
||||
|
||||
if (!username) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Must enter a username');
|
||||
}
|
||||
|
||||
if (username.length < 6) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Username is too short');
|
||||
}
|
||||
|
||||
if (username.length > 16) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Username is too long');
|
||||
}
|
||||
|
||||
if (!PNID_VALID_CHARACTERS_REGEX.test(username)) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Username contains invalid characters');
|
||||
}
|
||||
|
||||
if (PNID_PUNCTUATION_START_REGEX.test(username)) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Username cannot begin with punctuation characters');
|
||||
}
|
||||
|
||||
if (PNID_PUNCTUATION_END_REGEX.test(username)) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Username cannot end with punctuation characters');
|
||||
}
|
||||
|
||||
if (PNID_PUNCTUATION_DUPLICATE_REGEX.test(username)) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Two or more punctuation characters cannot be used in a row');
|
||||
}
|
||||
|
||||
const userExists: boolean = await doesPNIDExist(username);
|
||||
|
||||
if (userExists) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'PNID already in use');
|
||||
}
|
||||
|
||||
if (!miiName) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Must enter a Mii name');
|
||||
}
|
||||
|
||||
const miiNameBuffer: Buffer = Buffer.from(miiName, 'utf16le'); // * UTF8 to UTF16
|
||||
|
||||
if (miiNameBuffer.length > 0x14) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Mii name too long');
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Must enter a password');
|
||||
}
|
||||
|
||||
if (password.length < 6 || password.length > 16) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Password must be between 6 and 16 characters long');
|
||||
}
|
||||
|
||||
if (password.toLowerCase() === username.toLowerCase()) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Password cannot be the same as username');
|
||||
}
|
||||
|
||||
if (!PASSWORD_WORD_OR_NUMBER_REGEX.test(password) && !PASSWORD_WORD_OR_PUNCTUATION_REGEX.test(password) && !PASSWORD_NUMBER_OR_PUNCTUATION_REGEX.test(password)) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Password must have combination of letters, numbers, and/or punctuation characters');
|
||||
}
|
||||
|
||||
if (PASSWORD_REPEATED_CHARACTER_REGEX.test(password)) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Password may not have 3 repeating characters');
|
||||
}
|
||||
|
||||
if (password !== passwordConfirm) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Passwords do not match');
|
||||
}
|
||||
|
||||
const mii: Mii = new Mii(DEFAULT_MII_DATA);
|
||||
mii.miiName = miiName;
|
||||
|
||||
const creationDate: string = moment().format('YYYY-MM-DDTHH:MM:SS');
|
||||
let pnid: HydratedPNIDDocument;
|
||||
let nexAccount: HydratedNEXAccountDocument;
|
||||
|
||||
const session: mongoose.ClientSession = await databaseConnection().startSession();
|
||||
await session.startTransaction();
|
||||
|
||||
try {
|
||||
// * PNIDs can only be registered from a Wii U
|
||||
// * So assume website users are WiiU NEX accounts
|
||||
nexAccount = new NEXAccount({
|
||||
device_type: 'wiiu',
|
||||
});
|
||||
|
||||
await nexAccount.generatePID();
|
||||
await nexAccount.generatePassword();
|
||||
|
||||
// Quick hack to get the PIDs to match
|
||||
// TODO: Change this maybe?
|
||||
// NN with a NNID will always use the NNID PID
|
||||
// even if the provided NEX PID is different
|
||||
// To fix this we make them the same PID
|
||||
nexAccount.owning_pid = nexAccount.pid;
|
||||
|
||||
await nexAccount.save({ session });
|
||||
|
||||
const primaryPasswordHash: string = nintendoPasswordHash(password, nexAccount.pid);
|
||||
const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10);
|
||||
|
||||
pnid = new PNID({
|
||||
pid: nexAccount.pid,
|
||||
creation_date: creationDate,
|
||||
updated: creationDate,
|
||||
username: username,
|
||||
usernameLower: username.toLowerCase(),
|
||||
password: passwordHash,
|
||||
birthdate: '1990-01-01', // TODO: Change this
|
||||
gender: 'M', // TODO: Change this
|
||||
country: 'US', // TODO: Change this
|
||||
language: 'en', // TODO: Change this
|
||||
email: {
|
||||
address: email.toLowerCase(),
|
||||
primary: true, // TODO: Change this
|
||||
parent: true, // TODO: Change this
|
||||
reachable: false, // TODO: Change this
|
||||
validated: false, // TODO: Change this
|
||||
id: crypto.randomBytes(4).readUInt32LE()
|
||||
},
|
||||
region: 0x310B0000, // TODO: Change this
|
||||
timezone: {
|
||||
name: 'America/New_York', // TODO: Change this
|
||||
offset: -14400 // TODO: Change this
|
||||
},
|
||||
mii: {
|
||||
name: miiName,
|
||||
primary: true, // TODO: Change this
|
||||
data: mii.encode().toString('base64'),
|
||||
id: crypto.randomBytes(4).readUInt32LE(),
|
||||
hash: crypto.randomBytes(7).toString('hex'),
|
||||
image_url: '', // deprecated, will be removed in the future
|
||||
image_id: crypto.randomBytes(4).readUInt32LE()
|
||||
},
|
||||
flags: {
|
||||
active: true, // TODO: Change this
|
||||
marketing: true, // TODO: Change this
|
||||
off_device: true // TODO: Change this
|
||||
},
|
||||
identification: {
|
||||
email_code: 1, // will be overwritten before saving
|
||||
email_token: '' // will be overwritten before saving
|
||||
}
|
||||
});
|
||||
|
||||
await pnid.generateEmailValidationCode();
|
||||
await pnid.generateEmailValidationToken();
|
||||
await pnid.generateMiiImages();
|
||||
|
||||
await pnid.save({ session });
|
||||
|
||||
await session.commitTransaction();
|
||||
} catch (error) {
|
||||
let message: string = 'Unknown Mongo error';
|
||||
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
}
|
||||
|
||||
LOG_ERROR(`[gRPC] /api.API/Register: ${message}`);
|
||||
|
||||
await session.abortTransaction();
|
||||
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, message);
|
||||
} finally {
|
||||
// * This runs regardless of failure
|
||||
// * Returning on catch will not prevent this from running
|
||||
await session.endSession();
|
||||
}
|
||||
|
||||
await sendConfirmationEmail(pnid);
|
||||
|
||||
const accessTokenOptions: TokenOptions = {
|
||||
system_type: 0x3, // * API
|
||||
token_type: 0x1, // * OAuth Access
|
||||
pid: pnid.pid,
|
||||
access_level: pnid.access_level,
|
||||
title_id: BigInt(0),
|
||||
expire_time: BigInt(Date.now() + (3600 * 1000))
|
||||
};
|
||||
|
||||
const refreshTokenOptions: TokenOptions = {
|
||||
system_type: 0x3, // * API
|
||||
token_type: 0x2, // * OAuth Refresh
|
||||
pid: pnid.pid,
|
||||
access_level: pnid.access_level,
|
||||
title_id: BigInt(0),
|
||||
expire_time: BigInt(Date.now() + (3600 * 1000))
|
||||
};
|
||||
|
||||
const accessTokenBuffer: Buffer | null = await generateToken(config.aes_key, accessTokenOptions);
|
||||
const refreshTokenBuffer: Buffer | null = await generateToken(config.aes_key, refreshTokenOptions);
|
||||
|
||||
const accessToken: string = accessTokenBuffer ? accessTokenBuffer.toString('hex') : '';
|
||||
const refreshToken: string = refreshTokenBuffer ? refreshTokenBuffer.toString('hex') : '';
|
||||
|
||||
// TODO - Handle null tokens
|
||||
|
||||
return {
|
||||
accessToken: accessToken,
|
||||
tokenType: 'Bearer',
|
||||
expiresIn: 3600,
|
||||
refreshToken: refreshToken
|
||||
};
|
||||
}
|
||||
79
src/services/grpc/api/reset-password.ts
Normal file
79
src/services/grpc/api/reset-password.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import bcrypt from 'bcrypt';
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { ResetPasswordRequest } from 'pretendo-grpc-ts/dist/api/reset_password_rpc';
|
||||
import { decryptToken, unpackToken, nintendoPasswordHash } from '@/util';
|
||||
import { getPNIDByPID } from '@/database';
|
||||
import type { Empty } from 'pretendo-grpc-ts/dist/api/google/protobuf/empty';
|
||||
import type { Token } from '@/types/common/token';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
// This sucks
|
||||
const PASSWORD_WORD_OR_NUMBER_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*\d).*/;
|
||||
const PASSWORD_WORD_OR_PUNCTUATION_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*[_\-.]).*/;
|
||||
const PASSWORD_NUMBER_OR_PUNCTUATION_REGEX: RegExp = /(?=.*\d)(?=.*[_\-.]).*/;
|
||||
const PASSWORD_REPEATED_CHARACTER_REGEX: RegExp = /(.)\1\1/;
|
||||
|
||||
export async function resetPassword(request: ResetPasswordRequest): Promise<Empty> {
|
||||
const password: string = request.password.trim();
|
||||
const passwordConfirm: string = request.passwordConfirm.trim();
|
||||
const token: string = request.token.trim();
|
||||
|
||||
if (!token) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Missing token');
|
||||
}
|
||||
|
||||
let unpackedToken: Token;
|
||||
try {
|
||||
const decryptedToken: Buffer = await decryptToken(Buffer.from(token, 'base64'));
|
||||
unpackedToken = unpackToken(decryptedToken);
|
||||
} catch (error) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Invalid token');
|
||||
}
|
||||
|
||||
if (unpackedToken.expire_time < Date.now()) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Token expired');
|
||||
}
|
||||
|
||||
const pnid: HydratedPNIDDocument | null = await getPNIDByPID(unpackedToken.pid);
|
||||
|
||||
if (!pnid) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Invalid token. No user found');
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Must enter a password');
|
||||
}
|
||||
|
||||
if (password.length < 6) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Password is too short');
|
||||
}
|
||||
|
||||
if (password.length > 16) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Password is too long');
|
||||
}
|
||||
|
||||
if (password.toLowerCase() === pnid.usernameLower) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Password cannot be the same as username');
|
||||
}
|
||||
|
||||
if (!PASSWORD_WORD_OR_NUMBER_REGEX.test(password) && !PASSWORD_WORD_OR_PUNCTUATION_REGEX.test(password) && !PASSWORD_NUMBER_OR_PUNCTUATION_REGEX.test(password)) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Password must have combination of letters, numbers, and/or punctuation characters');
|
||||
}
|
||||
|
||||
if (PASSWORD_REPEATED_CHARACTER_REGEX.test(password)) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Password may not have 3 repeating characters');
|
||||
}
|
||||
|
||||
if (password !== passwordConfirm) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Passwords do not match');
|
||||
}
|
||||
|
||||
const primaryPasswordHash: string = nintendoPasswordHash(password, pnid.pid);
|
||||
const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10);
|
||||
|
||||
pnid.password = passwordHash;
|
||||
|
||||
await pnid.save();
|
||||
|
||||
return {};
|
||||
}
|
||||
26
src/services/grpc/api/set-discord-connection-data.ts
Normal file
26
src/services/grpc/api/set-discord-connection-data.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Status, ServerError, CallContext } from 'nice-grpc';
|
||||
import { SetDiscordConnectionDataRequest } from 'pretendo-grpc-ts/dist/api/set_discord_connection_data_rpc';
|
||||
import type { Empty } from 'pretendo-grpc-ts/dist/api/google/protobuf/empty';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/api/authentication-middleware';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
export async function setDiscordConnectionData(request: SetDiscordConnectionDataRequest, context: CallContext & AuthenticationCallContextExt): Promise<Empty>{
|
||||
// * This is asserted in authentication-middleware, we know this is never null
|
||||
const pnid: HydratedPNIDDocument = context.pnid!;
|
||||
|
||||
try {
|
||||
pnid.connections.discord.id = request.id;
|
||||
|
||||
await pnid.save();
|
||||
} catch (error) {
|
||||
let message: string = 'Unknown Mongo error';
|
||||
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
}
|
||||
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, message);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
91
src/services/grpc/api/set-stripe-connection-data.ts
Normal file
91
src/services/grpc/api/set-stripe-connection-data.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { Status, ServerError, CallContext } from 'nice-grpc';
|
||||
import { SetStripeConnectionDataRequest } from 'pretendo-grpc-ts/dist/api/set_stripe_connection_data_rpc';
|
||||
import { PNID } from '@/models/pnid';
|
||||
import type { Empty } from 'pretendo-grpc-ts/dist/api/google/protobuf/empty';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/api/authentication-middleware';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
type StripeMongoUpdateScheme = {
|
||||
access_level?: number;
|
||||
server_access_level?: string;
|
||||
'connections.stripe.customer_id'?: string;
|
||||
'connections.stripe.subscription_id'?: string;
|
||||
'connections.stripe.price_id'?: string;
|
||||
'connections.stripe.tier_level'?: number;
|
||||
'connections.stripe.tier_name'?: string;
|
||||
'connections.stripe.latest_webhook_timestamp': number;
|
||||
};
|
||||
|
||||
export async function setStripeConnectionData(request: SetStripeConnectionDataRequest, context: CallContext & AuthenticationCallContextExt): Promise<Empty>{
|
||||
// * This is asserted in authentication-middleware, we know this is never null
|
||||
const pnid: HydratedPNIDDocument = context.pnid!;
|
||||
|
||||
const updateData: StripeMongoUpdateScheme = {
|
||||
'connections.stripe.latest_webhook_timestamp': request.timestamp
|
||||
};
|
||||
|
||||
if (request.customerId && !pnid.connections.stripe.customer_id) {
|
||||
updateData['connections.stripe.customer_id'] = request.customerId;
|
||||
}
|
||||
|
||||
// * These checks allow for null/0 values in order to reset data if needed
|
||||
|
||||
if (request.accessLevel !== undefined) {
|
||||
updateData.access_level = request.accessLevel;
|
||||
}
|
||||
|
||||
if (request.serverAccessLevel !== undefined) {
|
||||
updateData.server_access_level = request.serverAccessLevel;
|
||||
}
|
||||
|
||||
if (request.subscriptionId !== undefined) {
|
||||
updateData['connections.stripe.subscription_id'] = request.subscriptionId;
|
||||
}
|
||||
|
||||
if (request.subscriptionId !== undefined) {
|
||||
updateData['connections.stripe.subscription_id'] = request.subscriptionId;
|
||||
}
|
||||
|
||||
if (request.priceId !== undefined) {
|
||||
updateData['connections.stripe.price_id'] = request.priceId;
|
||||
}
|
||||
|
||||
if (request.tierLevel !== undefined) {
|
||||
updateData['connections.stripe.tier_level'] = request.tierLevel;
|
||||
}
|
||||
|
||||
if (request.tierName !== undefined) {
|
||||
updateData['connections.stripe.tier_name'] = request.tierName;
|
||||
}
|
||||
|
||||
try {
|
||||
if (pnid.connections.stripe.latest_webhook_timestamp && pnid.connections.stripe.customer_id) {
|
||||
// * Stripe customer data has already been initialized, update it
|
||||
await PNID.updateOne({
|
||||
pid: pnid.pid,
|
||||
'connections.stripe.latest_webhook_timestamp': {
|
||||
$lte: request.timestamp
|
||||
}
|
||||
}, { $set: updateData }).exec();
|
||||
} else {
|
||||
// * Initialize a new Stripe user
|
||||
if (!request.customerId) {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'No Stripe user data found and no custom ID provided');
|
||||
}
|
||||
|
||||
PNID.updateOne({ pid: pnid.pid }, {
|
||||
$set: updateData
|
||||
}, { upsert: true }).exec();
|
||||
}
|
||||
} catch (error) {
|
||||
let message: string = 'Unknown Mongo error';
|
||||
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
}
|
||||
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, message);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
48
src/services/grpc/api/update-user-data.ts
Normal file
48
src/services/grpc/api/update-user-data.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { CallContext } from 'nice-grpc';
|
||||
import { UpdateUserDataRequest, DeepPartial } from 'pretendo-grpc-ts/dist/api/update_user_data_rpc';
|
||||
import { GetUserDataResponse } from 'pretendo-grpc-ts/dist/api/get_user_data_rpc';
|
||||
import { config } from '@/config-manager';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/api/authentication-middleware';
|
||||
|
||||
export async function updateUserData(_request: UpdateUserDataRequest, context: CallContext & AuthenticationCallContextExt): Promise<DeepPartial<GetUserDataResponse>> {
|
||||
// * This is asserted in authentication-middleware, we know this is never null
|
||||
const pnid: HydratedPNIDDocument = context.pnid!;
|
||||
|
||||
// TODO - STUBBED, DO SOMETHING HERE
|
||||
|
||||
return {
|
||||
deleted: pnid.deleted,
|
||||
creationDate: pnid.creation_date,
|
||||
updatedDate: pnid.updated,
|
||||
pid: pnid.pid,
|
||||
username: pnid.username,
|
||||
accessLevel: pnid.access_level,
|
||||
serverAccessLevel: pnid.server_access_level,
|
||||
mii: {
|
||||
name: pnid.mii.name,
|
||||
data: pnid.mii.data,
|
||||
url: `${config.cdn.base_url}/mii/${pnid.pid}/standard.tga`,
|
||||
},
|
||||
birthday: pnid.birthdate,
|
||||
gender: pnid.gender,
|
||||
country: pnid.country,
|
||||
timezone: pnid.timezone.name,
|
||||
language: pnid.language,
|
||||
emailAddress: pnid.email.address,
|
||||
connections: {
|
||||
discord: {
|
||||
id: pnid.connections.discord.id
|
||||
},
|
||||
stripe: {
|
||||
customerId: pnid.connections.stripe.customer_id,
|
||||
subscriptionId: pnid.connections.stripe.subscription_id,
|
||||
priceId: pnid.connections.stripe.price_id,
|
||||
tierLevel: pnid.connections.stripe.tier_level,
|
||||
tierName: pnid.connections.stripe.tier_name,
|
||||
latestWebhookTimestamp: pnid.connections.stripe.latest_webhook_timestamp
|
||||
}
|
||||
},
|
||||
marketingFlag: pnid.flags.marketing
|
||||
};
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { LoginRequest, LoginResponse, DeepPartial } from 'pretendo-grpc-ts/dist/account/login_rpc';
|
||||
|
||||
export async function login(_request: LoginRequest): Promise<DeepPartial<LoginResponse>> {
|
||||
throw new ServerError(Status.UNIMPLEMENTED, 'Login method not implemented');
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { RegisterPNIDRequest, DeepPartial } from 'pretendo-grpc-ts/dist/account/register_pnid_rpc';
|
||||
import { LoginResponse } from 'pretendo-grpc-ts/dist/account/login_rpc';
|
||||
|
||||
export async function registerPNID(_request: RegisterPNIDRequest): Promise<DeepPartial<LoginResponse>> {
|
||||
throw new ServerError(Status.UNIMPLEMENTED, 'Register PNID method not implemented');
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
import { createServer, Server } from 'nice-grpc';
|
||||
import { AccountServiceImplementation, AccountDefinition } from 'pretendo-grpc-ts/dist/account/account_service';
|
||||
import { AccountDefinition } from 'pretendo-grpc-ts/dist/account/account_service';
|
||||
import { APIDefinition } from 'pretendo-grpc-ts/dist/api/api_service';
|
||||
|
||||
import { apiKeyMiddleware as accountApiKeyMiddleware } from '@/services/grpc/account/api-key-middleware';
|
||||
import { apiKeyMiddleware as apiApiKeyMiddleware } from '@/services/grpc/api/api-key-middleware';
|
||||
import { authenticationMiddleware as apiAuthenticationMiddleware } from '@/services/grpc/api/authentication-middleware';
|
||||
|
||||
import { accountServiceImplementation } from '@/services/grpc/account/implementation';
|
||||
import { apiServiceImplementation } from '@/services/grpc/api/implementation';
|
||||
|
||||
import { config } from '@/config-manager';
|
||||
|
||||
import { apiKeyMiddleware } from '@/services/grpc/api-key-middleware';
|
||||
import { getUserData } from '@/services/grpc/get-user-data';
|
||||
import { login } from '@/services/grpc/login';
|
||||
import { registerPNID } from '@/services/grpc/register-pnid';
|
||||
|
||||
const accountServiceImplementation: AccountServiceImplementation = {
|
||||
getUserData,
|
||||
login,
|
||||
registerPNID,
|
||||
};
|
||||
|
||||
export async function startGRPCServer(): Promise<void> {
|
||||
const server: Server = createServer().use(apiKeyMiddleware);
|
||||
const server: Server = createServer();
|
||||
|
||||
server.add(AccountDefinition, accountServiceImplementation);
|
||||
server.with(accountApiKeyMiddleware).add(AccountDefinition, accountServiceImplementation);
|
||||
server.with(apiApiKeyMiddleware).with(apiAuthenticationMiddleware).add(APIDefinition, apiServiceImplementation);
|
||||
|
||||
await server.listen(`0.0.0.0:${config.grpc.port}`);
|
||||
}
|
||||
@@ -39,7 +39,10 @@ export interface Config {
|
||||
website_base: string;
|
||||
aes_key: string;
|
||||
grpc: {
|
||||
api_key: string;
|
||||
master_api_keys: {
|
||||
account: string;
|
||||
api: string;
|
||||
};
|
||||
port: number;
|
||||
};
|
||||
stripe?: {
|
||||
|
||||
Reference in New Issue
Block a user