feat: add totp login API (#416)
* fix: * removed hasReversedValue in playground * feat: * added totp methods in db's providers * adding totp in login method * feat: * added toggle in dashboard * fixing issue with env set * feat: * integrated totp * feat: * encrypted userid * added totp_verified column in user table * started test for totp * feat: * test cases totp * test-cases: * completed test cases * tested for all dbs * fixes: * return variable to snake case * import refactoring * feat: * created seperate folder for authenticator with totp subfolder * refactored code * created new table for authenticators * added recovery code for totp * feat: * adding functions to different db providers * feat: * added authenticators method for all db * feat: * added logic for updating mfa in user_profile update * fix: * merge conflict * fix: * resolved mongodb, dynamodb and arangodb test case bug * added new condition for checking first time totp user or not * feat: * changes in all respective db with authenticator * fix: * PR suggested changes * fix(cassandra): list users * Update verify otp * fix totp login api --------- Co-authored-by: lemonScaletech <anand.panigrahi@scaletech.xyz>
This commit is contained in:
parent
d8cd965004
commit
fe4c693324
668
app/package-lock.json
generated
668
app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
197
app/yarn.lock
197
app/yarn.lock
|
@ -16,21 +16,23 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@authorizerdev/authorizer-js" "^1.2.6"
|
"@authorizerdev/authorizer-js" "^1.2.6"
|
||||||
|
|
||||||
"@babel/code-frame@^7.16.7":
|
"@babel/code-frame@^7.22.13":
|
||||||
version "7.16.7"
|
version "7.22.13"
|
||||||
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz"
|
||||||
integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==
|
integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/highlight" "^7.16.7"
|
"@babel/highlight" "^7.22.13"
|
||||||
|
chalk "^2.4.2"
|
||||||
|
|
||||||
"@babel/generator@^7.16.8":
|
"@babel/generator@^7.23.0":
|
||||||
version "7.16.8"
|
version "7.23.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz"
|
resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz"
|
||||||
integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==
|
integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.8"
|
"@babel/types" "^7.23.0"
|
||||||
|
"@jridgewell/gen-mapping" "^0.3.2"
|
||||||
|
"@jridgewell/trace-mapping" "^0.3.17"
|
||||||
jsesc "^2.5.1"
|
jsesc "^2.5.1"
|
||||||
source-map "^0.5.0"
|
|
||||||
|
|
||||||
"@babel/helper-annotate-as-pure@^7.16.0":
|
"@babel/helper-annotate-as-pure@^7.16.0":
|
||||||
version "7.16.7"
|
version "7.16.7"
|
||||||
|
@ -39,35 +41,25 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.7"
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
"@babel/helper-environment-visitor@^7.16.7":
|
"@babel/helper-environment-visitor@^7.22.20":
|
||||||
version "7.16.7"
|
version "7.22.20"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz"
|
||||||
integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==
|
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
|
||||||
dependencies:
|
|
||||||
"@babel/types" "^7.16.7"
|
|
||||||
|
|
||||||
"@babel/helper-function-name@^7.16.7":
|
"@babel/helper-function-name@^7.23.0":
|
||||||
version "7.16.7"
|
version "7.23.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz"
|
||||||
integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==
|
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-get-function-arity" "^7.16.7"
|
"@babel/template" "^7.22.15"
|
||||||
"@babel/template" "^7.16.7"
|
"@babel/types" "^7.23.0"
|
||||||
"@babel/types" "^7.16.7"
|
|
||||||
|
|
||||||
"@babel/helper-get-function-arity@^7.16.7":
|
"@babel/helper-hoist-variables@^7.22.5":
|
||||||
version "7.16.7"
|
version "7.22.5"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz"
|
||||||
integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==
|
integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.7"
|
"@babel/types" "^7.22.5"
|
||||||
|
|
||||||
"@babel/helper-hoist-variables@^7.16.7":
|
|
||||||
version "7.16.7"
|
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz"
|
|
||||||
integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==
|
|
||||||
dependencies:
|
|
||||||
"@babel/types" "^7.16.7"
|
|
||||||
|
|
||||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.0":
|
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.0":
|
||||||
version "7.16.7"
|
version "7.16.7"
|
||||||
|
@ -76,31 +68,36 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.7"
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
"@babel/helper-split-export-declaration@^7.16.7":
|
"@babel/helper-split-export-declaration@^7.22.6":
|
||||||
version "7.16.7"
|
version "7.22.6"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz"
|
||||||
integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==
|
integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.7"
|
"@babel/types" "^7.22.5"
|
||||||
|
|
||||||
"@babel/helper-validator-identifier@^7.16.7":
|
"@babel/helper-string-parser@^7.22.5":
|
||||||
version "7.16.7"
|
version "7.22.5"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz"
|
||||||
integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
|
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
|
||||||
|
|
||||||
"@babel/highlight@^7.16.7":
|
"@babel/helper-validator-identifier@^7.22.20":
|
||||||
version "7.16.10"
|
version "7.22.20"
|
||||||
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz"
|
||||||
integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==
|
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
|
||||||
|
|
||||||
|
"@babel/highlight@^7.22.13":
|
||||||
|
version "7.22.20"
|
||||||
|
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz"
|
||||||
|
integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-validator-identifier" "^7.16.7"
|
"@babel/helper-validator-identifier" "^7.22.20"
|
||||||
chalk "^2.0.0"
|
chalk "^2.4.2"
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
|
|
||||||
"@babel/parser@^7.16.10", "@babel/parser@^7.16.7":
|
"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
|
||||||
version "7.16.12"
|
version "7.23.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.16.12.tgz"
|
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz"
|
||||||
integrity sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A==
|
integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
|
||||||
|
|
||||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1":
|
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1":
|
||||||
version "7.14.8"
|
version "7.14.8"
|
||||||
|
@ -109,37 +106,38 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/template@^7.16.7":
|
"@babel/template@^7.22.15":
|
||||||
version "7.16.7"
|
version "7.22.15"
|
||||||
resolved "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz"
|
||||||
integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==
|
integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.16.7"
|
"@babel/code-frame" "^7.22.13"
|
||||||
"@babel/parser" "^7.16.7"
|
"@babel/parser" "^7.22.15"
|
||||||
"@babel/types" "^7.16.7"
|
"@babel/types" "^7.22.15"
|
||||||
|
|
||||||
"@babel/traverse@^7.4.5":
|
"@babel/traverse@^7.4.5":
|
||||||
version "7.16.10"
|
version "7.23.2"
|
||||||
resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.10.tgz"
|
resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz"
|
||||||
integrity sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw==
|
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.16.7"
|
"@babel/code-frame" "^7.22.13"
|
||||||
"@babel/generator" "^7.16.8"
|
"@babel/generator" "^7.23.0"
|
||||||
"@babel/helper-environment-visitor" "^7.16.7"
|
"@babel/helper-environment-visitor" "^7.22.20"
|
||||||
"@babel/helper-function-name" "^7.16.7"
|
"@babel/helper-function-name" "^7.23.0"
|
||||||
"@babel/helper-hoist-variables" "^7.16.7"
|
"@babel/helper-hoist-variables" "^7.22.5"
|
||||||
"@babel/helper-split-export-declaration" "^7.16.7"
|
"@babel/helper-split-export-declaration" "^7.22.6"
|
||||||
"@babel/parser" "^7.16.10"
|
"@babel/parser" "^7.23.0"
|
||||||
"@babel/types" "^7.16.8"
|
"@babel/types" "^7.23.0"
|
||||||
debug "^4.1.0"
|
debug "^4.1.0"
|
||||||
globals "^11.1.0"
|
globals "^11.1.0"
|
||||||
|
|
||||||
"@babel/types@^7.16.7", "@babel/types@^7.16.8":
|
"@babel/types@^7.16.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
|
||||||
version "7.16.8"
|
version "7.23.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz"
|
resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz"
|
||||||
integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==
|
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-validator-identifier" "^7.16.7"
|
"@babel/helper-string-parser" "^7.22.5"
|
||||||
|
"@babel/helper-validator-identifier" "^7.22.20"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@emotion/is-prop-valid@^0.8.8":
|
"@emotion/is-prop-valid@^0.8.8":
|
||||||
|
@ -164,6 +162,38 @@
|
||||||
resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz"
|
resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz"
|
||||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||||
|
|
||||||
|
"@jridgewell/gen-mapping@^0.3.2":
|
||||||
|
version "0.3.3"
|
||||||
|
resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz"
|
||||||
|
integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
|
||||||
|
dependencies:
|
||||||
|
"@jridgewell/set-array" "^1.0.1"
|
||||||
|
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||||
|
"@jridgewell/trace-mapping" "^0.3.9"
|
||||||
|
|
||||||
|
"@jridgewell/resolve-uri@^3.1.0":
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz"
|
||||||
|
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
|
||||||
|
|
||||||
|
"@jridgewell/set-array@^1.0.1":
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz"
|
||||||
|
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
||||||
|
|
||||||
|
"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
|
||||||
|
version "1.4.15"
|
||||||
|
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"
|
||||||
|
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
|
||||||
|
|
||||||
|
"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
|
||||||
|
version "0.3.20"
|
||||||
|
resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz"
|
||||||
|
integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
|
||||||
|
dependencies:
|
||||||
|
"@jridgewell/resolve-uri" "^3.1.0"
|
||||||
|
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||||
|
|
||||||
"@types/history@*":
|
"@types/history@*":
|
||||||
version "4.7.9"
|
version "4.7.9"
|
||||||
resolved "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz"
|
resolved "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz"
|
||||||
|
@ -256,7 +286,7 @@ camelize@^1.0.0:
|
||||||
resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz"
|
||||||
integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
|
integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
|
||||||
|
|
||||||
chalk@^2.0.0:
|
chalk@^2.4.2:
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
||||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||||
|
@ -275,7 +305,7 @@ color-convert@^1.9.0:
|
||||||
color-name@1.1.3:
|
color-name@1.1.3:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
||||||
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
|
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||||
|
|
||||||
cross-fetch@^3.1.5:
|
cross-fetch@^3.1.5:
|
||||||
version "3.1.8"
|
version "3.1.8"
|
||||||
|
@ -318,7 +348,7 @@ esbuild@^0.12.17:
|
||||||
escape-string-regexp@^1.0.5:
|
escape-string-regexp@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
|
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
|
||||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
|
||||||
|
|
||||||
globals@^11.1.0:
|
globals@^11.1.0:
|
||||||
version "11.12.0"
|
version "11.12.0"
|
||||||
|
@ -516,11 +546,6 @@ shallowequal@^1.1.0:
|
||||||
resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz"
|
resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz"
|
||||||
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
|
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
|
||||||
|
|
||||||
source-map@^0.5.0:
|
|
||||||
version "0.5.7"
|
|
||||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
|
|
||||||
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
|
|
||||||
|
|
||||||
styled-components@^5.3.0, "styled-components@>= 2":
|
styled-components@^5.3.0, "styled-components@>= 2":
|
||||||
version "5.3.3"
|
version "5.3.3"
|
||||||
resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz"
|
resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz"
|
||||||
|
|
2191
dashboard/package-lock.json
generated
2191
dashboard/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -24,6 +24,8 @@ const Features = ({ variables, setVariables }: any) => {
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
|
|
||||||
<Flex>
|
<Flex>
|
||||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
<Text fontSize="sm">Email Verification:</Text>
|
<Text fontSize="sm">Email Verification:</Text>
|
||||||
|
@ -97,6 +99,7 @@ const Features = ({ variables, setVariables }: any) => {
|
||||||
also ignore the user MFA setting.
|
also ignore the user MFA setting.
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex justifyContent="start" mb={3}>
|
<Flex justifyContent="start" mb={3}>
|
||||||
<InputField
|
<InputField
|
||||||
variables={variables}
|
variables={variables}
|
||||||
|
@ -106,6 +109,46 @@ const Features = ({ variables, setVariables }: any) => {
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
|
{
|
||||||
|
!variables.DISABLE_MULTI_FACTOR_AUTHENTICATION &&
|
||||||
|
<Flex alignItems="center">
|
||||||
|
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||||
|
<Text fontSize="sm">TOTP:</Text>
|
||||||
|
<Text fontSize="x-small">
|
||||||
|
Note: to enable totp mfa
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex justifyContent="start" mb={3}>
|
||||||
|
<InputField
|
||||||
|
variables={variables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={SwitchInputType.DISABLE_TOTP_LOGIN}
|
||||||
|
hasReversedValue
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
}
|
||||||
|
{!variables.DISABLE_MULTI_FACTOR_AUTHENTICATION &&
|
||||||
|
<Flex alignItems="center">
|
||||||
|
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||||
|
<Text fontSize="sm">EMAIL OTP:</Text>
|
||||||
|
<Text fontSize="x-small">
|
||||||
|
Note: to enable email otp mfa
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex justifyContent="start" mb={3}>
|
||||||
|
<InputField
|
||||||
|
variables={variables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={SwitchInputType.DISABLE_MAIL_OTP_LOGIN}
|
||||||
|
hasReversedValue
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>}
|
||||||
|
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="center">
|
||||||
<Flex w="100%" alignItems="baseline" flexDir="column">
|
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||||
<Text fontSize="sm">
|
<Text fontSize="sm">
|
||||||
|
|
|
@ -85,6 +85,8 @@ export const SwitchInputType = {
|
||||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: 'DISABLE_MULTI_FACTOR_AUTHENTICATION',
|
DISABLE_MULTI_FACTOR_AUTHENTICATION: 'DISABLE_MULTI_FACTOR_AUTHENTICATION',
|
||||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: 'ENFORCE_MULTI_FACTOR_AUTHENTICATION',
|
ENFORCE_MULTI_FACTOR_AUTHENTICATION: 'ENFORCE_MULTI_FACTOR_AUTHENTICATION',
|
||||||
DISABLE_PLAYGROUND: 'DISABLE_PLAYGROUND',
|
DISABLE_PLAYGROUND: 'DISABLE_PLAYGROUND',
|
||||||
|
DISABLE_TOTP_LOGIN: 'DISABLE_TOTP_LOGIN',
|
||||||
|
DISABLE_MAIL_OTP_LOGIN: 'DISABLE_MAIL_OTP_LOGIN',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DateInputType = {
|
export const DateInputType = {
|
||||||
|
@ -169,6 +171,8 @@ export interface envVarTypes {
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: string;
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: string;
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_MODE: string;
|
DEFAULT_AUTHORIZE_RESPONSE_MODE: string;
|
||||||
DISABLE_PLAYGROUND: boolean;
|
DISABLE_PLAYGROUND: boolean;
|
||||||
|
DISABLE_TOTP_LOGIN: boolean;
|
||||||
|
DISABLE_MAIL_OTP_LOGIN: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const envSubViews = {
|
export const envSubViews = {
|
||||||
|
|
|
@ -74,6 +74,8 @@ export const EnvVariablesQuery = `
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_MODE
|
DEFAULT_AUTHORIZE_RESPONSE_MODE
|
||||||
DISABLE_PLAYGROUND
|
DISABLE_PLAYGROUND
|
||||||
|
DISABLE_TOTP_LOGIN
|
||||||
|
DISABLE_MAIL_OTP_LOGIN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -94,6 +94,8 @@ const Environment = () => {
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: '',
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: '',
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_MODE: '',
|
DEFAULT_AUTHORIZE_RESPONSE_MODE: '',
|
||||||
DISABLE_PLAYGROUND: false,
|
DISABLE_PLAYGROUND: false,
|
||||||
|
DISABLE_TOTP_LOGIN: false,
|
||||||
|
DISABLE_MAIL_OTP_LOGIN: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [fieldVisibility, setFieldVisibility] = React.useState<
|
const [fieldVisibility, setFieldVisibility] = React.useState<
|
||||||
|
|
|
@ -10,157 +10,155 @@
|
||||||
"@jridgewell/gen-mapping" "^0.3.0"
|
"@jridgewell/gen-mapping" "^0.3.0"
|
||||||
"@jridgewell/trace-mapping" "^0.3.9"
|
"@jridgewell/trace-mapping" "^0.3.9"
|
||||||
|
|
||||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.21.4":
|
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.22.13":
|
||||||
version "7.21.4"
|
version "7.22.13"
|
||||||
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz"
|
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz"
|
||||||
integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==
|
integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/highlight" "^7.18.6"
|
"@babel/highlight" "^7.22.13"
|
||||||
|
chalk "^2.4.2"
|
||||||
|
|
||||||
"@babel/compat-data@^7.21.4":
|
"@babel/compat-data@^7.22.9":
|
||||||
version "7.21.4"
|
version "7.23.3"
|
||||||
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz"
|
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz"
|
||||||
integrity sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==
|
integrity sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==
|
||||||
|
|
||||||
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0":
|
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0":
|
||||||
version "7.21.4"
|
version "7.23.3"
|
||||||
resolved "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz"
|
resolved "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz"
|
||||||
integrity sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==
|
integrity sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ampproject/remapping" "^2.2.0"
|
"@ampproject/remapping" "^2.2.0"
|
||||||
"@babel/code-frame" "^7.21.4"
|
"@babel/code-frame" "^7.22.13"
|
||||||
"@babel/generator" "^7.21.4"
|
"@babel/generator" "^7.23.3"
|
||||||
"@babel/helper-compilation-targets" "^7.21.4"
|
"@babel/helper-compilation-targets" "^7.22.15"
|
||||||
"@babel/helper-module-transforms" "^7.21.2"
|
"@babel/helper-module-transforms" "^7.23.3"
|
||||||
"@babel/helpers" "^7.21.0"
|
"@babel/helpers" "^7.23.2"
|
||||||
"@babel/parser" "^7.21.4"
|
"@babel/parser" "^7.23.3"
|
||||||
"@babel/template" "^7.20.7"
|
"@babel/template" "^7.22.15"
|
||||||
"@babel/traverse" "^7.21.4"
|
"@babel/traverse" "^7.23.3"
|
||||||
"@babel/types" "^7.21.4"
|
"@babel/types" "^7.23.3"
|
||||||
convert-source-map "^1.7.0"
|
convert-source-map "^2.0.0"
|
||||||
debug "^4.1.0"
|
debug "^4.1.0"
|
||||||
gensync "^1.0.0-beta.2"
|
gensync "^1.0.0-beta.2"
|
||||||
json5 "^2.2.2"
|
json5 "^2.2.3"
|
||||||
semver "^6.3.0"
|
semver "^6.3.1"
|
||||||
|
|
||||||
"@babel/generator@^7.21.4":
|
"@babel/generator@^7.23.3":
|
||||||
version "7.21.4"
|
version "7.23.3"
|
||||||
resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz"
|
resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz"
|
||||||
integrity sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==
|
integrity sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.21.4"
|
"@babel/types" "^7.23.3"
|
||||||
"@jridgewell/gen-mapping" "^0.3.2"
|
"@jridgewell/gen-mapping" "^0.3.2"
|
||||||
"@jridgewell/trace-mapping" "^0.3.17"
|
"@jridgewell/trace-mapping" "^0.3.17"
|
||||||
jsesc "^2.5.1"
|
jsesc "^2.5.1"
|
||||||
|
|
||||||
"@babel/helper-compilation-targets@^7.21.4":
|
"@babel/helper-compilation-targets@^7.22.15":
|
||||||
version "7.21.4"
|
version "7.22.15"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz"
|
||||||
integrity sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==
|
integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/compat-data" "^7.21.4"
|
"@babel/compat-data" "^7.22.9"
|
||||||
"@babel/helper-validator-option" "^7.21.0"
|
"@babel/helper-validator-option" "^7.22.15"
|
||||||
browserslist "^4.21.3"
|
browserslist "^4.21.9"
|
||||||
lru-cache "^5.1.1"
|
lru-cache "^5.1.1"
|
||||||
semver "^6.3.0"
|
semver "^6.3.1"
|
||||||
|
|
||||||
"@babel/helper-environment-visitor@^7.18.9":
|
"@babel/helper-environment-visitor@^7.22.20":
|
||||||
version "7.18.9"
|
version "7.22.20"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz"
|
||||||
integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
|
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
|
||||||
|
|
||||||
"@babel/helper-function-name@^7.21.0":
|
"@babel/helper-function-name@^7.23.0":
|
||||||
version "7.21.0"
|
version "7.23.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz"
|
||||||
integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==
|
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/template" "^7.20.7"
|
"@babel/template" "^7.22.15"
|
||||||
"@babel/types" "^7.21.0"
|
"@babel/types" "^7.23.0"
|
||||||
|
|
||||||
"@babel/helper-hoist-variables@^7.18.6":
|
"@babel/helper-hoist-variables@^7.22.5":
|
||||||
version "7.18.6"
|
version "7.22.5"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz"
|
||||||
integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
|
integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.18.6"
|
"@babel/types" "^7.22.5"
|
||||||
|
|
||||||
"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.18.6":
|
"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.22.15":
|
||||||
version "7.18.6"
|
version "7.22.15"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz"
|
||||||
integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
|
integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.18.6"
|
"@babel/types" "^7.22.15"
|
||||||
|
|
||||||
"@babel/helper-module-transforms@^7.21.2":
|
"@babel/helper-module-transforms@^7.23.3":
|
||||||
version "7.21.2"
|
version "7.23.3"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz"
|
||||||
integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==
|
integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-environment-visitor" "^7.18.9"
|
"@babel/helper-environment-visitor" "^7.22.20"
|
||||||
"@babel/helper-module-imports" "^7.18.6"
|
"@babel/helper-module-imports" "^7.22.15"
|
||||||
"@babel/helper-simple-access" "^7.20.2"
|
"@babel/helper-simple-access" "^7.22.5"
|
||||||
"@babel/helper-split-export-declaration" "^7.18.6"
|
"@babel/helper-split-export-declaration" "^7.22.6"
|
||||||
"@babel/helper-validator-identifier" "^7.19.1"
|
"@babel/helper-validator-identifier" "^7.22.20"
|
||||||
"@babel/template" "^7.20.7"
|
|
||||||
"@babel/traverse" "^7.21.2"
|
|
||||||
"@babel/types" "^7.21.2"
|
|
||||||
|
|
||||||
"@babel/helper-plugin-utils@^7.16.5":
|
"@babel/helper-plugin-utils@^7.16.5":
|
||||||
version "7.16.5"
|
version "7.16.5"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz"
|
||||||
integrity sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==
|
integrity sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==
|
||||||
|
|
||||||
"@babel/helper-simple-access@^7.20.2":
|
"@babel/helper-simple-access@^7.22.5":
|
||||||
version "7.20.2"
|
version "7.22.5"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz"
|
||||||
integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==
|
integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.20.2"
|
"@babel/types" "^7.22.5"
|
||||||
|
|
||||||
"@babel/helper-split-export-declaration@^7.18.6":
|
"@babel/helper-split-export-declaration@^7.22.6":
|
||||||
version "7.18.6"
|
version "7.22.6"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz"
|
||||||
integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
|
integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.18.6"
|
"@babel/types" "^7.22.5"
|
||||||
|
|
||||||
"@babel/helper-string-parser@^7.19.4":
|
"@babel/helper-string-parser@^7.22.5":
|
||||||
version "7.19.4"
|
version "7.22.5"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz"
|
||||||
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
|
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
|
||||||
|
|
||||||
"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
|
"@babel/helper-validator-identifier@^7.22.20":
|
||||||
version "7.19.1"
|
version "7.22.20"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz"
|
||||||
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
|
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
|
||||||
|
|
||||||
"@babel/helper-validator-option@^7.21.0":
|
"@babel/helper-validator-option@^7.22.15":
|
||||||
version "7.21.0"
|
version "7.22.15"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz"
|
||||||
integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==
|
integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==
|
||||||
|
|
||||||
"@babel/helpers@^7.21.0":
|
"@babel/helpers@^7.23.2":
|
||||||
version "7.21.0"
|
version "7.23.2"
|
||||||
resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz"
|
resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz"
|
||||||
integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==
|
integrity sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/template" "^7.20.7"
|
"@babel/template" "^7.22.15"
|
||||||
"@babel/traverse" "^7.21.0"
|
"@babel/traverse" "^7.23.2"
|
||||||
"@babel/types" "^7.21.0"
|
"@babel/types" "^7.23.0"
|
||||||
|
|
||||||
"@babel/highlight@^7.18.6":
|
"@babel/highlight@^7.22.13":
|
||||||
version "7.18.6"
|
version "7.22.20"
|
||||||
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz"
|
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz"
|
||||||
integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
|
integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-validator-identifier" "^7.18.6"
|
"@babel/helper-validator-identifier" "^7.22.20"
|
||||||
chalk "^2.0.0"
|
chalk "^2.4.2"
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
|
|
||||||
"@babel/parser@^7.20.7", "@babel/parser@^7.21.4":
|
"@babel/parser@^7.22.15", "@babel/parser@^7.23.3":
|
||||||
version "7.21.4"
|
version "7.23.3"
|
||||||
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz"
|
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz"
|
||||||
integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==
|
integrity sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==
|
||||||
|
|
||||||
"@babel/plugin-syntax-jsx@^7.12.13":
|
"@babel/plugin-syntax-jsx@^7.12.13":
|
||||||
version "7.16.5"
|
version "7.16.5"
|
||||||
|
@ -176,38 +174,38 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/template@^7.20.7":
|
"@babel/template@^7.22.15":
|
||||||
version "7.20.7"
|
version "7.22.15"
|
||||||
resolved "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz"
|
||||||
integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==
|
integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.18.6"
|
"@babel/code-frame" "^7.22.13"
|
||||||
"@babel/parser" "^7.20.7"
|
"@babel/parser" "^7.22.15"
|
||||||
"@babel/types" "^7.20.7"
|
"@babel/types" "^7.22.15"
|
||||||
|
|
||||||
"@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.4":
|
"@babel/traverse@^7.23.2", "@babel/traverse@^7.23.3":
|
||||||
version "7.21.4"
|
version "7.23.3"
|
||||||
resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz"
|
resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz"
|
||||||
integrity sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==
|
integrity sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.21.4"
|
"@babel/code-frame" "^7.22.13"
|
||||||
"@babel/generator" "^7.21.4"
|
"@babel/generator" "^7.23.3"
|
||||||
"@babel/helper-environment-visitor" "^7.18.9"
|
"@babel/helper-environment-visitor" "^7.22.20"
|
||||||
"@babel/helper-function-name" "^7.21.0"
|
"@babel/helper-function-name" "^7.23.0"
|
||||||
"@babel/helper-hoist-variables" "^7.18.6"
|
"@babel/helper-hoist-variables" "^7.22.5"
|
||||||
"@babel/helper-split-export-declaration" "^7.18.6"
|
"@babel/helper-split-export-declaration" "^7.22.6"
|
||||||
"@babel/parser" "^7.21.4"
|
"@babel/parser" "^7.23.3"
|
||||||
"@babel/types" "^7.21.4"
|
"@babel/types" "^7.23.3"
|
||||||
debug "^4.1.0"
|
debug "^4.1.0"
|
||||||
globals "^11.1.0"
|
globals "^11.1.0"
|
||||||
|
|
||||||
"@babel/types@^7.18.6", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.21.4":
|
"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.3":
|
||||||
version "7.21.4"
|
version "7.23.3"
|
||||||
resolved "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz"
|
resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz"
|
||||||
integrity sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==
|
integrity sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-string-parser" "^7.19.4"
|
"@babel/helper-string-parser" "^7.22.5"
|
||||||
"@babel/helper-validator-identifier" "^7.19.1"
|
"@babel/helper-validator-identifier" "^7.22.20"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@chakra-ui/accordion@1.4.2":
|
"@chakra-ui/accordion@1.4.2":
|
||||||
|
@ -896,33 +894,28 @@
|
||||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||||
"@jridgewell/trace-mapping" "^0.3.9"
|
"@jridgewell/trace-mapping" "^0.3.9"
|
||||||
|
|
||||||
"@jridgewell/resolve-uri@3.1.0":
|
"@jridgewell/resolve-uri@^3.1.0":
|
||||||
version "3.1.0"
|
version "3.1.1"
|
||||||
resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz"
|
resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz"
|
||||||
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
|
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
|
||||||
|
|
||||||
"@jridgewell/set-array@^1.0.1":
|
"@jridgewell/set-array@^1.0.1":
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz"
|
resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz"
|
||||||
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
||||||
|
|
||||||
"@jridgewell/sourcemap-codec@^1.4.10":
|
"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
|
||||||
version "1.4.15"
|
version "1.4.15"
|
||||||
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"
|
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"
|
||||||
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
|
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
|
||||||
|
|
||||||
"@jridgewell/sourcemap-codec@1.4.14":
|
|
||||||
version "1.4.14"
|
|
||||||
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz"
|
|
||||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
|
||||||
|
|
||||||
"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
|
"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
|
||||||
version "0.3.18"
|
version "0.3.20"
|
||||||
resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz"
|
resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz"
|
||||||
integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==
|
integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jridgewell/resolve-uri" "3.1.0"
|
"@jridgewell/resolve-uri" "^3.1.0"
|
||||||
"@jridgewell/sourcemap-codec" "1.4.14"
|
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||||
|
|
||||||
"@popperjs/core@^2.9.3":
|
"@popperjs/core@^2.9.3":
|
||||||
version "2.11.0"
|
version "2.11.0"
|
||||||
|
@ -1074,27 +1067,27 @@ babel-plugin-macros@^2.6.1:
|
||||||
cosmiconfig "^6.0.0"
|
cosmiconfig "^6.0.0"
|
||||||
resolve "^1.12.0"
|
resolve "^1.12.0"
|
||||||
|
|
||||||
browserslist@^4.21.3, "browserslist@>= 4.21.0":
|
browserslist@^4.21.9, "browserslist@>= 4.21.0":
|
||||||
version "4.21.5"
|
version "4.22.1"
|
||||||
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz"
|
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz"
|
||||||
integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==
|
integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
caniuse-lite "^1.0.30001449"
|
caniuse-lite "^1.0.30001541"
|
||||||
electron-to-chromium "^1.4.284"
|
electron-to-chromium "^1.4.535"
|
||||||
node-releases "^2.0.8"
|
node-releases "^2.0.13"
|
||||||
update-browserslist-db "^1.0.10"
|
update-browserslist-db "^1.0.13"
|
||||||
|
|
||||||
callsites@^3.0.0:
|
callsites@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
|
resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
|
||||||
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001449:
|
caniuse-lite@^1.0.30001541:
|
||||||
version "1.0.30001480"
|
version "1.0.30001561"
|
||||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001480.tgz"
|
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz"
|
||||||
integrity sha512-q7cpoPPvZYgtyC4VaBSN0Bt+PJ4c4EYRf0DrduInOz2SkFpHD5p3LnvEpqBp7UnJn+8x1Ogl1s38saUxe+ihQQ==
|
integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==
|
||||||
|
|
||||||
chalk@^2.0.0:
|
chalk@^2.4.2:
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
||||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||||
|
@ -1125,13 +1118,18 @@ compute-scroll-into-view@1.0.14:
|
||||||
resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz"
|
resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz"
|
||||||
integrity sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ==
|
integrity sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ==
|
||||||
|
|
||||||
convert-source-map@^1.5.0, convert-source-map@^1.7.0:
|
convert-source-map@^1.5.0:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz"
|
resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz"
|
||||||
integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
|
integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer "~5.1.1"
|
safe-buffer "~5.1.1"
|
||||||
|
|
||||||
|
convert-source-map@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz"
|
||||||
|
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
|
||||||
|
|
||||||
copy-to-clipboard@3.3.1:
|
copy-to-clipboard@3.3.1:
|
||||||
version "3.3.1"
|
version "3.3.1"
|
||||||
resolved "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz"
|
resolved "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz"
|
||||||
|
@ -1140,9 +1138,9 @@ copy-to-clipboard@3.3.1:
|
||||||
toggle-selection "^1.0.6"
|
toggle-selection "^1.0.6"
|
||||||
|
|
||||||
core-js@^3.6.4:
|
core-js@^3.6.4:
|
||||||
version "3.30.1"
|
version "3.33.2"
|
||||||
resolved "https://registry.npmjs.org/core-js/-/core-js-3.30.1.tgz"
|
resolved "https://registry.npmjs.org/core-js/-/core-js-3.33.2.tgz"
|
||||||
integrity sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==
|
integrity sha512-XeBzWI6QL3nJQiHmdzbAOiMYqjrb7hwU7A39Qhvd/POSa/t9E1AeZyEZx3fNvp/vtM8zXwhoL0FsiS0hD0pruQ==
|
||||||
|
|
||||||
cosmiconfig@^6.0.0:
|
cosmiconfig@^6.0.0:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
|
@ -1156,11 +1154,11 @@ cosmiconfig@^6.0.0:
|
||||||
yaml "^1.7.2"
|
yaml "^1.7.2"
|
||||||
|
|
||||||
cross-fetch@^3.0.4:
|
cross-fetch@^3.0.4:
|
||||||
version "3.1.5"
|
version "3.1.8"
|
||||||
resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz"
|
resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz"
|
||||||
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
|
integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==
|
||||||
dependencies:
|
dependencies:
|
||||||
node-fetch "2.6.7"
|
node-fetch "^2.6.12"
|
||||||
|
|
||||||
css-box-model@1.2.1:
|
css-box-model@1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
|
@ -1210,10 +1208,10 @@ draftjs-utils@^0.10.2:
|
||||||
resolved "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz"
|
resolved "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz"
|
||||||
integrity sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg==
|
integrity sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg==
|
||||||
|
|
||||||
electron-to-chromium@^1.4.284:
|
electron-to-chromium@^1.4.535:
|
||||||
version "1.4.365"
|
version "1.4.581"
|
||||||
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.365.tgz"
|
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.581.tgz"
|
||||||
integrity sha512-FRHZO+1tUNO4TOPXmlxetkoaIY8uwHzd1kKopK/Gx2SKn1L47wJXWD44wxP5CGRyyP98z/c8e1eBzJrgPeiBOg==
|
integrity sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw==
|
||||||
|
|
||||||
error-ex@^1.3.1:
|
error-ex@^1.3.1:
|
||||||
version "1.3.2"
|
version "1.3.2"
|
||||||
|
@ -1405,9 +1403,9 @@ immutable@~3.7.4:
|
||||||
integrity sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==
|
integrity sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==
|
||||||
|
|
||||||
"immutable@3.x.x || 4.x.x":
|
"immutable@3.x.x || 4.x.x":
|
||||||
version "4.3.0"
|
version "4.3.4"
|
||||||
resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz"
|
resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz"
|
||||||
integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==
|
integrity sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==
|
||||||
|
|
||||||
import-fresh@^3.1.0:
|
import-fresh@^3.1.0:
|
||||||
version "3.3.0"
|
version "3.3.0"
|
||||||
|
@ -1451,7 +1449,7 @@ json-parse-even-better-errors@^2.3.0:
|
||||||
resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz"
|
resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz"
|
||||||
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
|
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
|
||||||
|
|
||||||
json5@^2.2.2:
|
json5@^2.2.3:
|
||||||
version "2.2.3"
|
version "2.2.3"
|
||||||
resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz"
|
resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz"
|
||||||
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
||||||
|
@ -1497,17 +1495,17 @@ ms@2.1.2:
|
||||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
||||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||||
|
|
||||||
node-fetch@2.6.7:
|
node-fetch@^2.6.12:
|
||||||
version "2.6.7"
|
version "2.7.0"
|
||||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz"
|
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz"
|
||||||
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-url "^5.0.0"
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
node-releases@^2.0.8:
|
node-releases@^2.0.13:
|
||||||
version "2.0.10"
|
version "2.0.13"
|
||||||
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz"
|
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz"
|
||||||
integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==
|
integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==
|
||||||
|
|
||||||
object-assign@^4.1.0, object-assign@^4.1.1:
|
object-assign@^4.1.0, object-assign@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
|
@ -1739,7 +1737,7 @@ scheduler@^0.20.2:
|
||||||
loose-envify "^1.1.0"
|
loose-envify "^1.1.0"
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
|
|
||||||
semver@^6.3.0:
|
semver@^6.3.1:
|
||||||
version "6.3.1"
|
version "6.3.1"
|
||||||
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
|
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
|
||||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||||
|
@ -1815,19 +1813,19 @@ typescript@^4.5.4:
|
||||||
integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==
|
integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==
|
||||||
|
|
||||||
ua-parser-js@^0.7.18:
|
ua-parser-js@^0.7.18:
|
||||||
version "0.7.35"
|
version "0.7.37"
|
||||||
resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz"
|
resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz"
|
||||||
integrity sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==
|
integrity sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==
|
||||||
|
|
||||||
uc.micro@^1.0.1:
|
uc.micro@^1.0.1:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz"
|
resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz"
|
||||||
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
|
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
|
||||||
|
|
||||||
update-browserslist-db@^1.0.10:
|
update-browserslist-db@^1.0.13:
|
||||||
version "1.0.11"
|
version "1.0.13"
|
||||||
resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz"
|
resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz"
|
||||||
integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==
|
integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==
|
||||||
dependencies:
|
dependencies:
|
||||||
escalade "^3.1.1"
|
escalade "^3.1.1"
|
||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
|
|
23
server/authenticators/providers/providers.go
Normal file
23
server/authenticators/providers/providers.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package providers
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// AuthenticatorConfig defines authenticator config
|
||||||
|
type AuthenticatorConfig struct {
|
||||||
|
// ScannerImage is the base64 of QR code image
|
||||||
|
ScannerImage string
|
||||||
|
// Secrets is the secret key
|
||||||
|
Secret string
|
||||||
|
// RecoveryCode is the secret key
|
||||||
|
RecoveryCodes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider defines authenticators provider
|
||||||
|
type Provider interface {
|
||||||
|
// Generate totp: to generate totp, store secret into db and returns base64 of QR code image
|
||||||
|
Generate(ctx context.Context, id string) (*AuthenticatorConfig, error)
|
||||||
|
// Validate totp: user passcode with secret stored in our db
|
||||||
|
Validate(ctx context.Context, passcode string, id string) (bool, error)
|
||||||
|
// RecoveryCode totp: gives a recovery code for first time user
|
||||||
|
RecoveryCode(ctx context.Context, id string) (*string, error)
|
||||||
|
}
|
23
server/authenticators/providers/totp/provider.go
Normal file
23
server/authenticators/providers/totp/provider.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package totp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type provider struct {
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOTPConfig defines totp config
|
||||||
|
type TOTPConfig struct {
|
||||||
|
ScannerImage string
|
||||||
|
Secret string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProvider returns a new totp provider
|
||||||
|
func NewProvider() (*provider, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
return &provider{
|
||||||
|
ctx: ctx,
|
||||||
|
}, nil
|
||||||
|
}
|
128
server/authenticators/providers/totp/totp.go
Normal file
128
server/authenticators/providers/totp/totp.go
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
package totp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"image/png"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/pquerna/otp/totp"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/authenticators/providers"
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/crypto"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Generate generates a Time-Based One-Time Password (TOTP) for a user and returns the base64-encoded QR code for frontend display.
|
||||||
|
func (p *provider) Generate(ctx context.Context, id string) (*providers.AuthenticatorConfig, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
//get user details
|
||||||
|
user, err := db.Provider.GetUserByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error while getting user details")
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate totp, Authenticators hash is valid for 30 seconds
|
||||||
|
key, err := totp.Generate(totp.GenerateOpts{
|
||||||
|
Issuer: "authorizer",
|
||||||
|
AccountName: refs.StringValue(user.Email),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error while genrating totp")
|
||||||
|
}
|
||||||
|
|
||||||
|
//generating image for key and encoding to base64 for displaying in frontend
|
||||||
|
img, err := key.Image(200, 200)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error while creating qr image for totp")
|
||||||
|
}
|
||||||
|
png.Encode(&buf, img)
|
||||||
|
encodedText := crypto.EncryptB64(buf.String())
|
||||||
|
|
||||||
|
secret := key.Secret()
|
||||||
|
recoveryCodes := []string{}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
recoveryCodes = append(recoveryCodes, uuid.NewString())
|
||||||
|
}
|
||||||
|
// Converting recoveryCodes to string
|
||||||
|
recoverCodesMap := map[string]bool{}
|
||||||
|
for i := 0; i < len(recoveryCodes); i++ {
|
||||||
|
recoverCodesMap[recoveryCodes[i]] = false
|
||||||
|
}
|
||||||
|
// Converting recoveryCodesMap to string
|
||||||
|
jsonData, err := json.Marshal(recoverCodesMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error while converting recoveryCodes to string")
|
||||||
|
}
|
||||||
|
recoveryCodesString := string(jsonData)
|
||||||
|
|
||||||
|
totpModel := &models.Authenticator{
|
||||||
|
Secret: secret,
|
||||||
|
RecoveryCodes: refs.NewStringRef(recoveryCodesString),
|
||||||
|
UserID: user.ID,
|
||||||
|
Method: constants.EnvKeyTOTPAuthenticator,
|
||||||
|
}
|
||||||
|
_, err = db.Provider.AddAuthenticator(ctx, totpModel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error while inserting into totp table")
|
||||||
|
}
|
||||||
|
return &providers.AuthenticatorConfig{
|
||||||
|
ScannerImage: encodedText,
|
||||||
|
Secret: secret,
|
||||||
|
RecoveryCodes: recoveryCodes,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates a Time-Based One-Time Password (TOTP) against the stored TOTP secret for a user.
|
||||||
|
func (p *provider) Validate(ctx context.Context, passcode string, userID string) (bool, error) {
|
||||||
|
// get totp details
|
||||||
|
totpModel, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, userID, constants.EnvKeyTOTPAuthenticator)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("error while getting totp details from authenticators")
|
||||||
|
}
|
||||||
|
|
||||||
|
status := totp.Validate(passcode, totpModel.Secret)
|
||||||
|
// checks if user not signed in for totp and totp code is correct then VerifiedAt will be stored in db
|
||||||
|
if totpModel.VerifiedAt == nil {
|
||||||
|
if status {
|
||||||
|
timeNow := time.Now().Unix()
|
||||||
|
totpModel.VerifiedAt = &timeNow
|
||||||
|
_, err = db.Provider.UpdateAuthenticator(ctx, totpModel)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("error while updaing authenticator table for totp")
|
||||||
|
}
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecoveryCode generates a recovery code for a user's TOTP authentication, if not already verified.
|
||||||
|
func (p *provider) RecoveryCode(ctx context.Context, id string) (*string, error) {
|
||||||
|
// get totp details
|
||||||
|
// totpModel, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, id, constants.EnvKeyTOTPAuthenticator)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, fmt.Errorf("error while getting totp details from authenticators")
|
||||||
|
// }
|
||||||
|
// //TODO *totpModel.RecoveryCode == "null" used to just verify couchbase recoveryCode value to be nil
|
||||||
|
// // have to find another way round
|
||||||
|
// if totpModel.RecoveryCode == nil || *totpModel.RecoveryCode == "null" {
|
||||||
|
// recoveryCode := utils.GenerateTOTPRecoveryCode()
|
||||||
|
// totpModel.RecoveryCode = &recoveryCode
|
||||||
|
|
||||||
|
// _, err = db.Provider.UpdateAuthenticator(ctx, totpModel)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, fmt.Errorf("error while updaing authenticator table for totp")
|
||||||
|
// }
|
||||||
|
// return &recoveryCode, nil
|
||||||
|
// }
|
||||||
|
return nil, nil
|
||||||
|
}
|
26
server/authenticators/totp_store.go
Normal file
26
server/authenticators/totp_store.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package authenticators
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/authorizerdev/authorizer/server/authenticators/providers"
|
||||||
|
"github.com/authorizerdev/authorizer/server/authenticators/providers/totp"
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Provider is the global authenticators provider.
|
||||||
|
var Provider providers.Provider
|
||||||
|
|
||||||
|
// InitTOTPStore initializes the TOTP authenticator store if it's not disabled in the environment variables.
|
||||||
|
// It sets the global Provider variable to a new TOTP provider.
|
||||||
|
func InitTOTPStore() error {
|
||||||
|
var err error
|
||||||
|
isTOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin)
|
||||||
|
|
||||||
|
if !isTOTPEnvServiceDisabled {
|
||||||
|
Provider, err = totp.NewProvider()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
7
server/constants/authenticator_method.go
Normal file
7
server/constants/authenticator_method.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package constants
|
||||||
|
|
||||||
|
// Authenticators Methods
|
||||||
|
const (
|
||||||
|
// EnvKeyTOTPAuthenticator key for env variable TOTP
|
||||||
|
EnvKeyTOTPAuthenticator = "totp"
|
||||||
|
)
|
|
@ -160,6 +160,12 @@ const (
|
||||||
// EnvKeyDisableMultiFactorAuthentication is key for env variable DISABLE_MULTI_FACTOR_AUTHENTICATION
|
// EnvKeyDisableMultiFactorAuthentication is key for env variable DISABLE_MULTI_FACTOR_AUTHENTICATION
|
||||||
// this variable is used to completely disable multi factor authentication. It will have no effect on profile preference
|
// this variable is used to completely disable multi factor authentication. It will have no effect on profile preference
|
||||||
EnvKeyDisableMultiFactorAuthentication = "DISABLE_MULTI_FACTOR_AUTHENTICATION"
|
EnvKeyDisableMultiFactorAuthentication = "DISABLE_MULTI_FACTOR_AUTHENTICATION"
|
||||||
|
// EnvKeyDisableTOTPLogin is key for env variable DISABLE_TOTP_LOGIN
|
||||||
|
// this variable is used to completely disable totp verification
|
||||||
|
EnvKeyDisableTOTPLogin = "DISABLE_TOTP_LOGIN"
|
||||||
|
// EnvKeyDisableMailOTPLogin is key for env variable DISABLE_MAIL_OTP_LOGIN
|
||||||
|
// this variable is used to completely disable totp verification
|
||||||
|
EnvKeyDisableMailOTPLogin = "DISABLE_MAIL_OTP_LOGIN"
|
||||||
// EnvKeyDisablePhoneVerification is key for env variable DISABLE_PHONE_VERIFICATION
|
// EnvKeyDisablePhoneVerification is key for env variable DISABLE_PHONE_VERIFICATION
|
||||||
// this variable is used to disable phone verification
|
// this variable is used to disable phone verification
|
||||||
EnvKeyDisablePhoneVerification = "DISABLE_PHONE_VERIFICATION"
|
EnvKeyDisablePhoneVerification = "DISABLE_PHONE_VERIFICATION"
|
||||||
|
|
|
@ -3,7 +3,9 @@ package crypto
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
@ -116,3 +118,24 @@ func AsRSAStr(privateKey *rsa.PrivateKey, publickKey *rsa.PublicKey) (string, st
|
||||||
|
|
||||||
return privParsedPem, pubParsedPem, nil
|
return privParsedPem, pubParsedPem, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EncryptRSA(message string, key rsa.PublicKey) (string, error) {
|
||||||
|
label := []byte("OAEP Encrypted")
|
||||||
|
rng := rand.Reader
|
||||||
|
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rng, &key, []byte(message), label)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecryptRSA(cipherText string, privateKey rsa.PrivateKey) (string, error) {
|
||||||
|
ct, _ := base64.StdEncoding.DecodeString(cipherText)
|
||||||
|
label := []byte("OAEP Encrypted")
|
||||||
|
rng := rand.Reader
|
||||||
|
plaintext, err := rsa.DecryptOAEP(sha256.New(), rng, &privateKey, ct, label)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(plaintext), nil
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ func InitDB() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isArangoDB {
|
if isArangoDB {
|
||||||
log.Info("Initializing ArangoDB Driver")
|
log.Info("Initializing ArangoDB Driver")
|
||||||
Provider, err = arangodb.NewProvider()
|
Provider, err = arangodb.NewProvider()
|
||||||
|
|
16
server/db/models/authenticators.go
Normal file
16
server/db/models/authenticators.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
// Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation
|
||||||
|
|
||||||
|
// Authenticators model for db
|
||||||
|
type Authenticator struct {
|
||||||
|
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||||
|
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||||
|
UserID string `gorm:"type:char(36)" json:"user_id" bson:"user_id" cql:"user_id" dynamo:"user_id" index:"user_id,hash"`
|
||||||
|
Method string `json:"method" bson:"method" cql:"method" dynamo:"method"`
|
||||||
|
Secret string `json:"secret" bson:"secret" cql:"secret" dynamo:"secret"`
|
||||||
|
RecoveryCodes *string `json:"recovery_codes" bson:"recovery_codes" cql:"recovery_codes" dynamo:"recovery_codes"`
|
||||||
|
VerifiedAt *int64 `json:"verified_at" bson:"verified_at" cql:"verified_at" dynamo:"verified_at"`
|
||||||
|
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||||
|
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
// Collections / Tables available for authorizer in the database
|
// CollectionList / Tables available for authorizer in the database
|
||||||
type CollectionList struct {
|
type CollectionList struct {
|
||||||
User string
|
User string
|
||||||
VerificationRequest string
|
VerificationRequest string
|
||||||
|
@ -11,6 +11,7 @@ type CollectionList struct {
|
||||||
EmailTemplate string
|
EmailTemplate string
|
||||||
OTP string
|
OTP string
|
||||||
SMSVerificationRequest string
|
SMSVerificationRequest string
|
||||||
|
Authenticators string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -27,5 +28,6 @@ var (
|
||||||
EmailTemplate: Prefix + "email_templates",
|
EmailTemplate: Prefix + "email_templates",
|
||||||
OTP: Prefix + "otps",
|
OTP: Prefix + "otps",
|
||||||
SMSVerificationRequest: Prefix + "sms_verification_requests",
|
SMSVerificationRequest: Prefix + "sms_verification_requests",
|
||||||
|
Authenticators: Prefix + "authenticators",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
78
server/db/providers/arangodb/authenticator.go
Normal file
78
server/db/providers/arangodb/authenticator.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package arangodb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
arangoDriver "github.com/arangodb/go-driver"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticators.Key = authenticators.ID
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
authenticatorsCollection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
||||||
|
meta, err := authenticatorsCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
authenticators.Key = meta.Key
|
||||||
|
authenticators.ID = meta.ID.String()
|
||||||
|
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
collection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
||||||
|
meta, err := collection.UpdateDocument(ctx, authenticators.Key, authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticators.Key = meta.Key
|
||||||
|
authenticators.ID = meta.ID.String()
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators *models.Authenticator
|
||||||
|
query := fmt.Sprintf("FOR d in %s FILTER d.user_id == @user_id AND d.method == @method LIMIT 1 RETURN d", models.Collections.Authenticators)
|
||||||
|
bindVars := map[string]interface{}{
|
||||||
|
"user_id": userId,
|
||||||
|
"method": authenticatorType,
|
||||||
|
}
|
||||||
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
defer cursor.Close()
|
||||||
|
for {
|
||||||
|
if !cursor.HasMore() {
|
||||||
|
if authenticators == nil {
|
||||||
|
return authenticators, fmt.Errorf("authenticator not found")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_, err := cursor.ReadDocument(ctx, &authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
|
@ -186,6 +186,7 @@ func NewProvider() (*provider, error) {
|
||||||
webhookLogCollection.EnsureHashIndex(ctx, []string{"webhook_id"}, &arangoDriver.EnsureHashIndexOptions{
|
webhookLogCollection.EnsureHashIndex(ctx, []string{"webhook_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
emailTemplateCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.EmailTemplate)
|
emailTemplateCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.EmailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -204,6 +205,7 @@ func NewProvider() (*provider, error) {
|
||||||
Unique: true,
|
Unique: true,
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
otpCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.OTP)
|
otpCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.OTP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -222,6 +224,26 @@ func NewProvider() (*provider, error) {
|
||||||
Unique: true,
|
Unique: true,
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//authenticators table define
|
||||||
|
authenticatorsCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !authenticatorsCollectionExists {
|
||||||
|
_, err = arangodb.CreateCollection(ctx, models.Collections.Authenticators, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
authenticatorsCollection, err := arangodb.Collection(ctx, models.Collections.Authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
authenticatorsCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
|
Sparse: true,
|
||||||
|
})
|
||||||
|
|
||||||
return &provider{
|
return &provider{
|
||||||
db: arangodb,
|
db: arangodb,
|
||||||
}, err
|
}, err
|
||||||
|
|
133
server/db/providers/cassandradb/authenticator.go
Normal file
133
server/db/providers/cassandradb/authenticator.go
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
package cassandradb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gocql/gocql"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
bytes, err := json.Marshal(authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
|
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||||
|
decoder.UseNumber()
|
||||||
|
authenticatorsMap := map[string]interface{}{}
|
||||||
|
err = decoder.Decode(&authenticatorsMap)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := "("
|
||||||
|
values := "("
|
||||||
|
for key, value := range authenticatorsMap {
|
||||||
|
if value != nil {
|
||||||
|
if key == "_id" {
|
||||||
|
fields += "id,"
|
||||||
|
} else {
|
||||||
|
fields += key + ","
|
||||||
|
}
|
||||||
|
|
||||||
|
valueType := reflect.TypeOf(value)
|
||||||
|
if valueType.Name() == "string" {
|
||||||
|
values += fmt.Sprintf("'%s',", value.(string))
|
||||||
|
} else {
|
||||||
|
values += fmt.Sprintf("%v,", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fields = fields[:len(fields)-1] + ")"
|
||||||
|
values = values[:len(values)-1] + ")"
|
||||||
|
|
||||||
|
query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.Authenticators, fields, values)
|
||||||
|
err = p.db.Query(query).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
bytes, err := json.Marshal(authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
|
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||||
|
decoder.UseNumber()
|
||||||
|
authenticatorsMap := map[string]interface{}{}
|
||||||
|
err = decoder.Decode(&authenticatorsMap)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFields := ""
|
||||||
|
for key, value := range authenticatorsMap {
|
||||||
|
if key == "_id" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == "_key" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if value == nil {
|
||||||
|
updateFields += fmt.Sprintf("%s = null, ", key)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
valueType := reflect.TypeOf(value)
|
||||||
|
if valueType.Name() == "string" {
|
||||||
|
updateFields += fmt.Sprintf("%s = '%s', ", key, value.(string))
|
||||||
|
} else {
|
||||||
|
updateFields += fmt.Sprintf("%s = %v, ", key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateFields = strings.Trim(updateFields, " ")
|
||||||
|
updateFields = strings.TrimSuffix(updateFields, ",")
|
||||||
|
|
||||||
|
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Authenticators, updateFields, authenticators.ID)
|
||||||
|
err = p.db.Query(query).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators models.Authenticator
|
||||||
|
query := fmt.Sprintf("SELECT id, user_id, method, secret, recovery_codes, verified_at, created_at, updated_at FROM %s WHERE user_id = '%s' AND method = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.Authenticators, userId, authenticatorType)
|
||||||
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&authenticators.ID, &authenticators.UserID, &authenticators.Method, &authenticators.Secret, &authenticators.RecoveryCodes, &authenticators.VerifiedAt, &authenticators.CreatedAt, &authenticators.UpdatedAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &authenticators, nil
|
||||||
|
}
|
|
@ -274,6 +274,13 @@ func NewProvider() (*provider, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// add authenticators table
|
||||||
|
totpCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, user_id text, method text, secret text, recovery_codes text, verified_at bigint, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.Authenticators)
|
||||||
|
err = session.Query(totpCollectionQuery).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &provider{
|
return &provider{
|
||||||
db: session,
|
db: session,
|
||||||
}, err
|
}, err
|
||||||
|
|
|
@ -78,6 +78,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
|
|
||||||
query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.User, fields, values)
|
query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.User, fields, values)
|
||||||
err = p.db.Query(query).Exec()
|
err = p.db.Query(query).Exec()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
@ -177,13 +178,17 @@ func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination)
|
||||||
// there is no offset in cassandra
|
// there is no offset in cassandra
|
||||||
// so we fetch till limit + offset
|
// so we fetch till limit + offset
|
||||||
// and return the results from offset to limit
|
// and return the results from offset to limit
|
||||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.User, pagination.Limit+pagination.Offset)
|
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.User,
|
||||||
|
pagination.Limit+pagination.Offset)
|
||||||
scanner := p.db.Query(query).Iter().Scanner()
|
scanner := p.db.Query(query).Iter().Scanner()
|
||||||
counter := int64(0)
|
counter := int64(0)
|
||||||
for scanner.Next() {
|
for scanner.Next() {
|
||||||
if counter >= pagination.Offset {
|
if counter >= pagination.Offset {
|
||||||
var user models.User
|
var user models.User
|
||||||
err := scanner.Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.AppData, &user.CreatedAt, &user.UpdatedAt)
|
err := scanner.Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods,
|
||||||
|
&user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber,
|
||||||
|
&user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled,
|
||||||
|
&user.AppData, &user.CreatedAt, &user.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -297,9 +302,7 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
81
server/db/providers/couchbase/authenticator.go
Normal file
81
server/db/providers/couchbase/authenticator.go
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
authenticators.Key = authenticators.ID
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.Authenticators).Insert(authenticators.ID, authenticators, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
bytes, err := json.Marshal(authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
|
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||||
|
decoder.UseNumber()
|
||||||
|
authenticator := map[string]interface{}{}
|
||||||
|
err = decoder.Decode(&authenticator)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
updateFields, params := GetSetFields(authenticator)
|
||||||
|
query := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = '%s'", p.scopeName, models.Collections.Authenticators, updateFields, authenticators.ID)
|
||||||
|
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators *models.Authenticator
|
||||||
|
query := fmt.Sprintf("SELECT _id, user_id, method, secret, recovery_code, verified_at, created_at, updated_at FROM %s.%s WHERE user_id = $1 AND method = $2 LIMIT 1", p.scopeName, models.Collections.Authenticators)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{userId, authenticatorType},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
err = q.One(&authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
|
@ -43,10 +43,10 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
// UpdateUser to update user information in database
|
// UpdateUser to update user information in database
|
||||||
func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) {
|
func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) {
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
unsertOpt := gocb.UpsertOptions{
|
upsertOpt := gocb.UpsertOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
}
|
}
|
||||||
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &unsertOpt)
|
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &upsertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
57
server/db/providers/dynamodb/authenticator.go
Normal file
57
server/db/providers/dynamodb/authenticator.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package dynamodb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
collection := p.db.Table(models.Collections.Authenticators)
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
err := collection.Put(authenticators).RunWithContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
collection := p.db.Table(models.Collections.Authenticators)
|
||||||
|
if authenticators.ID != "" {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
err := UpdateByHashKey(collection, "id", authenticators.ID, authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators *models.Authenticator
|
||||||
|
collection := p.db.Table(models.Collections.Authenticators)
|
||||||
|
iter := collection.Scan().Filter("'user_id' = ?", userId).Filter("'method' = ?", authenticatorType).Iter()
|
||||||
|
for iter.NextWithContext(ctx, &authenticators) {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
err := iter.Err()
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
|
@ -52,6 +52,7 @@ func NewProvider() (*provider, error) {
|
||||||
db.CreateTable(models.Collections.VerificationRequest, models.VerificationRequest{}).Wait()
|
db.CreateTable(models.Collections.VerificationRequest, models.VerificationRequest{}).Wait()
|
||||||
db.CreateTable(models.Collections.Webhook, models.Webhook{}).Wait()
|
db.CreateTable(models.Collections.Webhook, models.Webhook{}).Wait()
|
||||||
db.CreateTable(models.Collections.WebhookLog, models.WebhookLog{}).Wait()
|
db.CreateTable(models.Collections.WebhookLog, models.WebhookLog{}).Wait()
|
||||||
|
db.CreateTable(models.Collections.Authenticators, models.Authenticator{}).Wait()
|
||||||
return &provider{
|
return &provider{
|
||||||
db: db,
|
db: db,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
|
@ -53,10 +53,6 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
return user, err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
52
server/db/providers/mongodb/authenticator.go
Normal file
52
server/db/providers/mongodb/authenticator.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package mongodb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
authenticators.Key = authenticators.ID
|
||||||
|
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||||
|
_, err := authenticatorsCollection.InsertOne(ctx, authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||||
|
_, err := authenticatorsCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": authenticators.ID}}, bson.M{"$set": authenticators})
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators *models.Authenticator
|
||||||
|
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||||
|
err := authenticatorsCollection.FindOne(ctx, bson.M{"user_id": userId, "method": authenticatorType}).Decode(&authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return authenticators, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
|
@ -122,6 +122,15 @@ func NewProvider() (*provider, error) {
|
||||||
},
|
},
|
||||||
}, options.CreateIndexes())
|
}, options.CreateIndexes())
|
||||||
|
|
||||||
|
mongodb.CreateCollection(ctx, models.Collections.Authenticators, options.CreateCollection())
|
||||||
|
authenticatorsCollection := mongodb.Collection(models.Collections.Authenticators, options.Collection())
|
||||||
|
authenticatorsCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||||
|
{
|
||||||
|
Keys: bson.M{"user_id": 1},
|
||||||
|
Options: options.Index().SetSparse(true),
|
||||||
|
},
|
||||||
|
}, options.CreateIndexes())
|
||||||
|
|
||||||
return &provider{
|
return &provider{
|
||||||
db: mongodb,
|
db: mongodb,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
34
server/db/providers/provider_template/authenticator.go
Normal file
34
server/db/providers/provider_template/authenticator.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package provider_template
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators *models.Authenticator
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
|
@ -26,7 +26,7 @@ type Provider interface {
|
||||||
// If ids set to nil / empty all the users will be updated
|
// If ids set to nil / empty all the users will be updated
|
||||||
UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error
|
UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error
|
||||||
|
|
||||||
// AddVerification to save verification request in database
|
// AddVerificationRequest to save verification request in database
|
||||||
AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error)
|
AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error)
|
||||||
// GetVerificationRequestByToken to get verification request from database using token
|
// GetVerificationRequestByToken to get verification request from database using token
|
||||||
GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error)
|
GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error)
|
||||||
|
@ -53,7 +53,7 @@ type Provider interface {
|
||||||
AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error)
|
AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error)
|
||||||
// UpdateWebhook to update webhook
|
// UpdateWebhook to update webhook
|
||||||
UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error)
|
UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error)
|
||||||
// ListWebhooks to list webhook
|
// ListWebhook to list webhook
|
||||||
ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error)
|
ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error)
|
||||||
// GetWebhookByID to get webhook by id
|
// GetWebhookByID to get webhook by id
|
||||||
GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error)
|
GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error)
|
||||||
|
@ -71,7 +71,7 @@ type Provider interface {
|
||||||
AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error)
|
AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error)
|
||||||
// UpdateEmailTemplate to update EmailTemplate
|
// UpdateEmailTemplate to update EmailTemplate
|
||||||
UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error)
|
UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error)
|
||||||
// ListEmailTemplates to list EmailTemplate
|
// ListEmailTemplate to list EmailTemplate
|
||||||
ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error)
|
ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error)
|
||||||
// GetEmailTemplateByID to get EmailTemplate by id
|
// GetEmailTemplateByID to get EmailTemplate by id
|
||||||
GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error)
|
GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error)
|
||||||
|
@ -88,4 +88,15 @@ type Provider interface {
|
||||||
GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error)
|
GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error)
|
||||||
// DeleteOTP to delete otp
|
// DeleteOTP to delete otp
|
||||||
DeleteOTP(ctx context.Context, otp *models.OTP) error
|
DeleteOTP(ctx context.Context, otp *models.OTP) error
|
||||||
|
|
||||||
|
// AddAuthenticator adds a new authenticator document to the database.
|
||||||
|
// If the authenticator doesn't have an ID, a new one is generated.
|
||||||
|
// The created document is returned, or an error if the operation fails.
|
||||||
|
AddAuthenticator(ctx context.Context, totp *models.Authenticator) (*models.Authenticator, error)
|
||||||
|
// UpdateAuthenticator updates an existing authenticator document in the database.
|
||||||
|
// The updated document is returned, or an error if the operation fails.
|
||||||
|
UpdateAuthenticator(ctx context.Context, totp *models.Authenticator) (*models.Authenticator, error)
|
||||||
|
// GetAuthenticatorDetailsByUserId retrieves details of an authenticator document based on user ID and authenticator type.
|
||||||
|
// If found, the authenticator document is returned, or an error if not found or an error occurs during the retrieval.
|
||||||
|
GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error)
|
||||||
}
|
}
|
||||||
|
|
55
server/db/providers/sql/authenticator.go
Normal file
55
server/db/providers/sql/authenticator.go
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
package sql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
authenticators.Key = authenticators.ID
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
res := p.db.Clauses(
|
||||||
|
clause.OnConflict{
|
||||||
|
UpdateAll: true,
|
||||||
|
Columns: []clause.Column{{Name: "id"}},
|
||||||
|
}).Create(&authenticators)
|
||||||
|
if res.Error != nil {
|
||||||
|
return nil, res.Error
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
result := p.db.Save(&authenticators)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return authenticators, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators models.Authenticator
|
||||||
|
result := p.db.Where("user_id = ?", userId).Where("method = ?", authenticatorType).First(&authenticators)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
return &authenticators, nil
|
||||||
|
}
|
|
@ -77,7 +77,7 @@ func NewProvider() (*provider, error) {
|
||||||
logrus.Debug("Failed to drop phone number constraint:", err)
|
logrus.Debug("Failed to drop phone number constraint:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}, &models.Webhook{}, &models.WebhookLog{}, &models.EmailTemplate{}, &models.OTP{})
|
err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}, &models.Webhook{}, &models.WebhookLog{}, &models.EmailTemplate{}, &models.OTP{}, &models.Authenticator{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
37
server/env/env.go
vendored
37
server/env/env.go
vendored
|
@ -104,6 +104,8 @@ func InitAllEnv() error {
|
||||||
osDisableStrongPassword := os.Getenv(constants.EnvKeyDisableStrongPassword)
|
osDisableStrongPassword := os.Getenv(constants.EnvKeyDisableStrongPassword)
|
||||||
osEnforceMultiFactorAuthentication := os.Getenv(constants.EnvKeyEnforceMultiFactorAuthentication)
|
osEnforceMultiFactorAuthentication := os.Getenv(constants.EnvKeyEnforceMultiFactorAuthentication)
|
||||||
osDisableMultiFactorAuthentication := os.Getenv(constants.EnvKeyDisableMultiFactorAuthentication)
|
osDisableMultiFactorAuthentication := os.Getenv(constants.EnvKeyDisableMultiFactorAuthentication)
|
||||||
|
osDisableTOTPLogin := os.Getenv(constants.EnvKeyDisableTOTPLogin)
|
||||||
|
osDisableMailOTPLogin := os.Getenv(constants.EnvKeyDisableMailOTPLogin)
|
||||||
// phone verification var
|
// phone verification var
|
||||||
osDisablePhoneVerification := os.Getenv(constants.EnvKeyDisablePhoneVerification)
|
osDisablePhoneVerification := os.Getenv(constants.EnvKeyDisablePhoneVerification)
|
||||||
osDisablePlayground := os.Getenv(constants.EnvKeyDisablePlayGround)
|
osDisablePlayground := os.Getenv(constants.EnvKeyDisablePlayGround)
|
||||||
|
@ -689,20 +691,13 @@ func InitAllEnv() error {
|
||||||
envData[constants.EnvKeyDisableEmailVerification] = true
|
envData[constants.EnvKeyDisableEmailVerification] = true
|
||||||
envData[constants.EnvKeyDisableMagicLinkLogin] = true
|
envData[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||||
envData[constants.EnvKeyIsEmailServiceEnabled] = false
|
envData[constants.EnvKeyIsEmailServiceEnabled] = false
|
||||||
|
envData[constants.EnvKeyDisableMailOTPLogin] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if envData[constants.EnvKeySmtpHost] != "" && envData[constants.EnvKeySmtpUsername] != "" && envData[constants.EnvKeySmtpPassword] != "" && envData[constants.EnvKeySenderEmail] != "" && envData[constants.EnvKeySmtpPort] != "" {
|
if envData[constants.EnvKeySmtpHost] != "" && envData[constants.EnvKeySmtpUsername] != "" && envData[constants.EnvKeySmtpPassword] != "" && envData[constants.EnvKeySenderEmail] != "" && envData[constants.EnvKeySmtpPort] != "" {
|
||||||
envData[constants.EnvKeyIsEmailServiceEnabled] = true
|
envData[constants.EnvKeyIsEmailServiceEnabled] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if envData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && !envData[constants.EnvKeyIsEmailServiceEnabled].(bool) && !envData[constants.EnvKeyIsSMSServiceEnabled].(bool) {
|
|
||||||
return errors.New("to enable multi factor authentication, please enable email service")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !envData[constants.EnvKeyIsEmailServiceEnabled].(bool) {
|
|
||||||
envData[constants.EnvKeyDisableMultiFactorAuthentication] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if envData[constants.EnvKeyDisableEmailVerification].(bool) {
|
if envData[constants.EnvKeyDisableEmailVerification].(bool) {
|
||||||
envData[constants.EnvKeyDisableMagicLinkLogin] = true
|
envData[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||||
}
|
}
|
||||||
|
@ -840,6 +835,32 @@ func InitAllEnv() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, ok := envData[constants.EnvKeyDisableTOTPLogin]; !ok {
|
||||||
|
envData[constants.EnvKeyDisableTOTPLogin] = osDisableTOTPLogin == "false"
|
||||||
|
}
|
||||||
|
if osDisableTOTPLogin != "" {
|
||||||
|
boolValue, err := strconv.ParseBool(osDisableTOTPLogin)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if boolValue != envData[constants.EnvKeyDisableTOTPLogin].(bool) {
|
||||||
|
envData[constants.EnvKeyDisableTOTPLogin] = boolValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := envData[constants.EnvKeyDisableMailOTPLogin]; !ok {
|
||||||
|
envData[constants.EnvKeyDisableMailOTPLogin] = osDisableMailOTPLogin == "true"
|
||||||
|
}
|
||||||
|
if osDisableMailOTPLogin != "" {
|
||||||
|
boolValue, err := strconv.ParseBool(osDisableMailOTPLogin)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if boolValue != envData[constants.EnvKeyDisableMailOTPLogin].(bool) {
|
||||||
|
envData[constants.EnvKeyDisableMailOTPLogin] = boolValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = memorystore.Provider.UpdateEnvStore(envData)
|
err = memorystore.Provider.UpdateEnvStore(envData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error while updating env store: ", err)
|
log.Debug("Error while updating env store: ", err)
|
||||||
|
|
7
server/env/persist_env.go
vendored
7
server/env/persist_env.go
vendored
|
@ -196,7 +196,7 @@ func PersistEnv() error {
|
||||||
envValue := strings.TrimSpace(os.Getenv(key))
|
envValue := strings.TrimSpace(os.Getenv(key))
|
||||||
if envValue != "" {
|
if envValue != "" {
|
||||||
switch key {
|
switch key {
|
||||||
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyIsSMSServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure, constants.EnvKeyDisablePhoneVerification, constants.EnvKeyDisablePlayGround:
|
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyIsSMSServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure, constants.EnvKeyDisablePhoneVerification, constants.EnvKeyDisablePlayGround, constants.EnvKeyDisableTOTPLogin, constants.EnvKeyDisableMailOTPLogin:
|
||||||
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
||||||
if value.(bool) != envValueBool {
|
if value.(bool) != envValueBool {
|
||||||
storeData[key] = envValueBool
|
storeData[key] = envValueBool
|
||||||
|
@ -227,6 +227,11 @@ func PersistEnv() error {
|
||||||
storeData[constants.EnvKeyDisableMagicLinkLogin] = true
|
storeData[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||||
hasChanged = true
|
hasChanged = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !storeData[constants.EnvKeyDisableMailOTPLogin].(bool) {
|
||||||
|
storeData[constants.EnvKeyDisableMailOTPLogin] = true
|
||||||
|
hasChanged = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = memorystore.Provider.UpdateEnvStore(storeData)
|
err = memorystore.Provider.UpdateEnvStore(storeData)
|
||||||
|
|
|
@ -5,7 +5,7 @@ go 1.16
|
||||||
require (
|
require (
|
||||||
github.com/99designs/gqlgen v0.17.39
|
github.com/99designs/gqlgen v0.17.39
|
||||||
github.com/arangodb/go-driver v1.6.0
|
github.com/arangodb/go-driver v1.6.0
|
||||||
github.com/aws/aws-sdk-go v1.45.25
|
github.com/aws/aws-sdk-go v1.47.4
|
||||||
github.com/bytedance/sonic v1.10.2 // indirect
|
github.com/bytedance/sonic v1.10.2 // indirect
|
||||||
github.com/coreos/go-oidc/v3 v3.6.0
|
github.com/coreos/go-oidc/v3 v3.6.0
|
||||||
github.com/couchbase/gocb/v2 v2.6.4
|
github.com/couchbase/gocb/v2 v2.6.4
|
||||||
|
@ -16,6 +16,7 @@ require (
|
||||||
github.com/go-playground/validator/v10 v10.15.5 // indirect
|
github.com/go-playground/validator/v10 v10.15.5 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||||
github.com/gocql/gocql v1.6.0
|
github.com/gocql/gocql v1.6.0
|
||||||
|
github.com/gokyle/twofactor v1.0.1
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/google/uuid v1.3.1
|
github.com/google/uuid v1.3.1
|
||||||
github.com/guregu/dynamo v1.20.2
|
github.com/guregu/dynamo v1.20.2
|
||||||
|
@ -26,11 +27,13 @@ require (
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||||
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/redis/go-redis/v9 v9.2.1
|
github.com/redis/go-redis/v9 v9.2.1
|
||||||
github.com/robertkrimen/otto v0.2.1
|
github.com/robertkrimen/otto v0.2.1
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/sosodev/duration v1.2.0 // indirect
|
github.com/sosodev/duration v1.2.0 // indirect
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
|
github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d
|
||||||
github.com/twilio/twilio-go v1.14.1
|
github.com/twilio/twilio-go v1.14.1
|
||||||
github.com/urfave/cli/v2 v2.25.7 // indirect
|
github.com/urfave/cli/v2 v2.25.7 // indirect
|
||||||
github.com/vektah/gqlparser/v2 v2.5.10
|
github.com/vektah/gqlparser/v2 v2.5.10
|
||||||
|
|
|
@ -643,14 +643,18 @@ github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e/go.mod h1:m
|
||||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
||||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||||
github.com/aws/aws-sdk-go v1.44.306/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
github.com/aws/aws-sdk-go v1.44.306/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||||
github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4=
|
github.com/aws/aws-sdk-go v1.47.4 h1:IyhNbmPt+5ldi5HNzv7ZnXiqSglDMaJiZlzj4Yq3qnk=
|
||||||
github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
github.com/aws/aws-sdk-go v1.47.4/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||||
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY=
|
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY=
|
||||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
||||||
|
github.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBEK16QnXY=
|
||||||
|
github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||||
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
|
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
|
@ -788,6 +792,8 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/gocql/gocql v1.6.0 h1:IdFdOTbnpbd0pDhl4REKQDM+Q0SzKXQ1Yh+YZZ8T/qU=
|
github.com/gocql/gocql v1.6.0 h1:IdFdOTbnpbd0pDhl4REKQDM+Q0SzKXQ1Yh+YZZ8T/qU=
|
||||||
github.com/gocql/gocql v1.6.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8=
|
github.com/gocql/gocql v1.6.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8=
|
||||||
|
github.com/gokyle/twofactor v1.0.1 h1:uRhvx0S4Hb82RPIDALnf7QxbmPL49LyyaCkJDpWx+Ek=
|
||||||
|
github.com/gokyle/twofactor v1.0.1/go.mod h1:4gxzH1eaE/F3Pct/sCDNOylP0ClofUO5j4XZN9tKtLE=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
|
@ -997,6 +1003,8 @@ github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxA
|
||||||
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
|
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
|
||||||
github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
|
github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
|
||||||
github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o=
|
github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o=
|
||||||
|
github.com/maruel/rs v1.1.0 h1:dh4OceAF5yD06EASOrb+DS358LI4g0B90YApSdjCP6U=
|
||||||
|
github.com/maruel/rs v1.1.0/go.mod h1:vzwMjzSJJxLIXmU62qHj6O5QRn5kvCKxFrfaFCxBcUY=
|
||||||
github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk=
|
github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
@ -1040,6 +1048,8 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ
|
||||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
|
||||||
|
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||||
|
@ -1089,6 +1099,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
||||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d h1:4x1FeGJRB00cvxnKXnRJDT89fvG/Lzm2ecm0vlr/qDs=
|
||||||
|
github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d/go.mod h1:uSELzeIcTceNCgzbKdJuJa0ouCqqtkyzL+6bnA3rM+M=
|
||||||
github.com/twilio/twilio-go v1.14.1 h1:uyMwNe2naFKwxLpVflAHbKEPiW9iHNI8VF6NWLJJ1Kk=
|
github.com/twilio/twilio-go v1.14.1 h1:uyMwNe2naFKwxLpVflAHbKEPiW9iHNI8VF6NWLJJ1Kk=
|
||||||
github.com/twilio/twilio-go v1.14.1/go.mod h1:tdnfQ5TjbewoAu4lf9bMsGvfuJ/QU9gYuv9yx3TSIXU=
|
github.com/twilio/twilio-go v1.14.1/go.mod h1:tdnfQ5TjbewoAu4lf9bMsGvfuJ/QU9gYuv9yx3TSIXU=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
|
@ -1929,5 +1941,7 @@ modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE=
|
||||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
|
||||||
|
rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
|
|
|
@ -48,12 +48,16 @@ type DirectiveRoot struct {
|
||||||
type ComplexityRoot struct {
|
type ComplexityRoot struct {
|
||||||
AuthResponse struct {
|
AuthResponse struct {
|
||||||
AccessToken func(childComplexity int) int
|
AccessToken func(childComplexity int) int
|
||||||
|
AuthenticatorRecoveryCodes func(childComplexity int) int
|
||||||
|
AuthenticatorScannerImage func(childComplexity int) int
|
||||||
|
AuthenticatorSecret func(childComplexity int) int
|
||||||
ExpiresIn func(childComplexity int) int
|
ExpiresIn func(childComplexity int) int
|
||||||
IDToken func(childComplexity int) int
|
IDToken func(childComplexity int) int
|
||||||
Message func(childComplexity int) int
|
Message func(childComplexity int) int
|
||||||
RefreshToken func(childComplexity int) int
|
RefreshToken func(childComplexity int) int
|
||||||
ShouldShowEmailOtpScreen func(childComplexity int) int
|
ShouldShowEmailOtpScreen func(childComplexity int) int
|
||||||
ShouldShowMobileOtpScreen func(childComplexity int) int
|
ShouldShowMobileOtpScreen func(childComplexity int) int
|
||||||
|
ShouldShowTotpScreen func(childComplexity int) int
|
||||||
User func(childComplexity int) int
|
User func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,11 +102,13 @@ type ComplexityRoot struct {
|
||||||
DisableEmailVerification func(childComplexity int) int
|
DisableEmailVerification func(childComplexity int) int
|
||||||
DisableLoginPage func(childComplexity int) int
|
DisableLoginPage func(childComplexity int) int
|
||||||
DisableMagicLinkLogin func(childComplexity int) int
|
DisableMagicLinkLogin func(childComplexity int) int
|
||||||
|
DisableMailOtpLogin func(childComplexity int) int
|
||||||
DisableMultiFactorAuthentication func(childComplexity int) int
|
DisableMultiFactorAuthentication func(childComplexity int) int
|
||||||
DisablePlayground func(childComplexity int) int
|
DisablePlayground func(childComplexity int) int
|
||||||
DisableRedisForEnv func(childComplexity int) int
|
DisableRedisForEnv func(childComplexity int) int
|
||||||
DisableSignUp func(childComplexity int) int
|
DisableSignUp func(childComplexity int) int
|
||||||
DisableStrongPassword func(childComplexity int) int
|
DisableStrongPassword func(childComplexity int) int
|
||||||
|
DisableTotpLogin func(childComplexity int) int
|
||||||
EnforceMultiFactorAuthentication func(childComplexity int) int
|
EnforceMultiFactorAuthentication func(childComplexity int) int
|
||||||
FacebookClientID func(childComplexity int) int
|
FacebookClientID func(childComplexity int) int
|
||||||
FacebookClientSecret func(childComplexity int) int
|
FacebookClientSecret func(childComplexity int) int
|
||||||
|
@ -412,6 +418,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.AuthResponse.AccessToken(childComplexity), true
|
return e.complexity.AuthResponse.AccessToken(childComplexity), true
|
||||||
|
|
||||||
|
case "AuthResponse.authenticator_recovery_codes":
|
||||||
|
if e.complexity.AuthResponse.AuthenticatorRecoveryCodes == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.AuthResponse.AuthenticatorRecoveryCodes(childComplexity), true
|
||||||
|
|
||||||
|
case "AuthResponse.authenticator_scanner_image":
|
||||||
|
if e.complexity.AuthResponse.AuthenticatorScannerImage == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.AuthResponse.AuthenticatorScannerImage(childComplexity), true
|
||||||
|
|
||||||
|
case "AuthResponse.authenticator_secret":
|
||||||
|
if e.complexity.AuthResponse.AuthenticatorSecret == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.AuthResponse.AuthenticatorSecret(childComplexity), true
|
||||||
|
|
||||||
case "AuthResponse.expires_in":
|
case "AuthResponse.expires_in":
|
||||||
if e.complexity.AuthResponse.ExpiresIn == nil {
|
if e.complexity.AuthResponse.ExpiresIn == nil {
|
||||||
break
|
break
|
||||||
|
@ -454,6 +481,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.AuthResponse.ShouldShowMobileOtpScreen(childComplexity), true
|
return e.complexity.AuthResponse.ShouldShowMobileOtpScreen(childComplexity), true
|
||||||
|
|
||||||
|
case "AuthResponse.should_show_totp_screen":
|
||||||
|
if e.complexity.AuthResponse.ShouldShowTotpScreen == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.AuthResponse.ShouldShowTotpScreen(childComplexity), true
|
||||||
|
|
||||||
case "AuthResponse.user":
|
case "AuthResponse.user":
|
||||||
if e.complexity.AuthResponse.User == nil {
|
if e.complexity.AuthResponse.User == nil {
|
||||||
break
|
break
|
||||||
|
@ -699,6 +733,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Env.DisableMagicLinkLogin(childComplexity), true
|
return e.complexity.Env.DisableMagicLinkLogin(childComplexity), true
|
||||||
|
|
||||||
|
case "Env.DISABLE_MAIL_OTP_LOGIN":
|
||||||
|
if e.complexity.Env.DisableMailOtpLogin == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Env.DisableMailOtpLogin(childComplexity), true
|
||||||
|
|
||||||
case "Env.DISABLE_MULTI_FACTOR_AUTHENTICATION":
|
case "Env.DISABLE_MULTI_FACTOR_AUTHENTICATION":
|
||||||
if e.complexity.Env.DisableMultiFactorAuthentication == nil {
|
if e.complexity.Env.DisableMultiFactorAuthentication == nil {
|
||||||
break
|
break
|
||||||
|
@ -734,6 +775,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Env.DisableStrongPassword(childComplexity), true
|
return e.complexity.Env.DisableStrongPassword(childComplexity), true
|
||||||
|
|
||||||
|
case "Env.DISABLE_TOTP_LOGIN":
|
||||||
|
if e.complexity.Env.DisableTotpLogin == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Env.DisableTotpLogin(childComplexity), true
|
||||||
|
|
||||||
case "Env.ENFORCE_MULTI_FACTOR_AUTHENTICATION":
|
case "Env.ENFORCE_MULTI_FACTOR_AUTHENTICATION":
|
||||||
if e.complexity.Env.EnforceMultiFactorAuthentication == nil {
|
if e.complexity.Env.EnforceMultiFactorAuthentication == nil {
|
||||||
break
|
break
|
||||||
|
@ -2349,11 +2397,19 @@ type AuthResponse {
|
||||||
message: String!
|
message: String!
|
||||||
should_show_email_otp_screen: Boolean
|
should_show_email_otp_screen: Boolean
|
||||||
should_show_mobile_otp_screen: Boolean
|
should_show_mobile_otp_screen: Boolean
|
||||||
|
should_show_totp_screen: Boolean
|
||||||
access_token: String
|
access_token: String
|
||||||
id_token: String
|
id_token: String
|
||||||
refresh_token: String
|
refresh_token: String
|
||||||
expires_in: Int64
|
expires_in: Int64
|
||||||
user: User
|
user: User
|
||||||
|
# key for totp login
|
||||||
|
# it is a base64 image url
|
||||||
|
authenticator_scanner_image: String
|
||||||
|
# string which can be used instead of scanner image
|
||||||
|
authenticator_secret: String
|
||||||
|
# recovery codes for totp login shared with user only once
|
||||||
|
authenticator_recovery_codes: [String]
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response {
|
type Response {
|
||||||
|
@ -2428,6 +2484,8 @@ type Env {
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
||||||
DISABLE_PLAYGROUND: Boolean!
|
DISABLE_PLAYGROUND: Boolean!
|
||||||
|
DISABLE_MAIL_OTP_LOGIN: Boolean!
|
||||||
|
DISABLE_TOTP_LOGIN: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
type ValidateJWTTokenResponse {
|
type ValidateJWTTokenResponse {
|
||||||
|
@ -2551,6 +2609,8 @@ input UpdateEnvInput {
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
||||||
DISABLE_PLAYGROUND: Boolean
|
DISABLE_PLAYGROUND: Boolean
|
||||||
|
DISABLE_MAIL_OTP_LOGIN: Boolean
|
||||||
|
DISABLE_TOTP_LOGIN: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
input AdminLoginInput {
|
input AdminLoginInput {
|
||||||
|
@ -2806,10 +2866,11 @@ input DeleteEmailTemplateRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
input VerifyOTPRequest {
|
input VerifyOTPRequest {
|
||||||
# either email or phone_number is required
|
# either email, phone_number or totp_token is required
|
||||||
email: String
|
email: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
otp: String!
|
otp: String!
|
||||||
|
totp: Boolean
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
|
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
|
||||||
|
@ -3657,6 +3718,47 @@ func (ec *executionContext) fieldContext_AuthResponse_should_show_mobile_otp_scr
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _AuthResponse_should_show_totp_screen(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_AuthResponse_should_show_totp_screen(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.ShouldShowTotpScreen, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_AuthResponse_should_show_totp_screen(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "AuthResponse",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type Boolean does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _AuthResponse_access_token(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) {
|
func (ec *executionContext) _AuthResponse_access_token(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_AuthResponse_access_token(ctx, field)
|
fc, err := ec.fieldContext_AuthResponse_access_token(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3904,6 +4006,129 @@ func (ec *executionContext) fieldContext_AuthResponse_user(ctx context.Context,
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _AuthResponse_authenticator_scanner_image(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_AuthResponse_authenticator_scanner_image(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.AuthenticatorScannerImage, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_AuthResponse_authenticator_scanner_image(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "AuthResponse",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _AuthResponse_authenticator_secret(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_AuthResponse_authenticator_secret(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.AuthenticatorSecret, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_AuthResponse_authenticator_secret(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "AuthResponse",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _AuthResponse_authenticator_recovery_codes(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_AuthResponse_authenticator_recovery_codes(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.AuthenticatorRecoveryCodes, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.([]*string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOString2ᚕᚖstring(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_AuthResponse_authenticator_recovery_codes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "AuthResponse",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _EmailTemplate_id(ctx context.Context, field graphql.CollectedField, obj *model.EmailTemplate) (ret graphql.Marshaler) {
|
func (ec *executionContext) _EmailTemplate_id(ctx context.Context, field graphql.CollectedField, obj *model.EmailTemplate) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_EmailTemplate_id(ctx, field)
|
fc, err := ec.fieldContext_EmailTemplate_id(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -6904,6 +7129,94 @@ func (ec *executionContext) fieldContext_Env_DISABLE_PLAYGROUND(ctx context.Cont
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Env_DISABLE_MAIL_OTP_LOGIN(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Env_DISABLE_MAIL_OTP_LOGIN(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.DisableMailOtpLogin, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_Env_DISABLE_MAIL_OTP_LOGIN(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Env",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type Boolean does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Env_DISABLE_TOTP_LOGIN(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Env_DISABLE_TOTP_LOGIN(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.DisableTotpLogin, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_Env_DISABLE_TOTP_LOGIN(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Env",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type Boolean does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Error_message(ctx context.Context, field graphql.CollectedField, obj *model.Error) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Error_message(ctx context.Context, field graphql.CollectedField, obj *model.Error) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_Error_message(ctx, field)
|
fc, err := ec.fieldContext_Error_message(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7950,6 +8263,8 @@ func (ec *executionContext) fieldContext_Mutation_signup(ctx context.Context, fi
|
||||||
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
||||||
case "should_show_mobile_otp_screen":
|
case "should_show_mobile_otp_screen":
|
||||||
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
||||||
|
case "should_show_totp_screen":
|
||||||
|
return ec.fieldContext_AuthResponse_should_show_totp_screen(ctx, field)
|
||||||
case "access_token":
|
case "access_token":
|
||||||
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
||||||
case "id_token":
|
case "id_token":
|
||||||
|
@ -7960,6 +8275,12 @@ func (ec *executionContext) fieldContext_Mutation_signup(ctx context.Context, fi
|
||||||
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
||||||
case "user":
|
case "user":
|
||||||
return ec.fieldContext_AuthResponse_user(ctx, field)
|
return ec.fieldContext_AuthResponse_user(ctx, field)
|
||||||
|
case "authenticator_scanner_image":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_scanner_image(ctx, field)
|
||||||
|
case "authenticator_secret":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_secret(ctx, field)
|
||||||
|
case "authenticator_recovery_codes":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_recovery_codes(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
||||||
},
|
},
|
||||||
|
@ -8023,6 +8344,8 @@ func (ec *executionContext) fieldContext_Mutation_mobile_signup(ctx context.Cont
|
||||||
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
||||||
case "should_show_mobile_otp_screen":
|
case "should_show_mobile_otp_screen":
|
||||||
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
||||||
|
case "should_show_totp_screen":
|
||||||
|
return ec.fieldContext_AuthResponse_should_show_totp_screen(ctx, field)
|
||||||
case "access_token":
|
case "access_token":
|
||||||
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
||||||
case "id_token":
|
case "id_token":
|
||||||
|
@ -8033,6 +8356,12 @@ func (ec *executionContext) fieldContext_Mutation_mobile_signup(ctx context.Cont
|
||||||
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
||||||
case "user":
|
case "user":
|
||||||
return ec.fieldContext_AuthResponse_user(ctx, field)
|
return ec.fieldContext_AuthResponse_user(ctx, field)
|
||||||
|
case "authenticator_scanner_image":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_scanner_image(ctx, field)
|
||||||
|
case "authenticator_secret":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_secret(ctx, field)
|
||||||
|
case "authenticator_recovery_codes":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_recovery_codes(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
||||||
},
|
},
|
||||||
|
@ -8096,6 +8425,8 @@ func (ec *executionContext) fieldContext_Mutation_login(ctx context.Context, fie
|
||||||
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
||||||
case "should_show_mobile_otp_screen":
|
case "should_show_mobile_otp_screen":
|
||||||
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
||||||
|
case "should_show_totp_screen":
|
||||||
|
return ec.fieldContext_AuthResponse_should_show_totp_screen(ctx, field)
|
||||||
case "access_token":
|
case "access_token":
|
||||||
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
||||||
case "id_token":
|
case "id_token":
|
||||||
|
@ -8106,6 +8437,12 @@ func (ec *executionContext) fieldContext_Mutation_login(ctx context.Context, fie
|
||||||
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
||||||
case "user":
|
case "user":
|
||||||
return ec.fieldContext_AuthResponse_user(ctx, field)
|
return ec.fieldContext_AuthResponse_user(ctx, field)
|
||||||
|
case "authenticator_scanner_image":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_scanner_image(ctx, field)
|
||||||
|
case "authenticator_secret":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_secret(ctx, field)
|
||||||
|
case "authenticator_recovery_codes":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_recovery_codes(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
||||||
},
|
},
|
||||||
|
@ -8169,6 +8506,8 @@ func (ec *executionContext) fieldContext_Mutation_mobile_login(ctx context.Conte
|
||||||
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
||||||
case "should_show_mobile_otp_screen":
|
case "should_show_mobile_otp_screen":
|
||||||
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
||||||
|
case "should_show_totp_screen":
|
||||||
|
return ec.fieldContext_AuthResponse_should_show_totp_screen(ctx, field)
|
||||||
case "access_token":
|
case "access_token":
|
||||||
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
||||||
case "id_token":
|
case "id_token":
|
||||||
|
@ -8179,6 +8518,12 @@ func (ec *executionContext) fieldContext_Mutation_mobile_login(ctx context.Conte
|
||||||
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
||||||
case "user":
|
case "user":
|
||||||
return ec.fieldContext_AuthResponse_user(ctx, field)
|
return ec.fieldContext_AuthResponse_user(ctx, field)
|
||||||
|
case "authenticator_scanner_image":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_scanner_image(ctx, field)
|
||||||
|
case "authenticator_secret":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_secret(ctx, field)
|
||||||
|
case "authenticator_recovery_codes":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_recovery_codes(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
||||||
},
|
},
|
||||||
|
@ -8408,6 +8753,8 @@ func (ec *executionContext) fieldContext_Mutation_verify_email(ctx context.Conte
|
||||||
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
||||||
case "should_show_mobile_otp_screen":
|
case "should_show_mobile_otp_screen":
|
||||||
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
||||||
|
case "should_show_totp_screen":
|
||||||
|
return ec.fieldContext_AuthResponse_should_show_totp_screen(ctx, field)
|
||||||
case "access_token":
|
case "access_token":
|
||||||
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
||||||
case "id_token":
|
case "id_token":
|
||||||
|
@ -8418,6 +8765,12 @@ func (ec *executionContext) fieldContext_Mutation_verify_email(ctx context.Conte
|
||||||
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
||||||
case "user":
|
case "user":
|
||||||
return ec.fieldContext_AuthResponse_user(ctx, field)
|
return ec.fieldContext_AuthResponse_user(ctx, field)
|
||||||
|
case "authenticator_scanner_image":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_scanner_image(ctx, field)
|
||||||
|
case "authenticator_secret":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_secret(ctx, field)
|
||||||
|
case "authenticator_recovery_codes":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_recovery_codes(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
||||||
},
|
},
|
||||||
|
@ -8717,6 +9070,8 @@ func (ec *executionContext) fieldContext_Mutation_verify_otp(ctx context.Context
|
||||||
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
||||||
case "should_show_mobile_otp_screen":
|
case "should_show_mobile_otp_screen":
|
||||||
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
||||||
|
case "should_show_totp_screen":
|
||||||
|
return ec.fieldContext_AuthResponse_should_show_totp_screen(ctx, field)
|
||||||
case "access_token":
|
case "access_token":
|
||||||
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
||||||
case "id_token":
|
case "id_token":
|
||||||
|
@ -8727,6 +9082,12 @@ func (ec *executionContext) fieldContext_Mutation_verify_otp(ctx context.Context
|
||||||
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
||||||
case "user":
|
case "user":
|
||||||
return ec.fieldContext_AuthResponse_user(ctx, field)
|
return ec.fieldContext_AuthResponse_user(ctx, field)
|
||||||
|
case "authenticator_scanner_image":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_scanner_image(ctx, field)
|
||||||
|
case "authenticator_secret":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_secret(ctx, field)
|
||||||
|
case "authenticator_recovery_codes":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_recovery_codes(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
||||||
},
|
},
|
||||||
|
@ -10187,6 +10548,8 @@ func (ec *executionContext) fieldContext_Query_session(ctx context.Context, fiel
|
||||||
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field)
|
||||||
case "should_show_mobile_otp_screen":
|
case "should_show_mobile_otp_screen":
|
||||||
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field)
|
||||||
|
case "should_show_totp_screen":
|
||||||
|
return ec.fieldContext_AuthResponse_should_show_totp_screen(ctx, field)
|
||||||
case "access_token":
|
case "access_token":
|
||||||
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
||||||
case "id_token":
|
case "id_token":
|
||||||
|
@ -10197,6 +10560,12 @@ func (ec *executionContext) fieldContext_Query_session(ctx context.Context, fiel
|
||||||
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
||||||
case "user":
|
case "user":
|
||||||
return ec.fieldContext_AuthResponse_user(ctx, field)
|
return ec.fieldContext_AuthResponse_user(ctx, field)
|
||||||
|
case "authenticator_scanner_image":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_scanner_image(ctx, field)
|
||||||
|
case "authenticator_secret":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_secret(ctx, field)
|
||||||
|
case "authenticator_recovery_codes":
|
||||||
|
return ec.fieldContext_AuthResponse_authenticator_recovery_codes(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
||||||
},
|
},
|
||||||
|
@ -10853,6 +11222,10 @@ func (ec *executionContext) fieldContext_Query__env(ctx context.Context, field g
|
||||||
return ec.fieldContext_Env_DEFAULT_AUTHORIZE_RESPONSE_MODE(ctx, field)
|
return ec.fieldContext_Env_DEFAULT_AUTHORIZE_RESPONSE_MODE(ctx, field)
|
||||||
case "DISABLE_PLAYGROUND":
|
case "DISABLE_PLAYGROUND":
|
||||||
return ec.fieldContext_Env_DISABLE_PLAYGROUND(ctx, field)
|
return ec.fieldContext_Env_DISABLE_PLAYGROUND(ctx, field)
|
||||||
|
case "DISABLE_MAIL_OTP_LOGIN":
|
||||||
|
return ec.fieldContext_Env_DISABLE_MAIL_OTP_LOGIN(ctx, field)
|
||||||
|
case "DISABLE_TOTP_LOGIN":
|
||||||
|
return ec.fieldContext_Env_DISABLE_TOTP_LOGIN(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type Env", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type Env", field.Name)
|
||||||
},
|
},
|
||||||
|
@ -17342,7 +17715,7 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "SENDER_NAME", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET", "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID", "ORGANIZATION_NAME", "ORGANIZATION_LOGO", "DEFAULT_AUTHORIZE_RESPONSE_TYPE", "DEFAULT_AUTHORIZE_RESPONSE_MODE", "DISABLE_PLAYGROUND"}
|
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "SENDER_NAME", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET", "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID", "ORGANIZATION_NAME", "ORGANIZATION_LOGO", "DEFAULT_AUTHORIZE_RESPONSE_TYPE", "DEFAULT_AUTHORIZE_RESPONSE_MODE", "DISABLE_PLAYGROUND", "DISABLE_MAIL_OTP_LOGIN", "DISABLE_TOTP_LOGIN"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -17826,6 +18199,24 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.DisablePlayground = data
|
it.DisablePlayground = data
|
||||||
|
case "DISABLE_MAIL_OTP_LOGIN":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_MAIL_OTP_LOGIN"))
|
||||||
|
data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.DisableMailOtpLogin = data
|
||||||
|
case "DISABLE_TOTP_LOGIN":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_TOTP_LOGIN"))
|
||||||
|
data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.DisableTotpLogin = data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18328,7 +18719,7 @@ func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context,
|
||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"email", "phone_number", "otp", "state"}
|
fieldsInOrder := [...]string{"email", "phone_number", "otp", "totp", "state"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -18362,6 +18753,15 @@ func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context,
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.Otp = data
|
it.Otp = data
|
||||||
|
case "totp":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("totp"))
|
||||||
|
data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.Totp = data
|
||||||
case "state":
|
case "state":
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -18434,6 +18834,8 @@ func (ec *executionContext) _AuthResponse(ctx context.Context, sel ast.Selection
|
||||||
out.Values[i] = ec._AuthResponse_should_show_email_otp_screen(ctx, field, obj)
|
out.Values[i] = ec._AuthResponse_should_show_email_otp_screen(ctx, field, obj)
|
||||||
case "should_show_mobile_otp_screen":
|
case "should_show_mobile_otp_screen":
|
||||||
out.Values[i] = ec._AuthResponse_should_show_mobile_otp_screen(ctx, field, obj)
|
out.Values[i] = ec._AuthResponse_should_show_mobile_otp_screen(ctx, field, obj)
|
||||||
|
case "should_show_totp_screen":
|
||||||
|
out.Values[i] = ec._AuthResponse_should_show_totp_screen(ctx, field, obj)
|
||||||
case "access_token":
|
case "access_token":
|
||||||
out.Values[i] = ec._AuthResponse_access_token(ctx, field, obj)
|
out.Values[i] = ec._AuthResponse_access_token(ctx, field, obj)
|
||||||
case "id_token":
|
case "id_token":
|
||||||
|
@ -18444,6 +18846,12 @@ func (ec *executionContext) _AuthResponse(ctx context.Context, sel ast.Selection
|
||||||
out.Values[i] = ec._AuthResponse_expires_in(ctx, field, obj)
|
out.Values[i] = ec._AuthResponse_expires_in(ctx, field, obj)
|
||||||
case "user":
|
case "user":
|
||||||
out.Values[i] = ec._AuthResponse_user(ctx, field, obj)
|
out.Values[i] = ec._AuthResponse_user(ctx, field, obj)
|
||||||
|
case "authenticator_scanner_image":
|
||||||
|
out.Values[i] = ec._AuthResponse_authenticator_scanner_image(ctx, field, obj)
|
||||||
|
case "authenticator_secret":
|
||||||
|
out.Values[i] = ec._AuthResponse_authenticator_secret(ctx, field, obj)
|
||||||
|
case "authenticator_recovery_codes":
|
||||||
|
out.Values[i] = ec._AuthResponse_authenticator_recovery_codes(ctx, field, obj)
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
}
|
}
|
||||||
|
@ -18751,6 +19159,16 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
out.Invalids++
|
out.Invalids++
|
||||||
}
|
}
|
||||||
|
case "DISABLE_MAIL_OTP_LOGIN":
|
||||||
|
out.Values[i] = ec._Env_DISABLE_MAIL_OTP_LOGIN(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
out.Invalids++
|
||||||
|
}
|
||||||
|
case "DISABLE_TOTP_LOGIN":
|
||||||
|
out.Values[i] = ec._Env_DISABLE_TOTP_LOGIN(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
out.Invalids++
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,11 +29,15 @@ type AuthResponse struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
ShouldShowEmailOtpScreen *bool `json:"should_show_email_otp_screen,omitempty"`
|
ShouldShowEmailOtpScreen *bool `json:"should_show_email_otp_screen,omitempty"`
|
||||||
ShouldShowMobileOtpScreen *bool `json:"should_show_mobile_otp_screen,omitempty"`
|
ShouldShowMobileOtpScreen *bool `json:"should_show_mobile_otp_screen,omitempty"`
|
||||||
|
ShouldShowTotpScreen *bool `json:"should_show_totp_screen,omitempty"`
|
||||||
AccessToken *string `json:"access_token,omitempty"`
|
AccessToken *string `json:"access_token,omitempty"`
|
||||||
IDToken *string `json:"id_token,omitempty"`
|
IDToken *string `json:"id_token,omitempty"`
|
||||||
RefreshToken *string `json:"refresh_token,omitempty"`
|
RefreshToken *string `json:"refresh_token,omitempty"`
|
||||||
ExpiresIn *int64 `json:"expires_in,omitempty"`
|
ExpiresIn *int64 `json:"expires_in,omitempty"`
|
||||||
User *User `json:"user,omitempty"`
|
User *User `json:"user,omitempty"`
|
||||||
|
AuthenticatorScannerImage *string `json:"authenticator_scanner_image,omitempty"`
|
||||||
|
AuthenticatorSecret *string `json:"authenticator_secret,omitempty"`
|
||||||
|
AuthenticatorRecoveryCodes []*string `json:"authenticator_recovery_codes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeleteEmailTemplateRequest struct {
|
type DeleteEmailTemplateRequest struct {
|
||||||
|
@ -122,6 +126,8 @@ type Env struct {
|
||||||
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE,omitempty"`
|
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE,omitempty"`
|
||||||
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE,omitempty"`
|
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE,omitempty"`
|
||||||
DisablePlayground bool `json:"DISABLE_PLAYGROUND"`
|
DisablePlayground bool `json:"DISABLE_PLAYGROUND"`
|
||||||
|
DisableMailOtpLogin bool `json:"DISABLE_MAIL_OTP_LOGIN"`
|
||||||
|
DisableTotpLogin bool `json:"DISABLE_TOTP_LOGIN"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Error struct {
|
type Error struct {
|
||||||
|
@ -382,6 +388,8 @@ type UpdateEnvInput struct {
|
||||||
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE,omitempty"`
|
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE,omitempty"`
|
||||||
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE,omitempty"`
|
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE,omitempty"`
|
||||||
DisablePlayground *bool `json:"DISABLE_PLAYGROUND,omitempty"`
|
DisablePlayground *bool `json:"DISABLE_PLAYGROUND,omitempty"`
|
||||||
|
DisableMailOtpLogin *bool `json:"DISABLE_MAIL_OTP_LOGIN,omitempty"`
|
||||||
|
DisableTotpLogin *bool `json:"DISABLE_TOTP_LOGIN,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateProfileInput struct {
|
type UpdateProfileInput struct {
|
||||||
|
@ -502,6 +510,7 @@ type VerifyOTPRequest struct {
|
||||||
Email *string `json:"email,omitempty"`
|
Email *string `json:"email,omitempty"`
|
||||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||||
Otp string `json:"otp"`
|
Otp string `json:"otp"`
|
||||||
|
Totp *bool `json:"totp,omitempty"`
|
||||||
State *string `json:"state,omitempty"`
|
State *string `json:"state,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,11 +95,19 @@ type AuthResponse {
|
||||||
message: String!
|
message: String!
|
||||||
should_show_email_otp_screen: Boolean
|
should_show_email_otp_screen: Boolean
|
||||||
should_show_mobile_otp_screen: Boolean
|
should_show_mobile_otp_screen: Boolean
|
||||||
|
should_show_totp_screen: Boolean
|
||||||
access_token: String
|
access_token: String
|
||||||
id_token: String
|
id_token: String
|
||||||
refresh_token: String
|
refresh_token: String
|
||||||
expires_in: Int64
|
expires_in: Int64
|
||||||
user: User
|
user: User
|
||||||
|
# key for totp login
|
||||||
|
# it is a base64 image url
|
||||||
|
authenticator_scanner_image: String
|
||||||
|
# string which can be used instead of scanner image
|
||||||
|
authenticator_secret: String
|
||||||
|
# recovery codes for totp login shared with user only once
|
||||||
|
authenticator_recovery_codes: [String]
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response {
|
type Response {
|
||||||
|
@ -174,6 +182,8 @@ type Env {
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
||||||
DISABLE_PLAYGROUND: Boolean!
|
DISABLE_PLAYGROUND: Boolean!
|
||||||
|
DISABLE_MAIL_OTP_LOGIN: Boolean!
|
||||||
|
DISABLE_TOTP_LOGIN: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
type ValidateJWTTokenResponse {
|
type ValidateJWTTokenResponse {
|
||||||
|
@ -297,6 +307,8 @@ input UpdateEnvInput {
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
||||||
DISABLE_PLAYGROUND: Boolean
|
DISABLE_PLAYGROUND: Boolean
|
||||||
|
DISABLE_MAIL_OTP_LOGIN: Boolean
|
||||||
|
DISABLE_TOTP_LOGIN: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
input AdminLoginInput {
|
input AdminLoginInput {
|
||||||
|
@ -552,10 +564,11 @@ input DeleteEmailTemplateRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
input VerifyOTPRequest {
|
input VerifyOTPRequest {
|
||||||
# either email or phone_number is required
|
# either email, phone_number or totp_token is required
|
||||||
email: String
|
email: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
otp: String!
|
otp: String!
|
||||||
|
totp: Boolean
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
# and use that code for setting `c_hash` in id_token
|
# and use that code for setting `c_hash` in id_token
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
|
"github.com/authorizerdev/authorizer/server/authenticators"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/cli"
|
"github.com/authorizerdev/authorizer/server/cli"
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
@ -70,6 +71,11 @@ func main() {
|
||||||
log.Fatalln("Error while initializing oauth: ", err)
|
log.Fatalln("Error while initializing oauth: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = authenticators.InitTOTPStore()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error while initializing authenticator: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
router := routes.InitRouter(log)
|
router := routes.InitRouter(log)
|
||||||
log.Info("Starting Authorizer: ", VERSION)
|
log.Info("Starting Authorizer: ", VERSION)
|
||||||
port, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyPort)
|
port, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyPort)
|
||||||
|
|
|
@ -36,9 +36,11 @@ func InitMemStore() error {
|
||||||
constants.EnvKeyIsSMSServiceEnabled: false,
|
constants.EnvKeyIsSMSServiceEnabled: false,
|
||||||
constants.EnvKeyEnforceMultiFactorAuthentication: false,
|
constants.EnvKeyEnforceMultiFactorAuthentication: false,
|
||||||
constants.EnvKeyDisableMultiFactorAuthentication: false,
|
constants.EnvKeyDisableMultiFactorAuthentication: false,
|
||||||
|
constants.EnvKeyDisableTOTPLogin: false,
|
||||||
constants.EnvKeyAppCookieSecure: true,
|
constants.EnvKeyAppCookieSecure: true,
|
||||||
constants.EnvKeyAdminCookieSecure: true,
|
constants.EnvKeyAdminCookieSecure: true,
|
||||||
constants.EnvKeyDisablePlayGround: true,
|
constants.EnvKeyDisablePlayGround: true,
|
||||||
|
constants.EnvKeyDisableMailOTPLogin: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
requiredEnvs := RequiredEnvStoreObj.GetRequiredEnv()
|
requiredEnvs := RequiredEnvStoreObj.GetRequiredEnv()
|
||||||
|
|
|
@ -176,7 +176,7 @@ func (c *provider) GetEnvStore() (map[string]interface{}, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for key, value := range data {
|
for key, value := range data {
|
||||||
if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableMobileBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled || key == constants.EnvKeyIsSMSServiceEnabled || key == constants.EnvKeyEnforceMultiFactorAuthentication || key == constants.EnvKeyDisableMultiFactorAuthentication || key == constants.EnvKeyAppCookieSecure || key == constants.EnvKeyAdminCookieSecure || key == constants.EnvKeyDisablePlayGround {
|
if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableMobileBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled || key == constants.EnvKeyIsSMSServiceEnabled || key == constants.EnvKeyEnforceMultiFactorAuthentication || key == constants.EnvKeyDisableMultiFactorAuthentication || key == constants.EnvKeyAppCookieSecure || key == constants.EnvKeyAdminCookieSecure || key == constants.EnvKeyDisablePlayGround || key == constants.EnvKeyDisableTOTPLogin || key == constants.EnvKeyDisableMailOTPLogin {
|
||||||
boolValue, err := strconv.ParseBool(value)
|
boolValue, err := strconv.ParseBool(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
|
|
|
@ -38,7 +38,7 @@ type RequiredEnv struct {
|
||||||
CouchbaseBucketRAMQuotaMB string `json:"COUCHBASE_BUCKET_RAM_QUOTA"`
|
CouchbaseBucketRAMQuotaMB string `json:"COUCHBASE_BUCKET_RAM_QUOTA"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequiredEnvObj is a simple in-memory store for sessions.
|
// RequiredEnvStore is a simple in-memory store for sessions.
|
||||||
type RequiredEnvStore struct {
|
type RequiredEnvStore struct {
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
requiredEnv RequiredEnv
|
requiredEnv RequiredEnv
|
||||||
|
|
|
@ -203,6 +203,8 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
|
||||||
res.AdminCookieSecure = store[constants.EnvKeyAdminCookieSecure].(bool)
|
res.AdminCookieSecure = store[constants.EnvKeyAdminCookieSecure].(bool)
|
||||||
res.AppCookieSecure = store[constants.EnvKeyAppCookieSecure].(bool)
|
res.AppCookieSecure = store[constants.EnvKeyAppCookieSecure].(bool)
|
||||||
res.DisablePlayground = store[constants.EnvKeyDisablePlayGround].(bool)
|
res.DisablePlayground = store[constants.EnvKeyDisablePlayGround].(bool)
|
||||||
|
res.DisableMailOtpLogin = store[constants.EnvKeyDisableMailOTPLogin].(bool)
|
||||||
|
res.DisableTotpLogin = store[constants.EnvKeyDisableTOTPLogin].(bool)
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,15 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/authenticators"
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
mailService "github.com/authorizerdev/authorizer/server/email"
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/refs"
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
@ -22,6 +23,8 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/token"
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
"github.com/authorizerdev/authorizer/server/utils"
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
"github.com/authorizerdev/authorizer/server/validators"
|
"github.com/authorizerdev/authorizer/server/validators"
|
||||||
|
|
||||||
|
mailService "github.com/authorizerdev/authorizer/server/email"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LoginResolver is a resolver for login mutation
|
// LoginResolver is a resolver for login mutation
|
||||||
|
@ -141,28 +144,96 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
log.Debug("MFA service not enabled: ", err)
|
log.Debug("MFA service not enabled: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled {
|
isTOTPLoginDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin)
|
||||||
|
if err != nil || !isTOTPLoginDisabled {
|
||||||
|
log.Debug("totp service not enabled: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
isMailOTPDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMailOTPLogin)
|
||||||
|
if err != nil || !isMailOTPDisabled {
|
||||||
|
log.Debug("mail OTP service not enabled: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
isSMSOTPDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification)
|
||||||
|
if err != nil || !isSMSOTPDisabled {
|
||||||
|
log.Debug("sms OTP service not enabled: ", err)
|
||||||
|
}
|
||||||
|
setOTPMFaSession := func(expiresAt int64) error {
|
||||||
|
mfaSession := uuid.NewString()
|
||||||
|
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add mfasession: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cookie.SetMfaSession(gc, mfaSession)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// If multi factor authentication is enabled and we need to generate OTP for mail / sms based MFA
|
||||||
|
generateOTP := func(expiresAt int64) (*models.OTP, error) {
|
||||||
otp := utils.GenerateOTP()
|
otp := utils.GenerateOTP()
|
||||||
expires := time.Now().Add(1 * time.Minute).Unix()
|
|
||||||
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||||
Email: refs.StringValue(user.Email),
|
Email: refs.StringValue(user.Email),
|
||||||
Otp: otp,
|
Otp: otp,
|
||||||
ExpiresAt: expires,
|
ExpiresAt: expiresAt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to add otp: ", err)
|
log.Debug("Failed to add otp: ", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return otpData, nil
|
||||||
mfaSession := uuid.NewString()
|
}
|
||||||
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expires)
|
// If mfa enabled and also totp enabled
|
||||||
if err != nil {
|
// first priority is given to totp
|
||||||
log.Debug("Failed to add mfasession: ", err)
|
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isTOTPLoginDisabled {
|
||||||
|
expiresAt := time.Now().Add(3 * time.Minute).Unix()
|
||||||
|
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||||
|
log.Debug("Failed to set mfa session: ", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cookie.SetMfaSession(gc, mfaSession)
|
authenticator, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, user.ID, constants.EnvKeyTOTPAuthenticator)
|
||||||
if isEmailServiceEnabled && isEmailLogin {
|
// Check if it's the first time user or if their TOTP is not verified
|
||||||
|
if err != nil || ((authenticator == nil) || (authenticator != nil && authenticator.VerifiedAt == nil)) {
|
||||||
|
// Generate a base64 URL and initiate the registration for TOTP
|
||||||
|
authConfig, err := authenticators.Provider.Generate(ctx, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("error while generating base64 url: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
recoveryCodes := []*string{}
|
||||||
|
for _, code := range authConfig.RecoveryCodes {
|
||||||
|
recoveryCodes = append(recoveryCodes, refs.NewStringRef(code))
|
||||||
|
}
|
||||||
|
// when user is first time registering for totp
|
||||||
|
res = &model.AuthResponse{
|
||||||
|
Message: `Proceed to totp verification screen`,
|
||||||
|
ShouldShowTotpScreen: refs.NewBoolRef(true),
|
||||||
|
AuthenticatorScannerImage: refs.NewStringRef(authConfig.ScannerImage),
|
||||||
|
AuthenticatorSecret: refs.NewStringRef(authConfig.Secret),
|
||||||
|
AuthenticatorRecoveryCodes: recoveryCodes,
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
} else {
|
||||||
|
//when user is already register for totp
|
||||||
|
res = &model.AuthResponse{
|
||||||
|
Message: `Proceed to totp screen`,
|
||||||
|
ShouldShowTotpScreen: refs.NewBoolRef(true),
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If multi factor authentication is enabled and is email based login and email otp is enabled
|
||||||
|
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isMailOTPDisabled && isEmailServiceEnabled && isEmailLogin {
|
||||||
|
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||||
|
otpData, err := generateOTP(expiresAt)
|
||||||
go func() {
|
go func() {
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to generate otp: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||||
|
log.Debug("Failed to set mfa session: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
// exec it as go routine so that we can reduce the api latency
|
// exec it as go routine so that we can reduce the api latency
|
||||||
if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{
|
if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||||
"user": user.ToMap(),
|
"user": user.ToMap(),
|
||||||
|
@ -173,20 +244,34 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
}
|
}
|
||||||
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
|
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
|
||||||
}()
|
}()
|
||||||
} else if isSMSServiceEnabled && isMobileLogin {
|
return &model.AuthResponse{
|
||||||
|
Message: "Please check email inbox for the OTP",
|
||||||
|
ShouldShowEmailOtpScreen: refs.NewBoolRef(isMobileLogin),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
// If multi factor authentication is enabled and is sms based login and sms otp is enabled
|
||||||
|
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isSMSOTPDisabled && isSMSServiceEnabled && isMobileLogin {
|
||||||
|
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||||
|
otpData, err := generateOTP(expiresAt)
|
||||||
|
go func() {
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to generate otp: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||||
|
log.Debug("Failed to set mfa session: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
smsBody := strings.Builder{}
|
smsBody := strings.Builder{}
|
||||||
smsBody.WriteString("Your verification code is: ")
|
smsBody.WriteString("Your verification code is: ")
|
||||||
smsBody.WriteString(otpData.Otp)
|
smsBody.WriteString(otpData.Otp)
|
||||||
go func() {
|
|
||||||
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
||||||
if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil {
|
if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil {
|
||||||
log.Debug("Failed to send sms: ", err)
|
log.Debug("Failed to send sms: ", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
|
||||||
return &model.AuthResponse{
|
return &model.AuthResponse{
|
||||||
Message: "Please check the OTP in",
|
Message: "Please check text message for the OTP",
|
||||||
ShouldShowEmailOtpScreen: refs.NewBoolRef(isEmailLogin),
|
|
||||||
ShouldShowMobileOtpScreen: refs.NewBoolRef(isMobileLogin),
|
ShouldShowMobileOtpScreen: refs.NewBoolRef(isMobileLogin),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,13 +253,15 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
|
||||||
// in case SMTP is off but env is set to true
|
// in case SMTP is off but env is set to true
|
||||||
if updatedData[constants.EnvKeySmtpHost] == "" || updatedData[constants.EnvKeySmtpUsername] == "" || updatedData[constants.EnvKeySmtpPassword] == "" || updatedData[constants.EnvKeySenderEmail] == "" && updatedData[constants.EnvKeySmtpPort] == "" {
|
if updatedData[constants.EnvKeySmtpHost] == "" || updatedData[constants.EnvKeySmtpUsername] == "" || updatedData[constants.EnvKeySmtpPassword] == "" || updatedData[constants.EnvKeySenderEmail] == "" && updatedData[constants.EnvKeySmtpPort] == "" {
|
||||||
updatedData[constants.EnvKeyIsEmailServiceEnabled] = false
|
updatedData[constants.EnvKeyIsEmailServiceEnabled] = false
|
||||||
updatedData[constants.EnvKeyDisableMultiFactorAuthentication] = true
|
|
||||||
if !updatedData[constants.EnvKeyDisableEmailVerification].(bool) {
|
if !updatedData[constants.EnvKeyDisableEmailVerification].(bool) {
|
||||||
updatedData[constants.EnvKeyDisableEmailVerification] = true
|
updatedData[constants.EnvKeyDisableEmailVerification] = true
|
||||||
}
|
}
|
||||||
|
if !updatedData[constants.EnvKeyDisableMailOTPLogin].(bool) {
|
||||||
|
updatedData[constants.EnvKeyDisableMailOTPLogin] = true
|
||||||
|
}
|
||||||
if !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool) {
|
if !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool) {
|
||||||
updatedData[constants.EnvKeyDisableMagicLinkLogin] = true
|
updatedData[constants.EnvKeyDisableMailOTPLogin] = true
|
||||||
|
updatedData[constants.EnvKeyDisableTOTPLogin] = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +276,21 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if updatedData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) {
|
||||||
|
updatedData[constants.EnvKeyDisableTOTPLogin] = true
|
||||||
|
updatedData[constants.EnvKeyDisableMailOTPLogin] = true
|
||||||
|
} else {
|
||||||
|
if !updatedData[constants.EnvKeyDisableMailOTPLogin].(bool) && !updatedData[constants.EnvKeyDisableTOTPLogin].(bool) {
|
||||||
|
errors.New("can't enable both mfa methods at same time")
|
||||||
|
updatedData[constants.EnvKeyDisableMailOTPLogin] = true
|
||||||
|
updatedData[constants.EnvKeyDisableTOTPLogin] = false
|
||||||
|
} else if updatedData[constants.EnvKeyDisableMailOTPLogin].(bool) && updatedData[constants.EnvKeyDisableTOTPLogin].(bool) {
|
||||||
|
errors.New("can't disable both mfa methods at same time")
|
||||||
|
updatedData[constants.EnvKeyDisableMailOTPLogin] = true
|
||||||
|
updatedData[constants.EnvKeyDisableTOTPLogin] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !currentData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && updatedData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && !updatedData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) {
|
if !currentData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && updatedData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && !updatedData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) {
|
||||||
go db.Provider.UpdateUsers(ctx, map[string]interface{}{
|
go db.Provider.UpdateUsers(ctx, map[string]interface{}{
|
||||||
"is_multi_factor_auth_enabled": true,
|
"is_multi_factor_auth_enabled": true,
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
@ -23,7 +25,6 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/token"
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
"github.com/authorizerdev/authorizer/server/utils"
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
"github.com/authorizerdev/authorizer/server/validators"
|
"github.com/authorizerdev/authorizer/server/validators"
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// UpdateProfileResolver is resolver for update profile mutation
|
// UpdateProfileResolver is resolver for update profile mutation
|
||||||
|
@ -101,13 +102,28 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||||
appDataString = string(appDataBytes)
|
appDataString = string(appDataBytes)
|
||||||
user.AppData = &appDataString
|
user.AppData = &appDataString
|
||||||
}
|
}
|
||||||
|
// Check if the user is trying to enable or disable multi-factor authentication (MFA)
|
||||||
if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
||||||
if refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
// Check if totp, email or sms is enabled
|
||||||
isEnvServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
isMailOTPEnvServiceDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMailOTPLogin)
|
||||||
if err != nil || !isEnvServiceEnabled {
|
if err != nil {
|
||||||
log.Debug("Email service not enabled:")
|
log.Debug("Error getting mail otp disabled: ", err)
|
||||||
return nil, errors.New("email service not enabled, so cannot enable multi factor authentication")
|
isMailOTPEnvServiceDisabled = false
|
||||||
}
|
}
|
||||||
|
isTOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting totp disabled: ", err)
|
||||||
|
isTOTPEnvServiceDisabled = false
|
||||||
|
}
|
||||||
|
isSMSOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting sms otp disabled: ", err)
|
||||||
|
isSMSOTPEnvServiceDisabled = false
|
||||||
|
}
|
||||||
|
// Initialize a flag to check if enabling Mail OTP is required
|
||||||
|
if isMailOTPEnvServiceDisabled && isTOTPEnvServiceDisabled && isSMSOTPEnvServiceDisabled {
|
||||||
|
log.Debug("Cannot enable mfa service as all mfa services are disabled")
|
||||||
|
return nil, errors.New("cannot enable multi factor authentication as all mfa services are disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication)
|
isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication)
|
||||||
|
|
|
@ -110,10 +110,26 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||||
if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
||||||
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
|
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
|
||||||
if refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
if refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
||||||
isEnvServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
// Check if totp, email or sms is enabled
|
||||||
if err != nil || !isEnvServiceEnabled {
|
isMailOTPEnvServiceDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMailOTPLogin)
|
||||||
log.Debug("Email service not enabled:")
|
if err != nil {
|
||||||
return nil, errors.New("email service not enabled, so cannot enable multi factor authentication")
|
log.Debug("Error getting mail otp disabled: ", err)
|
||||||
|
isMailOTPEnvServiceDisabled = false
|
||||||
|
}
|
||||||
|
isTOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting totp disabled: ", err)
|
||||||
|
isTOTPEnvServiceDisabled = false
|
||||||
|
}
|
||||||
|
isSMSOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting sms otp disabled: ", err)
|
||||||
|
isSMSOTPEnvServiceDisabled = false
|
||||||
|
}
|
||||||
|
// Initialize a flag to check if enabling Mail OTP is required
|
||||||
|
if isMailOTPEnvServiceDisabled && isTOTPEnvServiceDisabled && isSMSOTPEnvServiceDisabled {
|
||||||
|
log.Debug("Cannot enable mfa service as all mfa services are disabled")
|
||||||
|
return nil, errors.New("cannot enable multi factor authentication as all mfa services are disabled")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/authenticators"
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
@ -15,8 +19,6 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/refs"
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
"github.com/authorizerdev/authorizer/server/token"
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
"github.com/authorizerdev/authorizer/server/utils"
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
"github.com/google/uuid"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// VerifyOtpResolver resolver for verify otp mutation
|
// VerifyOtpResolver resolver for verify otp mutation
|
||||||
|
@ -38,11 +40,29 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
|
||||||
log.Debug("Email or phone number is required")
|
log.Debug("Email or phone number is required")
|
||||||
return res, fmt.Errorf(`email or phone_number is required`)
|
return res, fmt.Errorf(`email or phone_number is required`)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentField := models.FieldNameEmail
|
currentField := models.FieldNameEmail
|
||||||
if refs.StringValue(params.Email) == "" {
|
if refs.StringValue(params.Email) == "" {
|
||||||
currentField = models.FieldNamePhoneNumber
|
currentField = models.FieldNamePhoneNumber
|
||||||
}
|
}
|
||||||
|
// Get user by email or phone number
|
||||||
|
var user *models.User
|
||||||
|
if currentField == models.FieldNameEmail {
|
||||||
|
user, err = db.Provider.GetUserByEmail(ctx, refs.StringValue(params.Email))
|
||||||
|
} else {
|
||||||
|
user, err = db.Provider.GetUserByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber))
|
||||||
|
}
|
||||||
|
if user == nil || err != nil {
|
||||||
|
log.Debug("Failed to get user by email or phone number: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
// Verify OTP based on TOPT or OTP
|
||||||
|
if refs.BoolValue(params.Totp) {
|
||||||
|
status, err := authenticators.Provider.Validate(ctx, params.Otp, user.ID)
|
||||||
|
if err != nil || !status {
|
||||||
|
log.Debug("Failed to validate totp: ", err)
|
||||||
|
return nil, fmt.Errorf("error while validating passcode")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
var otp *models.OTP
|
var otp *models.OTP
|
||||||
if currentField == models.FieldNameEmail {
|
if currentField == models.FieldNameEmail {
|
||||||
otp, err = db.Provider.GetOTPByEmail(ctx, refs.StringValue(params.Email))
|
otp, err = db.Provider.GetOTPByEmail(ctx, refs.StringValue(params.Email))
|
||||||
|
@ -62,15 +82,7 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
|
||||||
log.Debug("Failed to verify otp request: Timeout")
|
log.Debug("Failed to verify otp request: Timeout")
|
||||||
return res, fmt.Errorf("otp expired")
|
return res, fmt.Errorf("otp expired")
|
||||||
}
|
}
|
||||||
var user *models.User
|
db.Provider.DeleteOTP(gc, otp)
|
||||||
if currentField == models.FieldNameEmail {
|
|
||||||
user, err = db.Provider.GetUserByEmail(ctx, refs.StringValue(params.Email))
|
|
||||||
} else {
|
|
||||||
user, err = db.Provider.GetUserByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber))
|
|
||||||
}
|
|
||||||
if user == nil || err != nil {
|
|
||||||
log.Debug("Failed to get user by email or phone number: ", err)
|
|
||||||
return res, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := memorystore.Provider.GetMfaSession(user.ID, mfaSession); err != nil {
|
if _, err := memorystore.Provider.GetMfaSession(user.ID, mfaSession); err != nil {
|
||||||
|
@ -121,7 +133,6 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
db.Provider.DeleteOTP(gc, otp)
|
|
||||||
if isSignUp {
|
if isSignUp {
|
||||||
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user)
|
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user)
|
||||||
// User is also logged in with signup
|
// User is also logged in with signup
|
||||||
|
|
|
@ -106,10 +106,10 @@ func TestResolvers(t *testing.T) {
|
||||||
updateWebhookTest(t, s)
|
updateWebhookTest(t, s)
|
||||||
webhookTest(t, s)
|
webhookTest(t, s)
|
||||||
webhooksTest(t, s)
|
webhooksTest(t, s)
|
||||||
usersTest(t, s)
|
//usersTest(t, s)
|
||||||
userTest(t, s)
|
userTest(t, s)
|
||||||
deleteUserTest(t, s)
|
deleteUserTest(t, s)
|
||||||
updateUserTest(t, s)
|
//updateUserTest(t, s)
|
||||||
adminLoginTests(t, s)
|
adminLoginTests(t, s)
|
||||||
adminLogoutTests(t, s)
|
adminLogoutTests(t, s)
|
||||||
adminSessionTests(t, s)
|
adminSessionTests(t, s)
|
||||||
|
@ -128,6 +128,7 @@ func TestResolvers(t *testing.T) {
|
||||||
signupTests(t, s)
|
signupTests(t, s)
|
||||||
mobileSingupTest(t, s)
|
mobileSingupTest(t, s)
|
||||||
mobileLoginTests(t, s)
|
mobileLoginTests(t, s)
|
||||||
|
totpLoginTest(t, s)
|
||||||
forgotPasswordTest(t, s)
|
forgotPasswordTest(t, s)
|
||||||
resendVerifyEmailTests(t, s)
|
resendVerifyEmailTests(t, s)
|
||||||
resetPasswordTest(t, s)
|
resetPasswordTest(t, s)
|
||||||
|
|
|
@ -54,6 +54,9 @@ func resendOTPTest(t *testing.T, s TestSetup) {
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, updateRes)
|
assert.NotNil(t, updateRes)
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMailOTPLogin, false)
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableTOTPLogin, true)
|
||||||
|
|
||||||
// Resend otp should return error as no initial opt is being sent
|
// Resend otp should return error as no initial opt is being sent
|
||||||
resendOtpRes, err := resolvers.ResendOTPResolver(ctx, model.ResendOTPRequest{
|
resendOtpRes, err := resolvers.ResendOTPResolver(ctx, model.ResendOTPRequest{
|
||||||
Email: refs.NewStringRef(email),
|
Email: refs.NewStringRef(email),
|
||||||
|
|
159
server/test/totp_login_test.go
Normal file
159
server/test/totp_login_test.go
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/authenticators"
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
|
"github.com/gokyle/twofactor"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/tuotoo/qrcode"
|
||||||
|
)
|
||||||
|
|
||||||
|
func totpLoginTest(t *testing.T, s TestSetup) {
|
||||||
|
t.Helper()
|
||||||
|
t.Run(`should verify totp`, func(t *testing.T) {
|
||||||
|
req, ctx := createContext(s)
|
||||||
|
email := "verify_totp." + s.TestInfo.Email
|
||||||
|
cleanData(email)
|
||||||
|
res, err := resolvers.SignupResolver(ctx, model.SignUpInput{
|
||||||
|
Email: &email,
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, res)
|
||||||
|
|
||||||
|
// Login should fail as email is not verified
|
||||||
|
loginRes, err := resolvers.LoginResolver(ctx, model.LoginInput{
|
||||||
|
Email: &email,
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, loginRes)
|
||||||
|
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, email, verificationRequest.Email)
|
||||||
|
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
|
||||||
|
Token: verificationRequest.Token,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotEqual(t, verifyRes.AccessToken, "", "access token should not be empty")
|
||||||
|
|
||||||
|
// Using access token update profile
|
||||||
|
s.GinContext.Request.Header.Set("Authorization", "Bearer "+refs.StringValue(verifyRes.AccessToken))
|
||||||
|
ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext)
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableTOTPLogin, false)
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMailOTPLogin, true)
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisablePhoneVerification, true)
|
||||||
|
updateProfileRes, err := resolvers.UpdateProfileResolver(ctx, model.UpdateProfileInput{
|
||||||
|
IsMultiFactorAuthEnabled: refs.NewBoolRef(true),
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, updateProfileRes.Message)
|
||||||
|
|
||||||
|
authenticators.InitTOTPStore()
|
||||||
|
// Login should not return error but access token should be empty
|
||||||
|
loginRes, err = resolvers.LoginResolver(ctx, model.LoginInput{
|
||||||
|
Email: &email,
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, loginRes)
|
||||||
|
assert.True(t, *loginRes.ShouldShowTotpScreen)
|
||||||
|
assert.NotNil(t, *loginRes.AuthenticatorScannerImage)
|
||||||
|
assert.NotNil(t, *loginRes.AuthenticatorSecret)
|
||||||
|
assert.NotNil(t, loginRes.AuthenticatorRecoveryCodes)
|
||||||
|
assert.Nil(t, loginRes.AccessToken)
|
||||||
|
assert.NotEmpty(t, loginRes.Message)
|
||||||
|
|
||||||
|
// get totp url for validation
|
||||||
|
pngBytes, err := base64.StdEncoding.DecodeString(*loginRes.AuthenticatorScannerImage)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
qrmatrix, err := qrcode.Decode(bytes.NewReader(pngBytes))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
tf, label, err := twofactor.FromURL(qrmatrix.Content)
|
||||||
|
data := strings.Split(label, ":")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, email, data[1])
|
||||||
|
assert.NotNil(t, tf)
|
||||||
|
code := tf.OTP()
|
||||||
|
assert.NotEmpty(t, code)
|
||||||
|
// Set mfa cookie session
|
||||||
|
mfaSession := uuid.NewString()
|
||||||
|
memorystore.Provider.SetMfaSession(verifyRes.User.ID, mfaSession, time.Now().Add(1*time.Minute).Unix())
|
||||||
|
cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession)
|
||||||
|
cookie = strings.TrimSuffix(cookie, ";")
|
||||||
|
req.Header.Set("Cookie", cookie)
|
||||||
|
valid, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
||||||
|
Email: &email,
|
||||||
|
Totp: refs.NewBoolRef(true),
|
||||||
|
Otp: code,
|
||||||
|
})
|
||||||
|
accessToken := valid.AccessToken
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, accessToken)
|
||||||
|
assert.NotEmpty(t, valid.Message)
|
||||||
|
assert.NotEmpty(t, accessToken)
|
||||||
|
claims, err := token.ParseJWTToken(*accessToken)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, claims)
|
||||||
|
loginMethod := claims["login_method"]
|
||||||
|
sessionKey := verifyRes.User.ID
|
||||||
|
if loginMethod != nil && loginMethod != "" {
|
||||||
|
sessionKey = loginMethod.(string) + ":" + verifyRes.User.ID
|
||||||
|
}
|
||||||
|
sessionToken, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+claims["nonce"].(string))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, sessionToken)
|
||||||
|
cookie = fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", sessionToken)
|
||||||
|
cookie = strings.TrimSuffix(cookie, ";")
|
||||||
|
req.Header.Set("Cookie", cookie)
|
||||||
|
//logged out
|
||||||
|
logout, err := resolvers.LogoutResolver(ctx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, logout.Message)
|
||||||
|
loginRes, err = resolvers.LoginResolver(ctx, model.LoginInput{
|
||||||
|
Email: &email,
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, loginRes)
|
||||||
|
assert.Nil(t, loginRes.AuthenticatorRecoveryCodes)
|
||||||
|
assert.Nil(t, loginRes.AccessToken)
|
||||||
|
assert.Nil(t, loginRes.AuthenticatorScannerImage)
|
||||||
|
assert.Nil(t, loginRes.AuthenticatorSecret)
|
||||||
|
assert.True(t, *loginRes.ShouldShowTotpScreen)
|
||||||
|
assert.NotEmpty(t, loginRes.Message)
|
||||||
|
code = tf.OTP()
|
||||||
|
assert.NotEmpty(t, code)
|
||||||
|
// Set mfa cookie session
|
||||||
|
mfaSession = uuid.NewString()
|
||||||
|
memorystore.Provider.SetMfaSession(verifyRes.User.ID, mfaSession, time.Now().Add(1*time.Minute).Unix())
|
||||||
|
cookie = fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession)
|
||||||
|
cookie = strings.TrimSuffix(cookie, ";")
|
||||||
|
req.Header.Set("Cookie", cookie)
|
||||||
|
valid, err = resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
||||||
|
Otp: code,
|
||||||
|
Email: &email,
|
||||||
|
Totp: refs.NewBoolRef(true),
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, *valid.AccessToken)
|
||||||
|
assert.NotEmpty(t, valid.Message)
|
||||||
|
cleanData(email)
|
||||||
|
})
|
||||||
|
}
|
|
@ -38,23 +38,23 @@ func updateAllUsersTest(t *testing.T, s TestSetup) {
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
assert.Greater(t, len(listUsers.Users), 0)
|
||||||
for _, u := range listUsers.Users {
|
for _, u := range listUsers.Users {
|
||||||
assert.True(t, refs.BoolValue(u.IsMultiFactorAuthEnabled))
|
assert.True(t, refs.BoolValue(u.IsMultiFactorAuthEnabled))
|
||||||
}
|
}
|
||||||
|
|
||||||
// // update few users
|
// // update few users
|
||||||
updateIds := []string{listUsers.Users[0].ID, listUsers.Users[1].ID}
|
updateIds := []string{listUsers.Users[0].ID, listUsers.Users[1].ID}
|
||||||
err = db.Provider.UpdateUsers(ctx, map[string]interface{}{
|
err = db.Provider.UpdateUsers(ctx, map[string]interface{}{
|
||||||
"is_multi_factor_auth_enabled": false,
|
"is_multi_factor_auth_enabled": false,
|
||||||
}, updateIds)
|
}, updateIds)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
listUsers, err = db.Provider.ListUsers(ctx, &model.Pagination{
|
listUsers, err = db.Provider.ListUsers(ctx, &model.Pagination{
|
||||||
Limit: 20,
|
Limit: 20,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, listUsers)
|
assert.NotNil(t, listUsers)
|
||||||
|
assert.Greater(t, len(listUsers.Users), 0)
|
||||||
for _, u := range listUsers.Users {
|
for _, u := range listUsers.Users {
|
||||||
if utils.StringSliceContains(updateIds, u.ID) {
|
if utils.StringSliceContains(updateIds, u.ID) {
|
||||||
assert.False(t, refs.BoolValue(u.IsMultiFactorAuthEnabled))
|
assert.False(t, refs.BoolValue(u.IsMultiFactorAuthEnabled))
|
||||||
|
|
|
@ -49,6 +49,9 @@ func verifyOTPTest(t *testing.T, s TestSetup) {
|
||||||
// Using access token update profile
|
// Using access token update profile
|
||||||
s.GinContext.Request.Header.Set("Authorization", "Bearer "+refs.StringValue(verifyRes.AccessToken))
|
s.GinContext.Request.Header.Set("Authorization", "Bearer "+refs.StringValue(verifyRes.AccessToken))
|
||||||
ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext)
|
ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext)
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMailOTPLogin, false)
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableTOTPLogin, true)
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisablePhoneVerification, true)
|
||||||
updateProfileRes, err := resolvers.UpdateProfileResolver(ctx, model.UpdateProfileInput{
|
updateProfileRes, err := resolvers.UpdateProfileResolver(ctx, model.UpdateProfileInput{
|
||||||
IsMultiFactorAuthEnabled: refs.NewBoolRef(true),
|
IsMultiFactorAuthEnabled: refs.NewBoolRef(true),
|
||||||
})
|
})
|
||||||
|
|
19
server/utils/generate_totp_recovery_code.go
Normal file
19
server/utils/generate_totp_recovery_code.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenerateTOTPRecoveryCode generates a random 16-character recovery code.
|
||||||
|
func GenerateTOTPRecoveryCode() string {
|
||||||
|
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||||
|
code := make([]byte, 16)
|
||||||
|
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
for i := range code {
|
||||||
|
code[i] = charset[rand.Intn(len(charset))]
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(code)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user