diff --git a/.env.test b/.env.test index 99c8081..293248a 100644 --- a/.env.test +++ b/.env.test @@ -7,5 +7,9 @@ SMTP_PORT=2525 SMTP_USERNAME=test SMTP_PASSWORD=test SENDER_EMAIL="info@authorizer.dev" +TWILIO_API_KEY=test +TWILIO_API_SECRET=test +TWILIO_ACCOUNT_SID=ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +TWILIO_SENDER=909921212112 SENDER_NAME="Authorizer" AWS_REGION=ap-south-1 \ No newline at end of file diff --git a/app/package-lock.json b/app/package-lock.json index cf332cb..1b7f5a4 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@authorizerdev/authorizer-react": "^1.1.11", + "@authorizerdev/authorizer-react": "^1.1.13", "@types/react": "^17.0.15", "@types/react-dom": "^17.0.9", "esbuild": "^0.12.17", @@ -27,9 +27,9 @@ } }, "node_modules/@authorizerdev/authorizer-js": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.3.tgz", - "integrity": "sha512-rk/fMRIsqbp+fsy2y09etVjf7CY9/4mG6hf0RKgXgRRfxtAQa1jdkt/De23hBTNeEwAWu6hP/9BQZjcrln6KtA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.6.tgz", + "integrity": "sha512-9+9phHUMF+AeDM0y+XQvIRDoerOXnQ1vfTfYN6KxWN1apdrkAd9nzS1zUsA2uJSnX3fFZOErn83GjbYYCYF1BA==", "dependencies": { "cross-fetch": "^3.1.5" }, @@ -41,11 +41,11 @@ } }, "node_modules/@authorizerdev/authorizer-react": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.11.tgz", - "integrity": "sha512-tSI/yjsoeK/RvCOMiHSf1QGOeSpaLYQZEM864LFLndKoJwk7UWCJ86qg1w6ge7B00PmZSNWqST/w5JTcQaVNpw==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.13.tgz", + "integrity": "sha512-LmpzyfR0+nEn+bjUrb/QU9b3kiVoYzMBIvcQ1nV4TNvrvVSqbLPKk+GmoIPkiBEtfy/QSM6XFLkiGNGD9BRP+g==", "dependencies": { - "@authorizerdev/authorizer-js": "^1.2.3" + "@authorizerdev/authorizer-js": "^1.2.6" }, "engines": { "node": ">=10" @@ -406,11 +406,11 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "node_modules/cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", "dependencies": { - "node-fetch": "2.6.7" + "node-fetch": "^2.6.12" } }, "node_modules/css-color-keywords": { @@ -567,9 +567,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -837,19 +837,19 @@ }, "dependencies": { "@authorizerdev/authorizer-js": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.3.tgz", - "integrity": "sha512-rk/fMRIsqbp+fsy2y09etVjf7CY9/4mG6hf0RKgXgRRfxtAQa1jdkt/De23hBTNeEwAWu6hP/9BQZjcrln6KtA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.6.tgz", + "integrity": "sha512-9+9phHUMF+AeDM0y+XQvIRDoerOXnQ1vfTfYN6KxWN1apdrkAd9nzS1zUsA2uJSnX3fFZOErn83GjbYYCYF1BA==", "requires": { "cross-fetch": "^3.1.5" } }, "@authorizerdev/authorizer-react": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.11.tgz", - "integrity": "sha512-tSI/yjsoeK/RvCOMiHSf1QGOeSpaLYQZEM864LFLndKoJwk7UWCJ86qg1w6ge7B00PmZSNWqST/w5JTcQaVNpw==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.13.tgz", + "integrity": "sha512-LmpzyfR0+nEn+bjUrb/QU9b3kiVoYzMBIvcQ1nV4TNvrvVSqbLPKk+GmoIPkiBEtfy/QSM6XFLkiGNGD9BRP+g==", "requires": { - "@authorizerdev/authorizer-js": "^1.2.3" + "@authorizerdev/authorizer-js": "^1.2.6" } }, "@babel/code-frame": { @@ -1144,11 +1144,11 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", "requires": { - "node-fetch": "2.6.7" + "node-fetch": "^2.6.12" } }, "css-color-keywords": { @@ -1270,9 +1270,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", "requires": { "whatwg-url": "^5.0.0" } diff --git a/app/package.json b/app/package.json index 1225346..2406108 100644 --- a/app/package.json +++ b/app/package.json @@ -12,7 +12,7 @@ "author": "Lakhan Samani", "license": "ISC", "dependencies": { - "@authorizerdev/authorizer-react": "^1.1.11", + "@authorizerdev/authorizer-react": "^1.1.13", "@types/react": "^17.0.15", "@types/react-dom": "^17.0.9", "esbuild": "^0.12.17", diff --git a/app/yarn.lock b/app/yarn.lock index 62aa3c4..2be982c 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -2,126 +2,126 @@ # yarn lockfile v1 -"@authorizerdev/authorizer-js@^1.2.3": - version "1.2.3" - resolved "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.3.tgz" - integrity sha512-rk/fMRIsqbp+fsy2y09etVjf7CY9/4mG6hf0RKgXgRRfxtAQa1jdkt/De23hBTNeEwAWu6hP/9BQZjcrln6KtA== +"@authorizerdev/authorizer-js@^1.2.6": + "integrity" "sha512-9+9phHUMF+AeDM0y+XQvIRDoerOXnQ1vfTfYN6KxWN1apdrkAd9nzS1zUsA2uJSnX3fFZOErn83GjbYYCYF1BA==" + "resolved" "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.6.tgz" + "version" "1.2.6" dependencies: - cross-fetch "^3.1.5" + "cross-fetch" "^3.1.5" -"@authorizerdev/authorizer-react@^1.1.11": - version "1.1.11" - resolved "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.11.tgz" - integrity sha512-tSI/yjsoeK/RvCOMiHSf1QGOeSpaLYQZEM864LFLndKoJwk7UWCJ86qg1w6ge7B00PmZSNWqST/w5JTcQaVNpw== +"@authorizerdev/authorizer-react@^1.1.13": + "integrity" "sha512-LmpzyfR0+nEn+bjUrb/QU9b3kiVoYzMBIvcQ1nV4TNvrvVSqbLPKk+GmoIPkiBEtfy/QSM6XFLkiGNGD9BRP+g==" + "resolved" "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.13.tgz" + "version" "1.1.13" dependencies: - "@authorizerdev/authorizer-js" "^1.2.3" + "@authorizerdev/authorizer-js" "^1.2.6" "@babel/code-frame@^7.16.7": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + "integrity" "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==" + "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz" + "version" "7.16.7" dependencies: "@babel/highlight" "^7.16.7" "@babel/generator@^7.16.8": - version "7.16.8" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz" - integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw== + "integrity" "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==" + "resolved" "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz" + "version" "7.16.8" dependencies: "@babel/types" "^7.16.8" - jsesc "^2.5.1" - source-map "^0.5.0" + "jsesc" "^2.5.1" + "source-map" "^0.5.0" "@babel/helper-annotate-as-pure@^7.16.0": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz" - integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== + "integrity" "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==" + "resolved" "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz" + "version" "7.16.7" dependencies: "@babel/types" "^7.16.7" "@babel/helper-environment-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz" - integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + "integrity" "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==" + "resolved" "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz" + "version" "7.16.7" dependencies: "@babel/types" "^7.16.7" "@babel/helper-function-name@^7.16.7": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz" - integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + "integrity" "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==" + "resolved" "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz" + "version" "7.16.7" dependencies: "@babel/helper-get-function-arity" "^7.16.7" "@babel/template" "^7.16.7" "@babel/types" "^7.16.7" "@babel/helper-get-function-arity@^7.16.7": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz" - integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + "integrity" "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==" + "resolved" "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz" + "version" "7.16.7" dependencies: "@babel/types" "^7.16.7" "@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== + "integrity" "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==" + "resolved" "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz" + "version" "7.16.7" dependencies: "@babel/types" "^7.16.7" "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.0": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + "integrity" "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz" + "version" "7.16.7" dependencies: "@babel/types" "^7.16.7" "@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + "integrity" "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==" + "resolved" "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz" + "version" "7.16.7" dependencies: "@babel/types" "^7.16.7" "@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + "integrity" "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz" + "version" "7.16.7" "@babel/highlight@^7.16.7": - version "7.16.10" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz" - integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== + "integrity" "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==" + "resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz" + "version" "7.16.10" dependencies: "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" + "chalk" "^2.0.0" + "js-tokens" "^4.0.0" "@babel/parser@^7.16.10", "@babel/parser@^7.16.7": - version "7.16.12" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.16.12.tgz" - integrity sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A== + "integrity" "sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A==" + "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.16.12.tgz" + "version" "7.16.12" "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1": - version "7.14.8" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz" - integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg== + "integrity" "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==" + "resolved" "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz" + "version" "7.14.8" dependencies: - regenerator-runtime "^0.13.4" + "regenerator-runtime" "^0.13.4" "@babel/template@^7.16.7": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + "integrity" "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==" + "resolved" "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz" + "version" "7.16.7" dependencies: "@babel/code-frame" "^7.16.7" "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" "@babel/traverse@^7.4.5": - version "7.16.10" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.10.tgz" - integrity sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw== + "integrity" "sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw==" + "resolved" "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.10.tgz" + "version" "7.16.10" dependencies: "@babel/code-frame" "^7.16.7" "@babel/generator" "^7.16.8" @@ -131,458 +131,458 @@ "@babel/helper-split-export-declaration" "^7.16.7" "@babel/parser" "^7.16.10" "@babel/types" "^7.16.8" - debug "^4.1.0" - globals "^11.1.0" + "debug" "^4.1.0" + "globals" "^11.1.0" "@babel/types@^7.16.7", "@babel/types@^7.16.8": - version "7.16.8" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz" - integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== + "integrity" "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==" + "resolved" "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz" + "version" "7.16.8" dependencies: "@babel/helper-validator-identifier" "^7.16.7" - to-fast-properties "^2.0.0" + "to-fast-properties" "^2.0.0" "@emotion/is-prop-valid@^0.8.8": - version "0.8.8" - resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz" - integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== + "integrity" "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==" + "resolved" "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz" + "version" "0.8.8" dependencies: "@emotion/memoize" "0.7.4" "@emotion/memoize@0.7.4": - version "0.7.4" - resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz" - integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== + "integrity" "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + "resolved" "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz" + "version" "0.7.4" "@emotion/stylis@^0.8.4": - version "0.8.5" - resolved "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz" - integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== + "integrity" "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + "resolved" "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz" + "version" "0.8.5" "@emotion/unitless@^0.7.4": - version "0.7.5" - resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz" - integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + "integrity" "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + "resolved" "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz" + "version" "0.7.5" "@types/history@*": - version "4.7.9" - resolved "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz" - integrity sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ== + "integrity" "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==" + "resolved" "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz" + "version" "4.7.9" "@types/hoist-non-react-statics@*": - version "3.3.1" - resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + "integrity" "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==" + "resolved" "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz" + "version" "3.3.1" dependencies: "@types/react" "*" - hoist-non-react-statics "^3.3.0" + "hoist-non-react-statics" "^3.3.0" "@types/prop-types@*": - version "15.7.4" - resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz" - integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== + "integrity" "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + "resolved" "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz" + "version" "15.7.4" "@types/react-dom@^17.0.9": - version "17.0.9" - resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz" - integrity sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg== + "integrity" "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==" + "resolved" "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz" + "version" "17.0.9" dependencies: "@types/react" "*" "@types/react-router-dom@^5.1.8": - version "5.1.8" - resolved "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.8.tgz" - integrity sha512-03xHyncBzG0PmDmf8pf3rehtjY0NpUj7TIN46FrT5n1ZWHPZvXz32gUyNboJ+xsL8cpg8bQVLcllptcQHvocrw== + "integrity" "sha512-03xHyncBzG0PmDmf8pf3rehtjY0NpUj7TIN46FrT5n1ZWHPZvXz32gUyNboJ+xsL8cpg8bQVLcllptcQHvocrw==" + "resolved" "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.8.tgz" + "version" "5.1.8" dependencies: "@types/history" "*" "@types/react" "*" "@types/react-router" "*" "@types/react-router@*": - version "5.1.16" - resolved "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz" - integrity sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg== + "integrity" "sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg==" + "resolved" "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz" + "version" "5.1.16" dependencies: "@types/history" "*" "@types/react" "*" "@types/react@*", "@types/react@^17.0.15": - version "17.0.15" - resolved "https://registry.npmjs.org/@types/react/-/react-17.0.15.tgz" - integrity sha512-uTKHDK9STXFHLaKv6IMnwp52fm0hwU+N89w/p9grdUqcFA6WuqDyPhaWopbNyE1k/VhgzmHl8pu1L4wITtmlLw== + "integrity" "sha512-uTKHDK9STXFHLaKv6IMnwp52fm0hwU+N89w/p9grdUqcFA6WuqDyPhaWopbNyE1k/VhgzmHl8pu1L4wITtmlLw==" + "resolved" "https://registry.npmjs.org/@types/react/-/react-17.0.15.tgz" + "version" "17.0.15" dependencies: "@types/prop-types" "*" "@types/scheduler" "*" - csstype "^3.0.2" + "csstype" "^3.0.2" "@types/scheduler@*": - version "0.16.2" - resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + "integrity" "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + "resolved" "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" + "version" "0.16.2" "@types/styled-components@^5.1.11": - version "5.1.25" - resolved "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.25.tgz" - integrity sha512-fgwl+0Pa8pdkwXRoVPP9JbqF0Ivo9llnmsm+7TCI330kbPIFd9qv1Lrhr37shf4tnxCOSu+/IgqM7uJXLWZZNQ== + "integrity" "sha512-fgwl+0Pa8pdkwXRoVPP9JbqF0Ivo9llnmsm+7TCI330kbPIFd9qv1Lrhr37shf4tnxCOSu+/IgqM7uJXLWZZNQ==" + "resolved" "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.25.tgz" + "version" "5.1.25" dependencies: "@types/hoist-non-react-statics" "*" "@types/react" "*" - csstype "^3.0.2" + "csstype" "^3.0.2" -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== +"ansi-styles@^3.2.1": + "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + "version" "3.2.1" dependencies: - color-convert "^1.9.0" + "color-convert" "^1.9.0" "babel-plugin-styled-components@>= 1.12.0": - version "2.0.2" - resolved "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.2.tgz" - integrity sha512-7eG5NE8rChnNTDxa6LQfynwgHTVOYYaHJbUYSlOhk8QBXIQiMBKq4gyfHBBKPrxUcVBXVJL61ihduCpCQbuNbw== + "integrity" "sha512-7eG5NE8rChnNTDxa6LQfynwgHTVOYYaHJbUYSlOhk8QBXIQiMBKq4gyfHBBKPrxUcVBXVJL61ihduCpCQbuNbw==" + "resolved" "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.2.tgz" + "version" "2.0.2" dependencies: "@babel/helper-annotate-as-pure" "^7.16.0" "@babel/helper-module-imports" "^7.16.0" - babel-plugin-syntax-jsx "^6.18.0" - lodash "^4.17.11" + "babel-plugin-syntax-jsx" "^6.18.0" + "lodash" "^4.17.11" -babel-plugin-syntax-jsx@^6.18.0: - version "6.18.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz" - integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= +"babel-plugin-syntax-jsx@^6.18.0": + "integrity" "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" + "resolved" "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz" + "version" "6.18.0" -camelize@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz" - integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= +"camelize@^1.0.0": + "integrity" "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + "resolved" "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz" + "version" "1.0.0" -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== +"chalk@^2.0.0": + "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + "version" "2.4.2" dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" + "ansi-styles" "^3.2.1" + "escape-string-regexp" "^1.0.5" + "supports-color" "^5.3.0" -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== +"color-convert@^1.9.0": + "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + "version" "1.9.3" dependencies: - color-name "1.1.3" + "color-name" "1.1.3" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +"color-name@1.1.3": + "integrity" "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + "version" "1.1.3" -cross-fetch@^3.1.5: - version "3.1.5" - resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== +"cross-fetch@^3.1.5": + "integrity" "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==" + "resolved" "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz" + "version" "3.1.8" dependencies: - node-fetch "2.6.7" + "node-fetch" "^2.6.12" -css-color-keywords@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz" - integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU= +"css-color-keywords@^1.0.0": + "integrity" "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=" + "resolved" "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz" + "version" "1.0.0" -css-to-react-native@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz" - integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ== +"css-to-react-native@^3.0.0": + "integrity" "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==" + "resolved" "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz" + "version" "3.0.0" dependencies: - camelize "^1.0.0" - css-color-keywords "^1.0.0" - postcss-value-parser "^4.0.2" + "camelize" "^1.0.0" + "css-color-keywords" "^1.0.0" + "postcss-value-parser" "^4.0.2" -csstype@^3.0.2: - version "3.0.8" - resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz" - integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw== +"csstype@^3.0.2": + "integrity" "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" + "resolved" "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz" + "version" "3.0.8" -debug@^4.1.0: - version "4.3.3" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== +"debug@^4.1.0": + "integrity" "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==" + "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz" + "version" "4.3.3" dependencies: - ms "2.1.2" + "ms" "2.1.2" -esbuild@^0.12.17: - version "0.12.17" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.12.17.tgz" - integrity sha512-GshKJyVYUnlSXIZj/NheC2O0Kblh42CS7P1wJyTbbIHevTG4jYMS9NNw8EOd8dDWD0dzydYHS01MpZoUcQXB4g== +"esbuild@^0.12.17": + "integrity" "sha512-GshKJyVYUnlSXIZj/NheC2O0Kblh42CS7P1wJyTbbIHevTG4jYMS9NNw8EOd8dDWD0dzydYHS01MpZoUcQXB4g==" + "resolved" "https://registry.npmjs.org/esbuild/-/esbuild-0.12.17.tgz" + "version" "0.12.17" -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +"escape-string-regexp@^1.0.5": + "integrity" "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + "version" "1.0.5" -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +"globals@^11.1.0": + "integrity" "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "resolved" "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + "version" "11.12.0" -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +"has-flag@^3.0.0": + "integrity" "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + "version" "3.0.0" -history@^4.9.0: - version "4.10.1" - resolved "https://registry.npmjs.org/history/-/history-4.10.1.tgz" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== +"history@^4.9.0": + "integrity" "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==" + "resolved" "https://registry.npmjs.org/history/-/history-4.10.1.tgz" + "version" "4.10.1" dependencies: "@babel/runtime" "^7.1.2" - loose-envify "^1.2.0" - resolve-pathname "^3.0.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - value-equal "^1.0.1" + "loose-envify" "^1.2.0" + "resolve-pathname" "^3.0.0" + "tiny-invariant" "^1.0.2" + "tiny-warning" "^1.0.0" + "value-equal" "^1.0.1" -hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0: - version "3.3.2" - resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== +"hoist-non-react-statics@^3.0.0", "hoist-non-react-statics@^3.1.0", "hoist-non-react-statics@^3.3.0": + "integrity" "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==" + "resolved" "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" + "version" "3.3.2" dependencies: - react-is "^16.7.0" + "react-is" "^16.7.0" -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= +"isarray@0.0.1": + "integrity" "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "resolved" "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + "version" "0.0.1" -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +"js-tokens@^3.0.0 || ^4.0.0", "js-tokens@^4.0.0": + "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + "version" "4.0.0" -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +"jsesc@^2.5.1": + "integrity" "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + "version" "2.5.2" -lodash@^4.17.11: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +"lodash@^4.17.11": + "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + "version" "4.17.21" -loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== +"loose-envify@^1.1.0", "loose-envify@^1.2.0", "loose-envify@^1.3.1", "loose-envify@^1.4.0": + "integrity" "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==" + "resolved" "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + "version" "1.4.0" dependencies: - js-tokens "^3.0.0 || ^4.0.0" + "js-tokens" "^3.0.0 || ^4.0.0" -mini-create-react-context@^0.4.0: - version "0.4.1" - resolved "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz" - integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== +"mini-create-react-context@^0.4.0": + "integrity" "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==" + "resolved" "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz" + "version" "0.4.1" dependencies: "@babel/runtime" "^7.12.1" - tiny-warning "^1.0.3" + "tiny-warning" "^1.0.3" -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +"ms@2.1.2": + "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + "version" "2.1.2" -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== +"node-fetch@^2.6.12": + "integrity" "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==" + "resolved" "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz" + "version" "2.6.12" dependencies: - whatwg-url "^5.0.0" + "whatwg-url" "^5.0.0" -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= +"object-assign@^4.1.1": + "integrity" "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "resolved" "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + "version" "4.1.1" -path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== +"path-to-regexp@^1.7.0": + "integrity" "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==" + "resolved" "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz" + "version" "1.8.0" dependencies: - isarray "0.0.1" + "isarray" "0.0.1" -postcss-value-parser@^4.0.2: - version "4.2.0" - resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" - integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== +"postcss-value-parser@^4.0.2": + "integrity" "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + "resolved" "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" + "version" "4.2.0" -prettier@2.7.1: - version "2.7.1" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz" - integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== +"prettier@2.7.1": + "integrity" "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==" + "resolved" "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz" + "version" "2.7.1" -prop-types@^15.0.0, prop-types@^15.6.2: - version "15.7.2" - resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== +"prop-types@^15.0.0", "prop-types@^15.6.2": + "integrity" "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==" + "resolved" "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz" + "version" "15.7.2" dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.8.1" + "loose-envify" "^1.4.0" + "object-assign" "^4.1.1" + "react-is" "^16.8.1" -react-dom@^17.0.2, "react-dom@>= 16.8.0": - version "17.0.2" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== +"react-dom@^17.0.2", "react-dom@>= 16.8.0": + "integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==" + "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" + "version" "17.0.2" dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" + "loose-envify" "^1.1.0" + "object-assign" "^4.1.1" + "scheduler" "^0.20.2" -react-is@^16.6.0: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +"react-is@^16.6.0": + "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + "version" "16.13.1" -react-is@^16.7.0: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +"react-is@^16.7.0": + "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + "version" "16.13.1" -react-is@^16.8.1: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +"react-is@^16.8.1": + "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + "version" "16.13.1" -react-is@^17.0.2, "react-is@>= 16.8.0": - version "17.0.2" - resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +"react-is@^17.0.2", "react-is@>= 16.8.0": + "integrity" "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + "resolved" "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" + "version" "17.0.2" -react-router-dom@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz" - integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== +"react-router-dom@^5.2.0": + "integrity" "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==" + "resolved" "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz" + "version" "5.2.0" dependencies: "@babel/runtime" "^7.1.2" - history "^4.9.0" - loose-envify "^1.3.1" - prop-types "^15.6.2" - react-router "5.2.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" + "history" "^4.9.0" + "loose-envify" "^1.3.1" + "prop-types" "^15.6.2" + "react-router" "5.2.0" + "tiny-invariant" "^1.0.2" + "tiny-warning" "^1.0.0" -react-router@5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz" - integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== +"react-router@5.2.0": + "integrity" "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==" + "resolved" "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz" + "version" "5.2.0" dependencies: "@babel/runtime" "^7.1.2" - history "^4.9.0" - hoist-non-react-statics "^3.1.0" - loose-envify "^1.3.1" - mini-create-react-context "^0.4.0" - path-to-regexp "^1.7.0" - prop-types "^15.6.2" - react-is "^16.6.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" + "history" "^4.9.0" + "hoist-non-react-statics" "^3.1.0" + "loose-envify" "^1.3.1" + "mini-create-react-context" "^0.4.0" + "path-to-regexp" "^1.7.0" + "prop-types" "^15.6.2" + "react-is" "^16.6.0" + "tiny-invariant" "^1.0.2" + "tiny-warning" "^1.0.0" -"react@^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", react@^17.0.2, "react@>= 16.8.0", react@>=15, react@>=16, react@17.0.2: - version "17.0.2" - resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== +"react@^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "react@^17.0.2", "react@>= 16.8.0", "react@>=15", "react@>=16", "react@17.0.2": + "integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==" + "resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz" + "version" "17.0.2" dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" + "loose-envify" "^1.1.0" + "object-assign" "^4.1.1" -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +"regenerator-runtime@^0.13.4": + "integrity" "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" + "version" "0.13.9" -resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== +"resolve-pathname@^3.0.0": + "integrity" "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + "resolved" "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz" + "version" "3.0.0" -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== +"scheduler@^0.20.2": + "integrity" "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==" + "resolved" "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz" + "version" "0.20.2" dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" + "loose-envify" "^1.1.0" + "object-assign" "^4.1.1" -shallowequal@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz" - integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== +"shallowequal@^1.1.0": + "integrity" "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + "resolved" "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz" + "version" "1.1.0" -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= +"source-map@^0.5.0": + "integrity" "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + "version" "0.5.7" -styled-components@^5.3.0, "styled-components@>= 2": - version "5.3.3" - resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz" - integrity sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw== +"styled-components@^5.3.0", "styled-components@>= 2": + "integrity" "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==" + "resolved" "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz" + "version" "5.3.3" dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/traverse" "^7.4.5" "@emotion/is-prop-valid" "^0.8.8" "@emotion/stylis" "^0.8.4" "@emotion/unitless" "^0.7.4" - babel-plugin-styled-components ">= 1.12.0" - css-to-react-native "^3.0.0" - hoist-non-react-statics "^3.0.0" - shallowequal "^1.1.0" - supports-color "^5.5.0" + "babel-plugin-styled-components" ">= 1.12.0" + "css-to-react-native" "^3.0.0" + "hoist-non-react-statics" "^3.0.0" + "shallowequal" "^1.1.0" + "supports-color" "^5.5.0" -supports-color@^5.3.0, supports-color@^5.5.0: - version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== +"supports-color@^5.3.0", "supports-color@^5.5.0": + "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + "version" "5.5.0" dependencies: - has-flag "^3.0.0" + "has-flag" "^3.0.0" -tiny-invariant@^1.0.2: - version "1.1.0" - resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz" - integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== +"tiny-invariant@^1.0.2": + "integrity" "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + "resolved" "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz" + "version" "1.1.0" -tiny-warning@^1.0.0, tiny-warning@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== +"tiny-warning@^1.0.0", "tiny-warning@^1.0.3": + "integrity" "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + "resolved" "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz" + "version" "1.0.3" -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= +"to-fast-properties@^2.0.0": + "integrity" "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "resolved" "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + "version" "2.0.0" -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +"tr46@~0.0.3": + "integrity" "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "resolved" "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" + "version" "0.0.3" -typescript@^4.3.5: - version "4.3.5" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz" - integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== +"typescript@^4.3.5": + "integrity" "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==" + "resolved" "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz" + "version" "4.3.5" -value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== +"value-equal@^1.0.1": + "integrity" "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + "resolved" "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz" + "version" "1.0.1" -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== +"webidl-conversions@^3.0.0": + "integrity" "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "resolved" "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" + "version" "3.0.1" -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== +"whatwg-url@^5.0.0": + "integrity" "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==" + "resolved" "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" + "version" "5.0.0" dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" + "tr46" "~0.0.3" + "webidl-conversions" "^3.0.0" diff --git a/dashboard/src/pages/Webhooks.tsx b/dashboard/src/pages/Webhooks.tsx index a4484b5..9d90378 100644 --- a/dashboard/src/pages/Webhooks.tsx +++ b/dashboard/src/pages/Webhooks.tsx @@ -118,7 +118,6 @@ const Webhooks = () => { useEffect(() => { fetchWebookData(); }, [paginationProps.page, paginationProps.limit]); - console.log({ webhookData }); return ( diff --git a/dashboard/yarn.lock b/dashboard/yarn.lock index f322597..e1239de 100644 --- a/dashboard/yarn.lock +++ b/dashboard/yarn.lock @@ -3,29 +3,29 @@ "@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + "integrity" "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==" + "resolved" "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz" + "version" "2.2.1" dependencies: "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.21.4": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz" - integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== + "integrity" "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==" + "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz" + "version" "7.21.4" dependencies: "@babel/highlight" "^7.18.6" "@babel/compat-data@^7.21.4": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz" - integrity sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g== + "integrity" "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==" + "resolved" "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz" + "version" "7.21.4" "@babel/core@^7.0.0", "@babel/core@^7.0.0-0": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz" - integrity sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA== + "integrity" "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==" + "resolved" "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz" + "version" "7.21.4" dependencies: "@ampproject/remapping" "^2.2.0" "@babel/code-frame" "^7.21.4" @@ -37,64 +37,64 @@ "@babel/template" "^7.20.7" "@babel/traverse" "^7.21.4" "@babel/types" "^7.21.4" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.2" - semver "^6.3.0" + "convert-source-map" "^1.7.0" + "debug" "^4.1.0" + "gensync" "^1.0.0-beta.2" + "json5" "^2.2.2" + "semver" "^6.3.0" "@babel/generator@^7.21.4": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz" - integrity sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA== + "integrity" "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==" + "resolved" "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz" + "version" "7.21.4" dependencies: "@babel/types" "^7.21.4" "@jridgewell/gen-mapping" "^0.3.2" "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" + "jsesc" "^2.5.1" "@babel/helper-compilation-targets@^7.21.4": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz" - integrity sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg== + "integrity" "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==" + "resolved" "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz" + "version" "7.21.4" dependencies: "@babel/compat-data" "^7.21.4" "@babel/helper-validator-option" "^7.21.0" - browserslist "^4.21.3" - lru-cache "^5.1.1" - semver "^6.3.0" + "browserslist" "^4.21.3" + "lru-cache" "^5.1.1" + "semver" "^6.3.0" "@babel/helper-environment-visitor@^7.18.9": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" - integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + "integrity" "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + "resolved" "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" + "version" "7.18.9" "@babel/helper-function-name@^7.21.0": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz" - integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== + "integrity" "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==" + "resolved" "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz" + "version" "7.21.0" dependencies: "@babel/template" "^7.20.7" "@babel/types" "^7.21.0" "@babel/helper-hoist-variables@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" - integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + "integrity" "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==" + "resolved" "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" + "version" "7.18.6" dependencies: "@babel/types" "^7.18.6" "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + "integrity" "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" + "version" "7.18.6" dependencies: "@babel/types" "^7.18.6" "@babel/helper-module-transforms@^7.21.2": - version "7.21.2" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz" - integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== + "integrity" "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz" + "version" "7.21.2" dependencies: "@babel/helper-environment-visitor" "^7.18.9" "@babel/helper-module-imports" "^7.18.6" @@ -106,89 +106,89 @@ "@babel/types" "^7.21.2" "@babel/helper-plugin-utils@^7.16.5": - version "7.16.5" - 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==" + "resolved" "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz" + "version" "7.16.5" "@babel/helper-simple-access@^7.20.2": - version "7.20.2" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz" - integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== + "integrity" "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==" + "resolved" "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz" + "version" "7.20.2" dependencies: "@babel/types" "^7.20.2" "@babel/helper-split-export-declaration@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" - integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + "integrity" "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==" + "resolved" "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" + "version" "7.18.6" dependencies: "@babel/types" "^7.18.6" "@babel/helper-string-parser@^7.19.4": - version "7.19.4" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz" - integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== + "integrity" "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + "resolved" "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz" + "version" "7.19.4" "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": - version "7.19.1" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + "integrity" "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz" + "version" "7.19.1" "@babel/helper-validator-option@^7.21.0": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz" - integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== + "integrity" "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz" + "version" "7.21.0" "@babel/helpers@^7.21.0": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz" - integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== + "integrity" "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==" + "resolved" "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz" + "version" "7.21.0" dependencies: "@babel/template" "^7.20.7" "@babel/traverse" "^7.21.0" "@babel/types" "^7.21.0" "@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + "integrity" "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==" + "resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" + "version" "7.18.6" dependencies: "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" - js-tokens "^4.0.0" + "chalk" "^2.0.0" + "js-tokens" "^4.0.0" "@babel/parser@^7.20.7", "@babel/parser@^7.21.4": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz" - integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw== + "integrity" "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==" + "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz" + "version" "7.21.4" "@babel/plugin-syntax-jsx@^7.12.13": - version "7.16.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.5.tgz" - integrity sha512-42OGssv9NPk4QHKVgIHlzeLgPOW5rGgfV5jzG90AhcXXIv6hu/eqj63w4VgvRxdvZY3AlYeDgPiSJ3BqAd1Y6Q== + "integrity" "sha512-42OGssv9NPk4QHKVgIHlzeLgPOW5rGgfV5jzG90AhcXXIv6hu/eqj63w4VgvRxdvZY3AlYeDgPiSJ3BqAd1Y6Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.5.tgz" + "version" "7.16.5" dependencies: "@babel/helper-plugin-utils" "^7.16.5" "@babel/runtime@^7.0.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.13.10", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6": - version "7.16.5" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz" - integrity sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA== + "integrity" "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==" + "resolved" "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz" + "version" "7.16.5" dependencies: - regenerator-runtime "^0.13.4" + "regenerator-runtime" "^0.13.4" "@babel/template@^7.20.7": - version "7.20.7" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz" - integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== + "integrity" "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==" + "resolved" "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz" + "version" "7.20.7" dependencies: "@babel/code-frame" "^7.18.6" "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.4": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz" - integrity sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q== + "integrity" "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==" + "resolved" "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz" + "version" "7.21.4" dependencies: "@babel/code-frame" "^7.21.4" "@babel/generator" "^7.21.4" @@ -198,22 +198,22 @@ "@babel/helper-split-export-declaration" "^7.18.6" "@babel/parser" "^7.21.4" "@babel/types" "^7.21.4" - debug "^4.1.0" - globals "^11.1.0" + "debug" "^4.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": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz" - integrity sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA== + "integrity" "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==" + "resolved" "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz" + "version" "7.21.4" dependencies: "@babel/helper-string-parser" "^7.19.4" "@babel/helper-validator-identifier" "^7.19.1" - to-fast-properties "^2.0.0" + "to-fast-properties" "^2.0.0" "@chakra-ui/accordion@1.4.2": - version "1.4.2" - resolved "https://registry.npmjs.org/@chakra-ui/accordion/-/accordion-1.4.2.tgz" - integrity sha512-BAGMvcm2sFE5Ft7jwC9nF03/Yv7qztuhzwKBBy4iL0p1nCPh6kV54RBXUcoj3VWe+yrmNiAVYKRTdqQBTJFwOw== + "integrity" "sha512-BAGMvcm2sFE5Ft7jwC9nF03/Yv7qztuhzwKBBy4iL0p1nCPh6kV54RBXUcoj3VWe+yrmNiAVYKRTdqQBTJFwOw==" + "resolved" "https://registry.npmjs.org/@chakra-ui/accordion/-/accordion-1.4.2.tgz" + "version" "1.4.2" dependencies: "@chakra-ui/descendant" "2.1.1" "@chakra-ui/hooks" "1.7.1" @@ -223,42 +223,42 @@ "@chakra-ui/utils" "1.9.1" "@chakra-ui/alert@1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@chakra-ui/alert/-/alert-1.3.2.tgz" - integrity sha512-+OMeVeGtydpj6nry0zH7qFDt36zEaxckRnufx1BGiCfWdUg6ahVwKXl8qX93Q8w82od7eAoBKMgGJz7IVL5NPw== + "integrity" "sha512-+OMeVeGtydpj6nry0zH7qFDt36zEaxckRnufx1BGiCfWdUg6ahVwKXl8qX93Q8w82od7eAoBKMgGJz7IVL5NPw==" + "resolved" "https://registry.npmjs.org/@chakra-ui/alert/-/alert-1.3.2.tgz" + "version" "1.3.2" dependencies: "@chakra-ui/icon" "2.0.0" "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/anatomy@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/anatomy/-/anatomy-1.2.1.tgz" - integrity sha512-kNS+FiEDTSnwpQUW4dEjZ5745xhkvB0XtmqjY1wpclUSpFfptLZM9QIHPTnBt2bzM9R+idmRRP+WkTt6kyTrLw== + "integrity" "sha512-kNS+FiEDTSnwpQUW4dEjZ5745xhkvB0XtmqjY1wpclUSpFfptLZM9QIHPTnBt2bzM9R+idmRRP+WkTt6kyTrLw==" + "resolved" "https://registry.npmjs.org/@chakra-ui/anatomy/-/anatomy-1.2.1.tgz" + "version" "1.2.1" dependencies: "@chakra-ui/theme-tools" "^1.3.1" "@chakra-ui/avatar@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/avatar/-/avatar-1.3.1.tgz" - integrity sha512-WI0/kcpTJViOH093V0bz8EB+e/rc+gjF+T5DkOuh1YWFxRRG5v+4Yd3PdEJtQgzWtBVhlbGWmE7WvBizyKwFCA== + "integrity" "sha512-WI0/kcpTJViOH093V0bz8EB+e/rc+gjF+T5DkOuh1YWFxRRG5v+4Yd3PdEJtQgzWtBVhlbGWmE7WvBizyKwFCA==" + "resolved" "https://registry.npmjs.org/@chakra-ui/avatar/-/avatar-1.3.1.tgz" + "version" "1.3.1" dependencies: "@chakra-ui/image" "1.1.1" "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/breadcrumb@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/breadcrumb/-/breadcrumb-1.3.1.tgz" - integrity sha512-b1IoBmtr5FcP2fn5NRbdOdQo2c866OQ/WhcTcZ6UKae1jjik+36/qWE+X+RKzxC6FLfqo5qayV5zSgsnZym7Pg== + "integrity" "sha512-b1IoBmtr5FcP2fn5NRbdOdQo2c866OQ/WhcTcZ6UKae1jjik+36/qWE+X+RKzxC6FLfqo5qayV5zSgsnZym7Pg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/breadcrumb/-/breadcrumb-1.3.1.tgz" + "version" "1.3.1" dependencies: "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/button@1.5.1": - version "1.5.1" - resolved "https://registry.npmjs.org/@chakra-ui/button/-/button-1.5.1.tgz" - integrity sha512-BvP29quEhP6OTgDiRsugD6adgkeOTEQpoDsZUVEmHnNVrbFfdsICEKKQTtDJ2iPf+hmpFrtnpN50vCLdAANKcw== + "integrity" "sha512-BvP29quEhP6OTgDiRsugD6adgkeOTEQpoDsZUVEmHnNVrbFfdsICEKKQTtDJ2iPf+hmpFrtnpN50vCLdAANKcw==" + "resolved" "https://registry.npmjs.org/@chakra-ui/button/-/button-1.5.1.tgz" + "version" "1.5.1" dependencies: "@chakra-ui/hooks" "1.7.1" "@chakra-ui/react-utils" "1.2.1" @@ -266,9 +266,9 @@ "@chakra-ui/utils" "1.9.1" "@chakra-ui/checkbox@1.6.1": - version "1.6.1" - resolved "https://registry.npmjs.org/@chakra-ui/checkbox/-/checkbox-1.6.1.tgz" - integrity sha512-Z5ZMeUYIRjRbi/knhYhSQshZH7OnROA7ezl9a9oVSKRF7iLMNMibQSlQLXmqUWaTKSgrS37cpKAzfgEuemyiUQ== + "integrity" "sha512-Z5ZMeUYIRjRbi/knhYhSQshZH7OnROA7ezl9a9oVSKRF7iLMNMibQSlQLXmqUWaTKSgrS37cpKAzfgEuemyiUQ==" + "resolved" "https://registry.npmjs.org/@chakra-ui/checkbox/-/checkbox-1.6.1.tgz" + "version" "1.6.1" dependencies: "@chakra-ui/hooks" "1.7.1" "@chakra-ui/react-utils" "1.2.1" @@ -276,78 +276,78 @@ "@chakra-ui/visually-hidden" "1.1.1" "@chakra-ui/clickable@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/clickable/-/clickable-1.2.1.tgz" - integrity sha512-B0CIbKzDMwzG1APeTpW9H2Jl8dkarI1Qstb3hDOy23O+N5TU6lpDdVnXQ7fpFJS6mu5JjFqtkwzGAVZnkkv1rw== + "integrity" "sha512-B0CIbKzDMwzG1APeTpW9H2Jl8dkarI1Qstb3hDOy23O+N5TU6lpDdVnXQ7fpFJS6mu5JjFqtkwzGAVZnkkv1rw==" + "resolved" "https://registry.npmjs.org/@chakra-ui/clickable/-/clickable-1.2.1.tgz" + "version" "1.2.1" dependencies: "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/close-button@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/close-button/-/close-button-1.2.2.tgz" - integrity sha512-SqeLib0qgMjK3OsO1g5OnAHUmdCC8GMjToNEea7TeSrA44bH9EXVhFTkMMu2PnDVHbQmi4Ee1cuulNJt0UhQ3g== + "integrity" "sha512-SqeLib0qgMjK3OsO1g5OnAHUmdCC8GMjToNEea7TeSrA44bH9EXVhFTkMMu2PnDVHbQmi4Ee1cuulNJt0UhQ3g==" + "resolved" "https://registry.npmjs.org/@chakra-ui/close-button/-/close-button-1.2.2.tgz" + "version" "1.2.2" dependencies: "@chakra-ui/icon" "2.0.0" "@chakra-ui/utils" "1.9.1" "@chakra-ui/color-mode@1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@chakra-ui/color-mode/-/color-mode-1.3.2.tgz" - integrity sha512-/rWcbrzbaWCyyUnT07Qjz0xf/ltHS31CHOKtVCWr2uTgfn2gOQpdxsKRbjrLYPOYZGTMdINUHNiAsqQjLoAoTQ== + "integrity" "sha512-/rWcbrzbaWCyyUnT07Qjz0xf/ltHS31CHOKtVCWr2uTgfn2gOQpdxsKRbjrLYPOYZGTMdINUHNiAsqQjLoAoTQ==" + "resolved" "https://registry.npmjs.org/@chakra-ui/color-mode/-/color-mode-1.3.2.tgz" + "version" "1.3.2" dependencies: "@chakra-ui/hooks" "1.7.1" "@chakra-ui/react-env" "1.1.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/control-box@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/control-box/-/control-box-1.1.1.tgz" - integrity sha512-ZFbh85pzzZoiSjGnvLUzMB5BoA8Xm6TBMWvMtzLY5xiFGb9/mBeRDH2KFjr1GJzoqleWKkQwvFD6JM0kXcekpg== + "integrity" "sha512-ZFbh85pzzZoiSjGnvLUzMB5BoA8Xm6TBMWvMtzLY5xiFGb9/mBeRDH2KFjr1GJzoqleWKkQwvFD6JM0kXcekpg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/control-box/-/control-box-1.1.1.tgz" + "version" "1.1.1" dependencies: "@chakra-ui/utils" "1.9.1" "@chakra-ui/counter@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/counter/-/counter-1.2.1.tgz" - integrity sha512-Gm4njMzEsDyAzdQtExn40TvmupzkPBrT5DiCu0DlxYqpLqCfqV49HgJHEG5oW3WV+WaC9mzg7VV+idKYh/d+Gg== + "integrity" "sha512-Gm4njMzEsDyAzdQtExn40TvmupzkPBrT5DiCu0DlxYqpLqCfqV49HgJHEG5oW3WV+WaC9mzg7VV+idKYh/d+Gg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/counter/-/counter-1.2.1.tgz" + "version" "1.2.1" dependencies: "@chakra-ui/hooks" "1.7.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/css-reset@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz" - integrity sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg== + "integrity" "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz" + "version" "1.1.1" "@chakra-ui/descendant@2.1.1": - version "2.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/descendant/-/descendant-2.1.1.tgz" - integrity sha512-JasdVaN4MjL7QFo1vMnADy6EtFAlPKT1kTJ1LwMtl9AaF9VFLBsfGxm0L+WQK+3NJMuCSDBXWJB8mV4AQ11Edg== + "integrity" "sha512-JasdVaN4MjL7QFo1vMnADy6EtFAlPKT1kTJ1LwMtl9AaF9VFLBsfGxm0L+WQK+3NJMuCSDBXWJB8mV4AQ11Edg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/descendant/-/descendant-2.1.1.tgz" + "version" "2.1.1" dependencies: "@chakra-ui/react-utils" "^1.2.1" "@chakra-ui/editable@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/editable/-/editable-1.3.1.tgz" - integrity sha512-MwyTtsnHNqmKmHv9SH3KIHWa06D4gBwcuTawTiSnYBUJL6My8ry/Wdca1to9So2tD6hcjz3TPTzOJOlyv0eiZg== + "integrity" "sha512-MwyTtsnHNqmKmHv9SH3KIHWa06D4gBwcuTawTiSnYBUJL6My8ry/Wdca1to9So2tD6hcjz3TPTzOJOlyv0eiZg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/editable/-/editable-1.3.1.tgz" + "version" "1.3.1" dependencies: "@chakra-ui/hooks" "1.7.1" "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/focus-lock@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/focus-lock/-/focus-lock-1.2.1.tgz" - integrity sha512-HYu39nvfaXUrBx+dIDJkFgebNCGEi9oZTfLUKzIJC+zPkmReTDSXV0dzSb/8vCAOq5fph1gFKsdbGy2U98P8GQ== + "integrity" "sha512-HYu39nvfaXUrBx+dIDJkFgebNCGEi9oZTfLUKzIJC+zPkmReTDSXV0dzSb/8vCAOq5fph1gFKsdbGy2U98P8GQ==" + "resolved" "https://registry.npmjs.org/@chakra-ui/focus-lock/-/focus-lock-1.2.1.tgz" + "version" "1.2.1" dependencies: "@chakra-ui/utils" "1.9.1" - react-focus-lock "2.5.2" + "react-focus-lock" "2.5.2" "@chakra-ui/form-control@1.5.2": - version "1.5.2" - resolved "https://registry.npmjs.org/@chakra-ui/form-control/-/form-control-1.5.2.tgz" - integrity sha512-uWv0/f+JEM0ZE5Hnj3TzCnJ09EB+A+DSs9QgyECOuxx9Ju6gnns2uaRki2BfxksQL9ZZomPCkMtXazY9Wa81ag== + "integrity" "sha512-uWv0/f+JEM0ZE5Hnj3TzCnJ09EB+A+DSs9QgyECOuxx9Ju6gnns2uaRki2BfxksQL9ZZomPCkMtXazY9Wa81ag==" + "resolved" "https://registry.npmjs.org/@chakra-ui/form-control/-/form-control-1.5.2.tgz" + "version" "1.5.2" dependencies: "@chakra-ui/hooks" "1.7.1" "@chakra-ui/icon" "2.0.0" @@ -355,67 +355,67 @@ "@chakra-ui/utils" "1.9.1" "@chakra-ui/hooks@1.7.1": - version "1.7.1" - resolved "https://registry.npmjs.org/@chakra-ui/hooks/-/hooks-1.7.1.tgz" - integrity sha512-hgN19X6GUKQYAHczmFY+GAT8vl9h+X+nGWrIAnmvZ6BgUXxDajnTNhZeWhj0ZkR+7A7dCE6Y/3X44GafUgChMw== + "integrity" "sha512-hgN19X6GUKQYAHczmFY+GAT8vl9h+X+nGWrIAnmvZ6BgUXxDajnTNhZeWhj0ZkR+7A7dCE6Y/3X44GafUgChMw==" + "resolved" "https://registry.npmjs.org/@chakra-ui/hooks/-/hooks-1.7.1.tgz" + "version" "1.7.1" dependencies: "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/utils" "1.9.1" - compute-scroll-into-view "1.0.14" - copy-to-clipboard "3.3.1" + "compute-scroll-into-view" "1.0.14" + "copy-to-clipboard" "3.3.1" "@chakra-ui/icon@2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@chakra-ui/icon/-/icon-2.0.0.tgz" - integrity sha512-/GuU+xIcOIy9uSUUUCu249ZJB/nLDbjWGkfpoSdBwqT4+ytJrKt+0Ckh3Ub14sz3BJD+Z6IiIt6ySOA9+7lbsA== + "integrity" "sha512-/GuU+xIcOIy9uSUUUCu249ZJB/nLDbjWGkfpoSdBwqT4+ytJrKt+0Ckh3Ub14sz3BJD+Z6IiIt6ySOA9+7lbsA==" + "resolved" "https://registry.npmjs.org/@chakra-ui/icon/-/icon-2.0.0.tgz" + "version" "2.0.0" dependencies: "@chakra-ui/utils" "1.9.1" "@chakra-ui/image@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/image/-/image-1.1.1.tgz" - integrity sha512-bz1pn08XlXcO3r1KnpdjQgN3R2soiTx10sG2d5Pw9BdGdySf7Y73wiLh+Tan1xJHp6p2KH1hz4f7uKXXDn7Qmw== + "integrity" "sha512-bz1pn08XlXcO3r1KnpdjQgN3R2soiTx10sG2d5Pw9BdGdySf7Y73wiLh+Tan1xJHp6p2KH1hz4f7uKXXDn7Qmw==" + "resolved" "https://registry.npmjs.org/@chakra-ui/image/-/image-1.1.1.tgz" + "version" "1.1.1" dependencies: "@chakra-ui/hooks" "1.7.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/input@1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@chakra-ui/input/-/input-1.3.2.tgz" - integrity sha512-VMxmQgFiQ2UnBlkgLX/336G0IfYfw8YWF2ZoEFj5WL9kDSrrL1FXSBgjFGxrper74G4W20tESBCfU1S891y6cg== + "integrity" "sha512-VMxmQgFiQ2UnBlkgLX/336G0IfYfw8YWF2ZoEFj5WL9kDSrrL1FXSBgjFGxrper74G4W20tESBCfU1S891y6cg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/input/-/input-1.3.2.tgz" + "version" "1.3.2" dependencies: "@chakra-ui/form-control" "1.5.2" "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/layout@1.6.0": - version "1.6.0" - resolved "https://registry.npmjs.org/@chakra-ui/layout/-/layout-1.6.0.tgz" - integrity sha512-WUfQ104y1wNueU33/hPlZsMzYJGjO0dXMpVkQf5ZNhNX3IGDO+5+MO2x2xloP+j45yNPi3p8ti/HBnm3dXI+3Q== + "integrity" "sha512-WUfQ104y1wNueU33/hPlZsMzYJGjO0dXMpVkQf5ZNhNX3IGDO+5+MO2x2xloP+j45yNPi3p8ti/HBnm3dXI+3Q==" + "resolved" "https://registry.npmjs.org/@chakra-ui/layout/-/layout-1.6.0.tgz" + "version" "1.6.0" dependencies: "@chakra-ui/icon" "2.0.0" "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/live-region@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/live-region/-/live-region-1.1.1.tgz" - integrity sha512-BSdI5gLIffNRETEp6W18kBNg9tL0ZLLzfWGRnuO9tEbox7NrcgqIeLF8mNKwhDOZz88NKHtUOPVzjAUKW1SryQ== + "integrity" "sha512-BSdI5gLIffNRETEp6W18kBNg9tL0ZLLzfWGRnuO9tEbox7NrcgqIeLF8mNKwhDOZz88NKHtUOPVzjAUKW1SryQ==" + "resolved" "https://registry.npmjs.org/@chakra-ui/live-region/-/live-region-1.1.1.tgz" + "version" "1.1.1" dependencies: "@chakra-ui/utils" "1.9.1" "@chakra-ui/media-query@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/media-query/-/media-query-1.2.2.tgz" - integrity sha512-xSmDVleE1drWiGH/MX3RqyVm29x/8Vf6G0UGaI2kCpbNmon+Q1zHW/yDHvptIuctLrPHYO8LOBxuUjfnIXwC2g== + "integrity" "sha512-xSmDVleE1drWiGH/MX3RqyVm29x/8Vf6G0UGaI2kCpbNmon+Q1zHW/yDHvptIuctLrPHYO8LOBxuUjfnIXwC2g==" + "resolved" "https://registry.npmjs.org/@chakra-ui/media-query/-/media-query-1.2.2.tgz" + "version" "1.2.2" dependencies: "@chakra-ui/react-env" "1.1.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/menu@1.8.2": - version "1.8.2" - resolved "https://registry.npmjs.org/@chakra-ui/menu/-/menu-1.8.2.tgz" - integrity sha512-u2GfkwTqbWa8L/7i/kOFbU3JANiT2HStR+gsYKuiuOPiuBcUb8OlgfJfP70OtVKegNKmVEMjvzXtld3wCCo/1g== + "integrity" "sha512-u2GfkwTqbWa8L/7i/kOFbU3JANiT2HStR+gsYKuiuOPiuBcUb8OlgfJfP70OtVKegNKmVEMjvzXtld3wCCo/1g==" + "resolved" "https://registry.npmjs.org/@chakra-ui/menu/-/menu-1.8.2.tgz" + "version" "1.8.2" dependencies: "@chakra-ui/clickable" "1.2.1" "@chakra-ui/descendant" "2.1.1" @@ -426,9 +426,9 @@ "@chakra-ui/utils" "1.9.1" "@chakra-ui/modal@1.10.2": - version "1.10.2" - resolved "https://registry.npmjs.org/@chakra-ui/modal/-/modal-1.10.2.tgz" - integrity sha512-ZlmYetPHwHW4CAM09j4/+Ui54dXR1nzU6mOwhWe4/IzLvEyoEU6fHJeKyGxVUpYTG/7wltG/wKFRJpYa77tiBg== + "integrity" "sha512-ZlmYetPHwHW4CAM09j4/+Ui54dXR1nzU6mOwhWe4/IzLvEyoEU6fHJeKyGxVUpYTG/7wltG/wKFRJpYa77tiBg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/modal/-/modal-1.10.2.tgz" + "version" "1.10.2" dependencies: "@chakra-ui/close-button" "1.2.2" "@chakra-ui/focus-lock" "1.2.1" @@ -437,13 +437,13 @@ "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/transition" "1.4.2" "@chakra-ui/utils" "1.9.1" - aria-hidden "^1.1.1" - react-remove-scroll "2.4.1" + "aria-hidden" "^1.1.1" + "react-remove-scroll" "2.4.1" "@chakra-ui/number-input@1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@chakra-ui/number-input/-/number-input-1.3.2.tgz" - integrity sha512-7x7AoqwPXU1odyDcqIwjBwf0MJUwYMM2fa+6YZ52F941GKlvkDiiJOhK6xfhhBzkLUQD6DN8zgAmmGhaZ6UQXw== + "integrity" "sha512-7x7AoqwPXU1odyDcqIwjBwf0MJUwYMM2fa+6YZ52F941GKlvkDiiJOhK6xfhhBzkLUQD6DN8zgAmmGhaZ6UQXw==" + "resolved" "https://registry.npmjs.org/@chakra-ui/number-input/-/number-input-1.3.2.tgz" + "version" "1.3.2" dependencies: "@chakra-ui/counter" "1.2.1" "@chakra-ui/form-control" "1.5.2" @@ -453,9 +453,9 @@ "@chakra-ui/utils" "1.9.1" "@chakra-ui/pin-input@1.7.1": - version "1.7.1" - resolved "https://registry.npmjs.org/@chakra-ui/pin-input/-/pin-input-1.7.1.tgz" - integrity sha512-eFFc5sofiyion+NxELWfCzD23XHIBDrJcfKKbNxt8jdXg9Ek4mFpmvnxBVrK0DIz6cVYgKY8c364OmxNUf4IyA== + "integrity" "sha512-eFFc5sofiyion+NxELWfCzD23XHIBDrJcfKKbNxt8jdXg9Ek4mFpmvnxBVrK0DIz6cVYgKY8c364OmxNUf4IyA==" + "resolved" "https://registry.npmjs.org/@chakra-ui/pin-input/-/pin-input-1.7.1.tgz" + "version" "1.7.1" dependencies: "@chakra-ui/descendant" "2.1.1" "@chakra-ui/hooks" "1.7.1" @@ -463,9 +463,9 @@ "@chakra-ui/utils" "1.9.1" "@chakra-ui/popover@1.11.0": - version "1.11.0" - resolved "https://registry.npmjs.org/@chakra-ui/popover/-/popover-1.11.0.tgz" - integrity sha512-cCHXAfhIRir+M0ehlYIjDw3mHpiCxDTJ9WV0H1zHQV8nDYVIlZw3nEntaq8oJrv0wpIzq2WCW5ss+bBR7nLZ1A== + "integrity" "sha512-cCHXAfhIRir+M0ehlYIjDw3mHpiCxDTJ9WV0H1zHQV8nDYVIlZw3nEntaq8oJrv0wpIzq2WCW5ss+bBR7nLZ1A==" + "resolved" "https://registry.npmjs.org/@chakra-ui/popover/-/popover-1.11.0.tgz" + "version" "1.11.0" dependencies: "@chakra-ui/close-button" "1.2.2" "@chakra-ui/hooks" "1.7.1" @@ -474,34 +474,34 @@ "@chakra-ui/utils" "1.9.1" "@chakra-ui/popper@2.4.1": - version "2.4.1" - resolved "https://registry.npmjs.org/@chakra-ui/popper/-/popper-2.4.1.tgz" - integrity sha512-cuwnwXx6RUXZGGynVOGG8fEIiMNBXUCy3UqWQD1eEd8200eWQobgNk4Z0YwzKuSzJwp0Auy+j5iKefi5FSkyog== + "integrity" "sha512-cuwnwXx6RUXZGGynVOGG8fEIiMNBXUCy3UqWQD1eEd8200eWQobgNk4Z0YwzKuSzJwp0Auy+j5iKefi5FSkyog==" + "resolved" "https://registry.npmjs.org/@chakra-ui/popper/-/popper-2.4.1.tgz" + "version" "2.4.1" dependencies: "@chakra-ui/react-utils" "1.2.1" "@popperjs/core" "^2.9.3" "@chakra-ui/portal@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/portal/-/portal-1.3.1.tgz" - integrity sha512-6UOGZCfujgdijcPs/JTEY5IB5WtKvUbfrSQYsG5CDa+guIwvnoP5qZ+rH6BR6DSSM8Wr/1n+WrtanhfFZShHKA== + "integrity" "sha512-6UOGZCfujgdijcPs/JTEY5IB5WtKvUbfrSQYsG5CDa+guIwvnoP5qZ+rH6BR6DSSM8Wr/1n+WrtanhfFZShHKA==" + "resolved" "https://registry.npmjs.org/@chakra-ui/portal/-/portal-1.3.1.tgz" + "version" "1.3.1" dependencies: "@chakra-ui/hooks" "1.7.1" "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/progress@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/progress/-/progress-1.2.1.tgz" - integrity sha512-213nN8nbODvD/A23vAtg+r3bRKKatWQHafgmLzeznUcxa/+ac0eVurIS8XSYLRkY4EXQ505re3ZkLhDd98a7QA== + "integrity" "sha512-213nN8nbODvD/A23vAtg+r3bRKKatWQHafgmLzeznUcxa/+ac0eVurIS8XSYLRkY4EXQ505re3ZkLhDd98a7QA==" + "resolved" "https://registry.npmjs.org/@chakra-ui/progress/-/progress-1.2.1.tgz" + "version" "1.2.1" dependencies: "@chakra-ui/theme-tools" "1.3.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/provider@1.7.3": - version "1.7.3" - resolved "https://registry.npmjs.org/@chakra-ui/provider/-/provider-1.7.3.tgz" - integrity sha512-D1SrQ7do4yzAv9/OTF3yj/BkLm7kFo5DdeuOCyvXGpVJumnvbtjltRmC7rFQH4R+y9qXPvfQP4LKMNBqSxPNng== + "integrity" "sha512-D1SrQ7do4yzAv9/OTF3yj/BkLm7kFo5DdeuOCyvXGpVJumnvbtjltRmC7rFQH4R+y9qXPvfQP4LKMNBqSxPNng==" + "resolved" "https://registry.npmjs.org/@chakra-ui/provider/-/provider-1.7.3.tgz" + "version" "1.7.3" dependencies: "@chakra-ui/css-reset" "1.1.1" "@chakra-ui/hooks" "1.7.1" @@ -511,9 +511,9 @@ "@chakra-ui/utils" "1.9.1" "@chakra-ui/radio@1.4.3": - version "1.4.3" - resolved "https://registry.npmjs.org/@chakra-ui/radio/-/radio-1.4.3.tgz" - integrity sha512-TQdyfdUD3BLklOP67n82JN8ksQv1BYjvaYsK0m6WCa0LDJr9aCC+XtUPgVq/1L2t4HqHdiGOrGBooF4vvy/+BA== + "integrity" "sha512-TQdyfdUD3BLklOP67n82JN8ksQv1BYjvaYsK0m6WCa0LDJr9aCC+XtUPgVq/1L2t4HqHdiGOrGBooF4vvy/+BA==" + "resolved" "https://registry.npmjs.org/@chakra-ui/radio/-/radio-1.4.3.tgz" + "version" "1.4.3" dependencies: "@chakra-ui/form-control" "1.5.2" "@chakra-ui/hooks" "1.7.1" @@ -522,23 +522,23 @@ "@chakra-ui/visually-hidden" "1.1.1" "@chakra-ui/react-env@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/react-env/-/react-env-1.1.1.tgz" - integrity sha512-Lgmb0y4kv0ffsGMelAOaYOd4tYZAv4FYWgV86ckGMjmYQWA8drv4v/lHTNltixxWMmBEpjcHALpJuS6yAZYHug== + "integrity" "sha512-Lgmb0y4kv0ffsGMelAOaYOd4tYZAv4FYWgV86ckGMjmYQWA8drv4v/lHTNltixxWMmBEpjcHALpJuS6yAZYHug==" + "resolved" "https://registry.npmjs.org/@chakra-ui/react-env/-/react-env-1.1.1.tgz" + "version" "1.1.1" dependencies: "@chakra-ui/utils" "1.9.1" "@chakra-ui/react-utils@^1.2.1", "@chakra-ui/react-utils@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/react-utils/-/react-utils-1.2.1.tgz" - integrity sha512-bV8FRaXiOgGxOg03iTNin/B02I+tHH9PQtqUTl3U7cJaoI+5AUYhrqXvl1Ya2/R7zxSFrb/gBVDTgbZiVkJ+Dg== + "integrity" "sha512-bV8FRaXiOgGxOg03iTNin/B02I+tHH9PQtqUTl3U7cJaoI+5AUYhrqXvl1Ya2/R7zxSFrb/gBVDTgbZiVkJ+Dg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/react-utils/-/react-utils-1.2.1.tgz" + "version" "1.2.1" dependencies: "@chakra-ui/utils" "^1.9.1" "@chakra-ui/react@^1.7.3": - version "1.7.3" - resolved "https://registry.npmjs.org/@chakra-ui/react/-/react-1.7.3.tgz" - integrity sha512-6mrfDUOa9MoQ44Xvi7xgdDq48jTTTjW9BupCGf2R3DI+z6RbUKIHzbcoDJZt2HGY6j9EarMVNRoQJzvzGUKpoQ== + "integrity" "sha512-6mrfDUOa9MoQ44Xvi7xgdDq48jTTTjW9BupCGf2R3DI+z6RbUKIHzbcoDJZt2HGY6j9EarMVNRoQJzvzGUKpoQ==" + "resolved" "https://registry.npmjs.org/@chakra-ui/react/-/react-1.7.3.tgz" + "version" "1.7.3" dependencies: "@chakra-ui/accordion" "1.4.2" "@chakra-ui/alert" "1.3.2" @@ -589,17 +589,17 @@ "@chakra-ui/visually-hidden" "1.1.1" "@chakra-ui/select@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/select/-/select-1.2.2.tgz" - integrity sha512-EchJW3St1DtSWHe//DHwKjGsQYL2zbKcNCLnJWQKGMPZsQhAD2wsm4xjowFrV8AkY7jbVM/U2v68puN7YTC3hg== + "integrity" "sha512-EchJW3St1DtSWHe//DHwKjGsQYL2zbKcNCLnJWQKGMPZsQhAD2wsm4xjowFrV8AkY7jbVM/U2v68puN7YTC3hg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/select/-/select-1.2.2.tgz" + "version" "1.2.2" dependencies: "@chakra-ui/form-control" "1.5.2" "@chakra-ui/utils" "1.9.1" "@chakra-ui/skeleton@1.2.3": - version "1.2.3" - resolved "https://registry.npmjs.org/@chakra-ui/skeleton/-/skeleton-1.2.3.tgz" - integrity sha512-u5ASkzPiBjfvKxKuBienUfmyYDTHziSWQ8Ny6k83LbwLv9IcmBNGsSkmsp7hesgi9cMHGBQ3hY2GTqG9ljndIg== + "integrity" "sha512-u5ASkzPiBjfvKxKuBienUfmyYDTHziSWQ8Ny6k83LbwLv9IcmBNGsSkmsp7hesgi9cMHGBQ3hY2GTqG9ljndIg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/skeleton/-/skeleton-1.2.3.tgz" + "version" "1.2.3" dependencies: "@chakra-ui/hooks" "1.7.1" "@chakra-ui/media-query" "1.2.2" @@ -607,69 +607,69 @@ "@chakra-ui/utils" "1.9.1" "@chakra-ui/slider@1.5.2": - version "1.5.2" - resolved "https://registry.npmjs.org/@chakra-ui/slider/-/slider-1.5.2.tgz" - integrity sha512-zP07TMew61GkJe47Nu7zEg/SUEwPHpN4alW6VUM6Y8UaVpQaDx7InarbWTc/bXdTP03SfE+hQ6WD9Oy7noe4hQ== + "integrity" "sha512-zP07TMew61GkJe47Nu7zEg/SUEwPHpN4alW6VUM6Y8UaVpQaDx7InarbWTc/bXdTP03SfE+hQ6WD9Oy7noe4hQ==" + "resolved" "https://registry.npmjs.org/@chakra-ui/slider/-/slider-1.5.2.tgz" + "version" "1.5.2" dependencies: "@chakra-ui/hooks" "1.7.1" "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/spinner@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/spinner/-/spinner-1.2.1.tgz" - integrity sha512-CQsUJNJWWSot1ku5Se41Nz1dXIDhk+/7FIhTbfRHSjtYZnAab3CPMHBkTGqwbJxQ9oHYgk9Rso3cfG+/ra6aTQ== + "integrity" "sha512-CQsUJNJWWSot1ku5Se41Nz1dXIDhk+/7FIhTbfRHSjtYZnAab3CPMHBkTGqwbJxQ9oHYgk9Rso3cfG+/ra6aTQ==" + "resolved" "https://registry.npmjs.org/@chakra-ui/spinner/-/spinner-1.2.1.tgz" + "version" "1.2.1" dependencies: "@chakra-ui/utils" "1.9.1" "@chakra-ui/visually-hidden" "1.1.1" "@chakra-ui/stat@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/stat/-/stat-1.2.2.tgz" - integrity sha512-0StsPDC56MjzhdlBl0R8wU0uwj9L1tvhQzge/ELSDn4tQDI7VovrxpFzVH0qsj7EZDwZa0BRQaSrstzWvgmJ/Q== + "integrity" "sha512-0StsPDC56MjzhdlBl0R8wU0uwj9L1tvhQzge/ELSDn4tQDI7VovrxpFzVH0qsj7EZDwZa0BRQaSrstzWvgmJ/Q==" + "resolved" "https://registry.npmjs.org/@chakra-ui/stat/-/stat-1.2.2.tgz" + "version" "1.2.2" dependencies: "@chakra-ui/icon" "2.0.0" "@chakra-ui/utils" "1.9.1" "@chakra-ui/visually-hidden" "1.1.1" "@chakra-ui/styled-system@1.15.0": - version "1.15.0" - resolved "https://registry.npmjs.org/@chakra-ui/styled-system/-/styled-system-1.15.0.tgz" - integrity sha512-LnsKeiYkUuJ+NMTwueiX0Mj8CW9XAMJrJxpQm/X3GY5L5PO7Hv6wW725Ovqdy4mhG3IK7S8444FthpsDv/luHw== + "integrity" "sha512-LnsKeiYkUuJ+NMTwueiX0Mj8CW9XAMJrJxpQm/X3GY5L5PO7Hv6wW725Ovqdy4mhG3IK7S8444FthpsDv/luHw==" + "resolved" "https://registry.npmjs.org/@chakra-ui/styled-system/-/styled-system-1.15.0.tgz" + "version" "1.15.0" dependencies: "@chakra-ui/utils" "1.9.1" - csstype "^3.0.9" + "csstype" "^3.0.9" "@chakra-ui/switch@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/switch/-/switch-1.3.1.tgz" - integrity sha512-92hXJ2/ozj7B3cJNT259mFNoad7Ck892uHTuEQ/GIdXb25doE6F1wCp0TreOnGiEgU5YSaxpdrcZjA0QODP//w== + "integrity" "sha512-92hXJ2/ozj7B3cJNT259mFNoad7Ck892uHTuEQ/GIdXb25doE6F1wCp0TreOnGiEgU5YSaxpdrcZjA0QODP//w==" + "resolved" "https://registry.npmjs.org/@chakra-ui/switch/-/switch-1.3.1.tgz" + "version" "1.3.1" dependencies: "@chakra-ui/checkbox" "1.6.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/system@>=1.0.0", "@chakra-ui/system@1.8.3": - version "1.8.3" - resolved "https://registry.npmjs.org/@chakra-ui/system/-/system-1.8.3.tgz" - integrity sha512-6MaevsT7A2ifgOGQQCQsfvzPVd0kEXqFrX1Oxd842bawaqthmbFdo2bBTdaia/+Ivq/8Xot2uAQSbU+3NuRiUA== + "integrity" "sha512-6MaevsT7A2ifgOGQQCQsfvzPVd0kEXqFrX1Oxd842bawaqthmbFdo2bBTdaia/+Ivq/8Xot2uAQSbU+3NuRiUA==" + "resolved" "https://registry.npmjs.org/@chakra-ui/system/-/system-1.8.3.tgz" + "version" "1.8.3" dependencies: "@chakra-ui/color-mode" "1.3.2" "@chakra-ui/react-utils" "1.2.1" "@chakra-ui/styled-system" "1.15.0" "@chakra-ui/utils" "1.9.1" - react-fast-compare "3.2.0" + "react-fast-compare" "3.2.0" "@chakra-ui/table@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/table/-/table-1.3.1.tgz" - integrity sha512-+ia/7zs7AGj01lon301EEx+mK4918yGc0K6e68Kxomex8tnxkwbskFWs6hX+6Kzbj56ZBm99eLlKpo2iGYX0HA== + "integrity" "sha512-+ia/7zs7AGj01lon301EEx+mK4918yGc0K6e68Kxomex8tnxkwbskFWs6hX+6Kzbj56ZBm99eLlKpo2iGYX0HA==" + "resolved" "https://registry.npmjs.org/@chakra-ui/table/-/table-1.3.1.tgz" + "version" "1.3.1" dependencies: "@chakra-ui/utils" "1.9.1" "@chakra-ui/tabs@1.6.1": - version "1.6.1" - resolved "https://registry.npmjs.org/@chakra-ui/tabs/-/tabs-1.6.1.tgz" - integrity sha512-p7HdHcleJWNwteWYVPt2KF52YbS5pIIfs/IpgtnYZRsJbqvRVxSwgg5Wsn+vuxFXBKW0cA2rDGbyzsZ+ChtEXQ== + "integrity" "sha512-p7HdHcleJWNwteWYVPt2KF52YbS5pIIfs/IpgtnYZRsJbqvRVxSwgg5Wsn+vuxFXBKW0cA2rDGbyzsZ+ChtEXQ==" + "resolved" "https://registry.npmjs.org/@chakra-ui/tabs/-/tabs-1.6.1.tgz" + "version" "1.6.1" dependencies: "@chakra-ui/clickable" "1.2.1" "@chakra-ui/descendant" "2.1.1" @@ -678,42 +678,42 @@ "@chakra-ui/utils" "1.9.1" "@chakra-ui/tag@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/tag/-/tag-1.2.2.tgz" - integrity sha512-H25y9nEyUAUdwQDND9P4mMXKf1wf9UH4A3DyP237qVKIyYBpa4aCH8eJU4dunh2yIzASB0DWcr7lsul/HAHxmg== + "integrity" "sha512-H25y9nEyUAUdwQDND9P4mMXKf1wf9UH4A3DyP237qVKIyYBpa4aCH8eJU4dunh2yIzASB0DWcr7lsul/HAHxmg==" + "resolved" "https://registry.npmjs.org/@chakra-ui/tag/-/tag-1.2.2.tgz" + "version" "1.2.2" dependencies: "@chakra-ui/icon" "2.0.0" "@chakra-ui/utils" "1.9.1" "@chakra-ui/textarea@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/textarea/-/textarea-1.2.2.tgz" - integrity sha512-DoLdKxHk0DyrQDnj1la9wjl2AW3/SK62nfWDYLAm0ouFsw1VKPw9nU+Yyj0dPruQTzI19nLaYF26i97rtnT27g== + "integrity" "sha512-DoLdKxHk0DyrQDnj1la9wjl2AW3/SK62nfWDYLAm0ouFsw1VKPw9nU+Yyj0dPruQTzI19nLaYF26i97rtnT27g==" + "resolved" "https://registry.npmjs.org/@chakra-ui/textarea/-/textarea-1.2.2.tgz" + "version" "1.2.2" dependencies: "@chakra-ui/form-control" "1.5.2" "@chakra-ui/utils" "1.9.1" "@chakra-ui/theme-tools@^1.3.1", "@chakra-ui/theme-tools@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/theme-tools/-/theme-tools-1.3.1.tgz" - integrity sha512-D8arJ5uFGuYZrrFGpXqgov8FhsJYWRyar5oBZY5TJR9gsVYBlJ8Ai91pwM/NflCFqzerTOgyt7bNSGQMdZ8ghA== + "integrity" "sha512-D8arJ5uFGuYZrrFGpXqgov8FhsJYWRyar5oBZY5TJR9gsVYBlJ8Ai91pwM/NflCFqzerTOgyt7bNSGQMdZ8ghA==" + "resolved" "https://registry.npmjs.org/@chakra-ui/theme-tools/-/theme-tools-1.3.1.tgz" + "version" "1.3.1" dependencies: "@chakra-ui/utils" "1.9.1" "@ctrl/tinycolor" "^3.4.0" "@chakra-ui/theme@>=1.0.0", "@chakra-ui/theme@1.12.2": - version "1.12.2" - resolved "https://registry.npmjs.org/@chakra-ui/theme/-/theme-1.12.2.tgz" - integrity sha512-LVjSf16yYHD40ILrsDEd3idVQRvJSY7JY8lvTGWo2p6v+JQESWF+zXlYi9Le+TXRpZuFvJuuQ1SEvoqVwdcJ8Q== + "integrity" "sha512-LVjSf16yYHD40ILrsDEd3idVQRvJSY7JY8lvTGWo2p6v+JQESWF+zXlYi9Le+TXRpZuFvJuuQ1SEvoqVwdcJ8Q==" + "resolved" "https://registry.npmjs.org/@chakra-ui/theme/-/theme-1.12.2.tgz" + "version" "1.12.2" dependencies: "@chakra-ui/anatomy" "1.2.1" "@chakra-ui/theme-tools" "1.3.1" "@chakra-ui/utils" "1.9.1" "@chakra-ui/toast@1.5.0": - version "1.5.0" - resolved "https://registry.npmjs.org/@chakra-ui/toast/-/toast-1.5.0.tgz" - integrity sha512-rTsFx/Qos5oVPN6aZMbT/wTxwZlFNSXQqrTpJYaRcRFQGzxIDDxmGkKYfPnyJjRP9i6EqynJhXEIyhMA0xO0dw== + "integrity" "sha512-rTsFx/Qos5oVPN6aZMbT/wTxwZlFNSXQqrTpJYaRcRFQGzxIDDxmGkKYfPnyJjRP9i6EqynJhXEIyhMA0xO0dw==" + "resolved" "https://registry.npmjs.org/@chakra-ui/toast/-/toast-1.5.0.tgz" + "version" "1.5.0" dependencies: "@chakra-ui/alert" "1.3.2" "@chakra-ui/close-button" "1.2.2" @@ -724,9 +724,9 @@ "@reach/alert" "0.13.2" "@chakra-ui/tooltip@1.4.2": - version "1.4.2" - resolved "https://registry.npmjs.org/@chakra-ui/tooltip/-/tooltip-1.4.2.tgz" - integrity sha512-+wyYXG8qenKkFy2YSFfOBf3rlWADnu6S9EUxP+3Rmm78unOWXDuTJWzqy2QlXs2BwoQoifaz1LVwzmMb7WLVgQ== + "integrity" "sha512-+wyYXG8qenKkFy2YSFfOBf3rlWADnu6S9EUxP+3Rmm78unOWXDuTJWzqy2QlXs2BwoQoifaz1LVwzmMb7WLVgQ==" + "resolved" "https://registry.npmjs.org/@chakra-ui/tooltip/-/tooltip-1.4.2.tgz" + "version" "1.4.2" dependencies: "@chakra-ui/hooks" "1.7.1" "@chakra-ui/popper" "2.4.1" @@ -736,38 +736,38 @@ "@chakra-ui/visually-hidden" "1.1.1" "@chakra-ui/transition@1.4.2": - version "1.4.2" - resolved "https://registry.npmjs.org/@chakra-ui/transition/-/transition-1.4.2.tgz" - integrity sha512-S+BNmpErHlntl//uaqv0sJegzMsQms0OnJapeZaRsvZL4s1SVYrR8kMrXigkdpeh4lAUqGsLpQHPKkzaKGbBOw== + "integrity" "sha512-S+BNmpErHlntl//uaqv0sJegzMsQms0OnJapeZaRsvZL4s1SVYrR8kMrXigkdpeh4lAUqGsLpQHPKkzaKGbBOw==" + "resolved" "https://registry.npmjs.org/@chakra-ui/transition/-/transition-1.4.2.tgz" + "version" "1.4.2" dependencies: "@chakra-ui/utils" "1.9.1" "@chakra-ui/utils@^1.9.1", "@chakra-ui/utils@1.9.1": - version "1.9.1" - resolved "https://registry.npmjs.org/@chakra-ui/utils/-/utils-1.9.1.tgz" - integrity sha512-Tue8JfpzOqeHd8vSqAnX1l/Y3Gg456+BXFP/TH6mCIeqMAMbrvv25vDskds0wlXRjMYdmpqHxCEzkalFrscGHA== + "integrity" "sha512-Tue8JfpzOqeHd8vSqAnX1l/Y3Gg456+BXFP/TH6mCIeqMAMbrvv25vDskds0wlXRjMYdmpqHxCEzkalFrscGHA==" + "resolved" "https://registry.npmjs.org/@chakra-ui/utils/-/utils-1.9.1.tgz" + "version" "1.9.1" dependencies: "@types/lodash.mergewith" "4.6.6" - css-box-model "1.2.1" - framesync "5.3.0" - lodash.mergewith "4.6.2" + "css-box-model" "1.2.1" + "framesync" "5.3.0" + "lodash.mergewith" "4.6.2" "@chakra-ui/visually-hidden@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/visually-hidden/-/visually-hidden-1.1.1.tgz" - integrity sha512-AGK9YBQS2FW/1e5tfivS8VVXn8y2uTyJ9ACOnGiLm9FNdth9pR0fGil9axlcmhZpEYcSRlnCuma3nkqaCjJnAA== + "integrity" "sha512-AGK9YBQS2FW/1e5tfivS8VVXn8y2uTyJ9ACOnGiLm9FNdth9pR0fGil9axlcmhZpEYcSRlnCuma3nkqaCjJnAA==" + "resolved" "https://registry.npmjs.org/@chakra-ui/visually-hidden/-/visually-hidden-1.1.1.tgz" + "version" "1.1.1" dependencies: "@chakra-ui/utils" "1.9.1" "@ctrl/tinycolor@^3.4.0": - version "3.4.0" - resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz" - integrity sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ== + "integrity" "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ==" + "resolved" "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz" + "version" "3.4.0" "@emotion/babel-plugin@^11.3.0": - version "11.7.2" - resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz" - integrity sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ== + "integrity" "sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ==" + "resolved" "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz" + "version" "11.7.2" dependencies: "@babel/helper-module-imports" "^7.12.13" "@babel/plugin-syntax-jsx" "^7.12.13" @@ -775,62 +775,62 @@ "@emotion/hash" "^0.8.0" "@emotion/memoize" "^0.7.5" "@emotion/serialize" "^1.0.2" - babel-plugin-macros "^2.6.1" - convert-source-map "^1.5.0" - escape-string-regexp "^4.0.0" - find-root "^1.1.0" - source-map "^0.5.7" - stylis "4.0.13" + "babel-plugin-macros" "^2.6.1" + "convert-source-map" "^1.5.0" + "escape-string-regexp" "^4.0.0" + "find-root" "^1.1.0" + "source-map" "^0.5.7" + "stylis" "4.0.13" "@emotion/cache@^11.7.1": - version "11.7.1" - resolved "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz" - integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A== + "integrity" "sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==" + "resolved" "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz" + "version" "11.7.1" dependencies: "@emotion/memoize" "^0.7.4" "@emotion/sheet" "^1.1.0" "@emotion/utils" "^1.0.0" "@emotion/weak-memoize" "^0.2.5" - stylis "4.0.13" + "stylis" "4.0.13" "@emotion/core@^11.0.0": - version "11.0.0" - resolved "https://registry.npmjs.org/@emotion/core/-/core-11.0.0.tgz" - integrity sha512-w4sE3AmHmyG6RDKf6mIbtHpgJUSJ2uGvPQb8VXFL7hFjMPibE8IiehG8cMX3Ztm4svfCQV6KqusQbeIOkurBcA== + "integrity" "sha512-w4sE3AmHmyG6RDKf6mIbtHpgJUSJ2uGvPQb8VXFL7hFjMPibE8IiehG8cMX3Ztm4svfCQV6KqusQbeIOkurBcA==" + "resolved" "https://registry.npmjs.org/@emotion/core/-/core-11.0.0.tgz" + "version" "11.0.0" "@emotion/hash@^0.8.0": - version "0.8.0" - resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz" - integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== + "integrity" "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + "resolved" "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz" + "version" "0.8.0" "@emotion/is-prop-valid@^0.8.2": - version "0.8.8" - resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz" - integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== + "integrity" "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==" + "resolved" "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz" + "version" "0.8.8" dependencies: "@emotion/memoize" "0.7.4" "@emotion/is-prop-valid@^1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.1.tgz" - integrity sha512-bW1Tos67CZkOURLc0OalnfxtSXQJMrAMV0jZTVGJUPSOd4qgjF3+tTD5CwJM13PHA8cltGW1WGbbvV9NpvUZPw== + "integrity" "sha512-bW1Tos67CZkOURLc0OalnfxtSXQJMrAMV0jZTVGJUPSOd4qgjF3+tTD5CwJM13PHA8cltGW1WGbbvV9NpvUZPw==" + "resolved" "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.1.tgz" + "version" "1.1.1" dependencies: "@emotion/memoize" "^0.7.4" "@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": - version "0.7.5" - resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz" - integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== + "integrity" "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" + "resolved" "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz" + "version" "0.7.5" "@emotion/memoize@0.7.4": - version "0.7.4" - resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz" - integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== + "integrity" "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + "resolved" "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz" + "version" "0.7.4" "@emotion/react@^11.0.0", "@emotion/react@^11.0.0-rc.0", "@emotion/react@^11.7.1", "@emotion/react@>=10.0.35": - version "11.7.1" - resolved "https://registry.npmjs.org/@emotion/react/-/react-11.7.1.tgz" - integrity sha512-DV2Xe3yhkF1yT4uAUoJcYL1AmrnO5SVsdfvu+fBuS7IbByDeTVx9+wFmvx9Idzv7/78+9Mgx2Hcmr7Fex3tIyw== + "integrity" "sha512-DV2Xe3yhkF1yT4uAUoJcYL1AmrnO5SVsdfvu+fBuS7IbByDeTVx9+wFmvx9Idzv7/78+9Mgx2Hcmr7Fex3tIyw==" + "resolved" "https://registry.npmjs.org/@emotion/react/-/react-11.7.1.tgz" + "version" "11.7.1" dependencies: "@babel/runtime" "^7.13.10" "@emotion/cache" "^11.7.1" @@ -838,28 +838,28 @@ "@emotion/sheet" "^1.1.0" "@emotion/utils" "^1.0.0" "@emotion/weak-memoize" "^0.2.5" - hoist-non-react-statics "^3.3.1" + "hoist-non-react-statics" "^3.3.1" "@emotion/serialize@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz" - integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== + "integrity" "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==" + "resolved" "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz" + "version" "1.0.2" dependencies: "@emotion/hash" "^0.8.0" "@emotion/memoize" "^0.7.4" "@emotion/unitless" "^0.7.5" "@emotion/utils" "^1.0.0" - csstype "^3.0.2" + "csstype" "^3.0.2" "@emotion/sheet@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz" - integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g== + "integrity" "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" + "resolved" "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz" + "version" "1.1.0" "@emotion/styled@^11.0.0", "@emotion/styled@^11.6.0": - version "11.6.0" - resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.6.0.tgz" - integrity sha512-mxVtVyIOTmCAkFbwIp+nCjTXJNgcz4VWkOYQro87jE2QBTydnkiYusMrRGFtzuruiGK4dDaNORk4gH049iiQuw== + "integrity" "sha512-mxVtVyIOTmCAkFbwIp+nCjTXJNgcz4VWkOYQro87jE2QBTydnkiYusMrRGFtzuruiGK4dDaNORk4gH049iiQuw==" + "resolved" "https://registry.npmjs.org/@emotion/styled/-/styled-11.6.0.tgz" + "version" "11.6.0" dependencies: "@babel/runtime" "^7.13.10" "@emotion/babel-plugin" "^11.3.0" @@ -868,1022 +868,1022 @@ "@emotion/utils" "^1.0.0" "@emotion/unitless@^0.7.5": - version "0.7.5" - resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz" - integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + "integrity" "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + "resolved" "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz" + "version" "0.7.5" "@emotion/utils@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz" - integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA== + "integrity" "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==" + "resolved" "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz" + "version" "1.0.0" "@emotion/weak-memoize@^0.2.5": - version "0.2.5" - resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz" - integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== + "integrity" "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" + "resolved" "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz" + "version" "0.2.5" "@graphql-typed-document-node/core@^3.1.0": - version "3.1.1" - resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz" - integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg== + "integrity" "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==" + "resolved" "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz" + "version" "3.1.1" "@jridgewell/gen-mapping@^0.3.0", "@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== + "integrity" "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==" + "resolved" "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz" + "version" "0.3.3" 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.0" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + "integrity" "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + "resolved" "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" + "version" "3.1.0" "@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== + "integrity" "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + "resolved" "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + "version" "1.1.2" "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.15" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + "integrity" "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "resolved" "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" + "version" "1.4.15" "@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== + "integrity" "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + "resolved" "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + "version" "1.4.14" "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.18" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz" - integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + "integrity" "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==" + "resolved" "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz" + "version" "0.3.18" dependencies: "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" "@popperjs/core@^2.9.3": - version "2.11.0" - resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.0.tgz" - integrity sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ== + "integrity" "sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ==" + "resolved" "https://registry.npmjs.org/@popperjs/core/-/core-2.11.0.tgz" + "version" "2.11.0" "@reach/alert@0.13.2": - version "0.13.2" - resolved "https://registry.npmjs.org/@reach/alert/-/alert-0.13.2.tgz" - integrity sha512-LDz83AXCrClyq/MWe+0vaZfHp1Ytqn+kgL5VxG7rirUvmluWaj/snxzfNPWn0Ma4K2YENmXXRC/iHt5X95SqIg== + "integrity" "sha512-LDz83AXCrClyq/MWe+0vaZfHp1Ytqn+kgL5VxG7rirUvmluWaj/snxzfNPWn0Ma4K2YENmXXRC/iHt5X95SqIg==" + "resolved" "https://registry.npmjs.org/@reach/alert/-/alert-0.13.2.tgz" + "version" "0.13.2" dependencies: "@reach/utils" "0.13.2" "@reach/visually-hidden" "0.13.2" - prop-types "^15.7.2" - tslib "^2.1.0" + "prop-types" "^15.7.2" + "tslib" "^2.1.0" "@reach/utils@0.13.2": - version "0.13.2" - resolved "https://registry.npmjs.org/@reach/utils/-/utils-0.13.2.tgz" - integrity sha512-3ir6cN60zvUrwjOJu7C6jec/samqAeyAB12ZADK+qjnmQPdzSYldrFWwDVV5H0WkhbYXR3uh+eImu13hCetNPQ== + "integrity" "sha512-3ir6cN60zvUrwjOJu7C6jec/samqAeyAB12ZADK+qjnmQPdzSYldrFWwDVV5H0WkhbYXR3uh+eImu13hCetNPQ==" + "resolved" "https://registry.npmjs.org/@reach/utils/-/utils-0.13.2.tgz" + "version" "0.13.2" dependencies: "@types/warning" "^3.0.0" - tslib "^2.1.0" - warning "^4.0.3" + "tslib" "^2.1.0" + "warning" "^4.0.3" "@reach/visually-hidden@0.13.2": - version "0.13.2" - resolved "https://registry.npmjs.org/@reach/visually-hidden/-/visually-hidden-0.13.2.tgz" - integrity sha512-sPZwNS0/duOuG0mYwE5DmgEAzW9VhgU3aIt1+mrfT/xiT9Cdncqke+kRBQgU708q/Ttm9tWsoHni03nn/SuPTQ== + "integrity" "sha512-sPZwNS0/duOuG0mYwE5DmgEAzW9VhgU3aIt1+mrfT/xiT9Cdncqke+kRBQgU708q/Ttm9tWsoHni03nn/SuPTQ==" + "resolved" "https://registry.npmjs.org/@reach/visually-hidden/-/visually-hidden-0.13.2.tgz" + "version" "0.13.2" dependencies: - prop-types "^15.7.2" - tslib "^2.1.0" + "prop-types" "^15.7.2" + "tslib" "^2.1.0" "@types/history@*": - version "4.7.9" - resolved "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz" - integrity sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ== + "integrity" "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==" + "resolved" "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz" + "version" "4.7.9" "@types/lodash.mergewith@4.6.6": - version "4.6.6" - resolved "https://registry.npmjs.org/@types/lodash.mergewith/-/lodash.mergewith-4.6.6.tgz" - integrity sha512-RY/8IaVENjG19rxTZu9Nukqh0W2UrYgmBj5sdns4hWRZaV8PqR7wIKHFKzvOTjo4zVRV7sVI+yFhAJql12Kfqg== + "integrity" "sha512-RY/8IaVENjG19rxTZu9Nukqh0W2UrYgmBj5sdns4hWRZaV8PqR7wIKHFKzvOTjo4zVRV7sVI+yFhAJql12Kfqg==" + "resolved" "https://registry.npmjs.org/@types/lodash.mergewith/-/lodash.mergewith-4.6.6.tgz" + "version" "4.6.6" dependencies: "@types/lodash" "*" "@types/lodash@*": - version "4.14.178" - resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz" - integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== + "integrity" "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==" + "resolved" "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz" + "version" "4.14.178" "@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + "integrity" "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + "resolved" "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" + "version" "4.0.0" "@types/prop-types@*": - version "15.7.4" - resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz" - integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== + "integrity" "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + "resolved" "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz" + "version" "15.7.4" "@types/react-dom@^17.0.11": - version "17.0.11" - resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz" - integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q== + "integrity" "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==" + "resolved" "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz" + "version" "17.0.11" dependencies: "@types/react" "*" "@types/react-email-editor@^1.1.7": - version "1.1.7" - resolved "https://registry.npmjs.org/@types/react-email-editor/-/react-email-editor-1.1.7.tgz" - integrity sha512-OURTAgaE9pjA6KiU97k13fPdoglI1ZyowUuZ0nu5tTSyrw5PiZoYzYEf9y25YTjmw/ohxT5yqoP0tt+AjSh1qQ== + "integrity" "sha512-OURTAgaE9pjA6KiU97k13fPdoglI1ZyowUuZ0nu5tTSyrw5PiZoYzYEf9y25YTjmw/ohxT5yqoP0tt+AjSh1qQ==" + "resolved" "https://registry.npmjs.org/@types/react-email-editor/-/react-email-editor-1.1.7.tgz" + "version" "1.1.7" dependencies: "@types/react" "*" "@types/react-router-dom@^5.3.2": - version "5.3.2" - resolved "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.2.tgz" - integrity sha512-ELEYRUie2czuJzaZ5+ziIp9Hhw+juEw8b7C11YNA4QdLCVbQ3qLi2l4aq8XnlqM7V31LZX8dxUuFUCrzHm6sqQ== + "integrity" "sha512-ELEYRUie2czuJzaZ5+ziIp9Hhw+juEw8b7C11YNA4QdLCVbQ3qLi2l4aq8XnlqM7V31LZX8dxUuFUCrzHm6sqQ==" + "resolved" "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.2.tgz" + "version" "5.3.2" dependencies: "@types/history" "*" "@types/react" "*" "@types/react-router" "*" "@types/react-router@*": - version "5.1.17" - resolved "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz" - integrity sha512-RNSXOyb3VyRs/EOGmjBhhGKTbnN6fHWvy5FNLzWfOWOGjgVUKqJZXfpKzLmgoU8h6Hj8mpALj/mbXQASOb92wQ== + "integrity" "sha512-RNSXOyb3VyRs/EOGmjBhhGKTbnN6fHWvy5FNLzWfOWOGjgVUKqJZXfpKzLmgoU8h6Hj8mpALj/mbXQASOb92wQ==" + "resolved" "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz" + "version" "5.1.17" dependencies: "@types/history" "*" "@types/react" "*" "@types/react@*", "@types/react@^16.8.0 || ^17.0.0", "@types/react@^17.0.38": - version "17.0.38" - resolved "https://registry.npmjs.org/@types/react/-/react-17.0.38.tgz" - integrity sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ== + "integrity" "sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ==" + "resolved" "https://registry.npmjs.org/@types/react/-/react-17.0.38.tgz" + "version" "17.0.38" dependencies: "@types/prop-types" "*" "@types/scheduler" "*" - csstype "^3.0.2" + "csstype" "^3.0.2" "@types/scheduler@*": - version "0.16.2" - resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + "integrity" "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + "resolved" "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" + "version" "0.16.2" "@types/warning@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz" - integrity sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI= + "integrity" "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI=" + "resolved" "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz" + "version" "3.0.0" "@urql/core@^2.3.6": - version "2.3.6" - resolved "https://registry.npmjs.org/@urql/core/-/core-2.3.6.tgz" - integrity sha512-PUxhtBh7/8167HJK6WqBv6Z0piuiaZHQGYbhwpNL9aIQmLROPEdaUYkY4wh45wPQXcTpnd11l0q3Pw+TI11pdw== + "integrity" "sha512-PUxhtBh7/8167HJK6WqBv6Z0piuiaZHQGYbhwpNL9aIQmLROPEdaUYkY4wh45wPQXcTpnd11l0q3Pw+TI11pdw==" + "resolved" "https://registry.npmjs.org/@urql/core/-/core-2.3.6.tgz" + "version" "2.3.6" dependencies: "@graphql-typed-document-node/core" "^3.1.0" - wonka "^4.0.14" + "wonka" "^4.0.14" -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== +"ansi-styles@^3.2.1": + "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + "version" "3.2.1" dependencies: - color-convert "^1.9.0" + "color-convert" "^1.9.0" -aria-hidden@^1.1.1: - version "1.1.3" - resolved "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.1.3.tgz" - integrity sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA== +"aria-hidden@^1.1.1": + "integrity" "sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA==" + "resolved" "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.1.3.tgz" + "version" "1.1.3" dependencies: - tslib "^1.0.0" + "tslib" "^1.0.0" -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz" - integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== +"asap@~2.0.3": + "integrity" "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + "resolved" "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz" + "version" "2.0.6" -attr-accept@^2.2.2: - version "2.2.2" - resolved "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz" - integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== +"attr-accept@^2.2.2": + "integrity" "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==" + "resolved" "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz" + "version" "2.2.2" -babel-plugin-macros@^2.6.1: - version "2.8.0" - resolved "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz" - integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== +"babel-plugin-macros@^2.6.1": + "integrity" "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==" + "resolved" "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz" + "version" "2.8.0" dependencies: "@babel/runtime" "^7.7.2" - cosmiconfig "^6.0.0" - resolve "^1.12.0" + "cosmiconfig" "^6.0.0" + "resolve" "^1.12.0" -browserslist@^4.21.3, "browserslist@>= 4.21.0": - version "4.21.5" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz" - integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== +"browserslist@^4.21.3", "browserslist@>= 4.21.0": + "integrity" "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==" + "resolved" "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz" + "version" "4.21.5" dependencies: - caniuse-lite "^1.0.30001449" - electron-to-chromium "^1.4.284" - node-releases "^2.0.8" - update-browserslist-db "^1.0.10" + "caniuse-lite" "^1.0.30001449" + "electron-to-chromium" "^1.4.284" + "node-releases" "^2.0.8" + "update-browserslist-db" "^1.0.10" -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +"callsites@^3.0.0": + "integrity" "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + "resolved" "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + "version" "3.1.0" -caniuse-lite@^1.0.30001449: - version "1.0.30001480" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001480.tgz" - integrity sha512-q7cpoPPvZYgtyC4VaBSN0Bt+PJ4c4EYRf0DrduInOz2SkFpHD5p3LnvEpqBp7UnJn+8x1Ogl1s38saUxe+ihQQ== +"caniuse-lite@^1.0.30001449": + "integrity" "sha512-q7cpoPPvZYgtyC4VaBSN0Bt+PJ4c4EYRf0DrduInOz2SkFpHD5p3LnvEpqBp7UnJn+8x1Ogl1s38saUxe+ihQQ==" + "resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001480.tgz" + "version" "1.0.30001480" -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== +"chalk@^2.0.0": + "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + "version" "2.4.2" dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" + "ansi-styles" "^3.2.1" + "escape-string-regexp" "^1.0.5" + "supports-color" "^5.3.0" -classnames@^2.2.6: - version "2.3.1" - resolved "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz" - integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== +"classnames@^2.2.6": + "integrity" "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + "resolved" "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz" + "version" "2.3.1" -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== +"color-convert@^1.9.0": + "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + "version" "1.9.3" dependencies: - color-name "1.1.3" + "color-name" "1.1.3" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +"color-name@1.1.3": + "integrity" "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + "version" "1.1.3" -compute-scroll-into-view@1.0.14: - version "1.0.14" - resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz" - integrity sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ== +"compute-scroll-into-view@1.0.14": + "integrity" "sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ==" + "resolved" "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz" + "version" "1.0.14" -convert-source-map@^1.5.0, convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== +"convert-source-map@^1.5.0", "convert-source-map@^1.7.0": + "integrity" "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==" + "resolved" "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" + "version" "1.8.0" dependencies: - safe-buffer "~5.1.1" + "safe-buffer" "~5.1.1" -copy-to-clipboard@3.3.1: - version "3.3.1" - resolved "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz" - integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== +"copy-to-clipboard@3.3.1": + "integrity" "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==" + "resolved" "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz" + "version" "3.3.1" dependencies: - toggle-selection "^1.0.6" + "toggle-selection" "^1.0.6" -core-js@^3.6.4: - version "3.30.1" - resolved "https://registry.npmjs.org/core-js/-/core-js-3.30.1.tgz" - integrity sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ== +"core-js@^3.6.4": + "integrity" "sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==" + "resolved" "https://registry.npmjs.org/core-js/-/core-js-3.30.1.tgz" + "version" "3.30.1" -cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz" - integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== +"cosmiconfig@^6.0.0": + "integrity" "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==" + "resolved" "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz" + "version" "6.0.0" dependencies: "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" + "import-fresh" "^3.1.0" + "parse-json" "^5.0.0" + "path-type" "^4.0.0" + "yaml" "^1.7.2" -cross-fetch@^3.0.4: - version "3.1.5" - resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== +"cross-fetch@^3.0.4": + "integrity" "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==" + "resolved" "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz" + "version" "3.1.5" dependencies: - node-fetch "2.6.7" + "node-fetch" "2.6.7" -css-box-model@1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz" - integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== +"css-box-model@1.2.1": + "integrity" "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==" + "resolved" "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz" + "version" "1.2.1" dependencies: - tiny-invariant "^1.0.6" + "tiny-invariant" "^1.0.6" -csstype@^3.0.2, csstype@^3.0.9: - version "3.0.10" - resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz" - integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== +"csstype@^3.0.2", "csstype@^3.0.9": + "integrity" "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" + "resolved" "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz" + "version" "3.0.10" -dayjs@^1.10.7: - version "1.10.7" - resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz" - integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig== +"dayjs@^1.10.7": + "integrity" "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==" + "resolved" "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz" + "version" "1.10.7" -debounce@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz" - integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== +"debounce@^1.2.1": + "integrity" "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + "resolved" "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz" + "version" "1.2.1" -debug@^4.1.0: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +"debug@^4.1.0": + "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + "version" "4.3.4" dependencies: - ms "2.1.2" + "ms" "2.1.2" -detect-node-es@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz" - integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== +"detect-node-es@^1.1.0": + "integrity" "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" + "resolved" "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz" + "version" "1.1.0" -"draft-js@^0.10.x || ^0.11.x", draft-js@^0.11.x: - version "0.11.7" - resolved "https://registry.npmjs.org/draft-js/-/draft-js-0.11.7.tgz" - integrity sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg== +"draft-js@^0.10.x || ^0.11.x", "draft-js@^0.11.x": + "integrity" "sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg==" + "resolved" "https://registry.npmjs.org/draft-js/-/draft-js-0.11.7.tgz" + "version" "0.11.7" dependencies: - fbjs "^2.0.0" - immutable "~3.7.4" - object-assign "^4.1.1" + "fbjs" "^2.0.0" + "immutable" "~3.7.4" + "object-assign" "^4.1.1" -draftjs-utils@^0.10.2: - version "0.10.2" - resolved "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz" - integrity sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg== +"draftjs-utils@^0.10.2": + "integrity" "sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg==" + "resolved" "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz" + "version" "0.10.2" -electron-to-chromium@^1.4.284: - version "1.4.365" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.365.tgz" - integrity sha512-FRHZO+1tUNO4TOPXmlxetkoaIY8uwHzd1kKopK/Gx2SKn1L47wJXWD44wxP5CGRyyP98z/c8e1eBzJrgPeiBOg== +"electron-to-chromium@^1.4.284": + "integrity" "sha512-FRHZO+1tUNO4TOPXmlxetkoaIY8uwHzd1kKopK/Gx2SKn1L47wJXWD44wxP5CGRyyP98z/c8e1eBzJrgPeiBOg==" + "resolved" "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.365.tgz" + "version" "1.4.365" -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== +"error-ex@^1.3.1": + "integrity" "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==" + "resolved" "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + "version" "1.3.2" dependencies: - is-arrayish "^0.2.1" + "is-arrayish" "^0.2.1" -esbuild-linux-64@0.14.9: - version "0.14.9" - resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.9.tgz" - integrity sha512-WoEI+R6/PLZAxS7XagfQMFgRtLUi5cjqqU9VCfo3tnWmAXh/wt8QtUfCVVCcXVwZLS/RNvI19CtfjlrJU61nOg== +"esbuild-darwin-arm64@0.14.9": + "integrity" "sha512-3ue+1T4FR5TaAu4/V1eFMG8Uwn0pgAwQZb/WwL1X78d5Cy8wOVQ67KNH1lsjU+y/9AcwMKZ9x0GGNxBB4a1Rbw==" + "resolved" "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.9.tgz" + "version" "0.14.9" -esbuild@^0.14.9: - version "0.14.9" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.9.tgz" - integrity sha512-uuT3kFsfUvzNW6I2RKKIHuCvutY/U9KFcAP6emUm98WvBhyhEr5vGkZLeN3r3vXfoykl+7xekAH8Ky09LXBd0Q== +"esbuild@^0.14.9": + "integrity" "sha512-uuT3kFsfUvzNW6I2RKKIHuCvutY/U9KFcAP6emUm98WvBhyhEr5vGkZLeN3r3vXfoykl+7xekAH8Ky09LXBd0Q==" + "resolved" "https://registry.npmjs.org/esbuild/-/esbuild-0.14.9.tgz" + "version" "0.14.9" optionalDependencies: - esbuild-android-arm64 "0.14.9" - esbuild-darwin-64 "0.14.9" - esbuild-darwin-arm64 "0.14.9" - esbuild-freebsd-64 "0.14.9" - esbuild-freebsd-arm64 "0.14.9" - esbuild-linux-32 "0.14.9" - esbuild-linux-64 "0.14.9" - esbuild-linux-arm "0.14.9" - esbuild-linux-arm64 "0.14.9" - esbuild-linux-mips64le "0.14.9" - esbuild-linux-ppc64le "0.14.9" - esbuild-linux-s390x "0.14.9" - esbuild-netbsd-64 "0.14.9" - esbuild-openbsd-64 "0.14.9" - esbuild-sunos-64 "0.14.9" - esbuild-windows-32 "0.14.9" - esbuild-windows-64 "0.14.9" - esbuild-windows-arm64 "0.14.9" + "esbuild-android-arm64" "0.14.9" + "esbuild-darwin-64" "0.14.9" + "esbuild-darwin-arm64" "0.14.9" + "esbuild-freebsd-64" "0.14.9" + "esbuild-freebsd-arm64" "0.14.9" + "esbuild-linux-32" "0.14.9" + "esbuild-linux-64" "0.14.9" + "esbuild-linux-arm" "0.14.9" + "esbuild-linux-arm64" "0.14.9" + "esbuild-linux-mips64le" "0.14.9" + "esbuild-linux-ppc64le" "0.14.9" + "esbuild-linux-s390x" "0.14.9" + "esbuild-netbsd-64" "0.14.9" + "esbuild-openbsd-64" "0.14.9" + "esbuild-sunos-64" "0.14.9" + "esbuild-windows-32" "0.14.9" + "esbuild-windows-64" "0.14.9" + "esbuild-windows-arm64" "0.14.9" -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +"escalade@^3.1.1": + "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + "version" "3.1.1" -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +"escape-string-regexp@^1.0.5": + "integrity" "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + "version" "1.0.5" -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +"escape-string-regexp@^4.0.0": + "integrity" "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + "version" "4.0.0" -fbjs-css-vars@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz" - integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== +"fbjs-css-vars@^1.0.0": + "integrity" "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + "resolved" "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz" + "version" "1.0.2" -fbjs@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz" - integrity sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ== +"fbjs@^2.0.0": + "integrity" "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ==" + "resolved" "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz" + "version" "2.0.0" dependencies: - core-js "^3.6.4" - cross-fetch "^3.0.4" - fbjs-css-vars "^1.0.0" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.18" + "core-js" "^3.6.4" + "cross-fetch" "^3.0.4" + "fbjs-css-vars" "^1.0.0" + "loose-envify" "^1.0.0" + "object-assign" "^4.1.0" + "promise" "^7.1.1" + "setimmediate" "^1.0.5" + "ua-parser-js" "^0.7.18" -file-selector@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/file-selector/-/file-selector-0.4.0.tgz" - integrity sha512-iACCiXeMYOvZqlF1kTiYINzgepRBymz1wwjiuup9u9nayhb6g4fSwiyJ/6adli+EPwrWtpgQAh2PoS7HukEGEg== +"file-selector@^0.4.0": + "integrity" "sha512-iACCiXeMYOvZqlF1kTiYINzgepRBymz1wwjiuup9u9nayhb6g4fSwiyJ/6adli+EPwrWtpgQAh2PoS7HukEGEg==" + "resolved" "https://registry.npmjs.org/file-selector/-/file-selector-0.4.0.tgz" + "version" "0.4.0" dependencies: - tslib "^2.0.3" + "tslib" "^2.0.3" -find-root@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== +"find-root@^1.1.0": + "integrity" "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + "resolved" "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz" + "version" "1.1.0" -focus-lock@^0.9.1: - version "0.9.2" - resolved "https://registry.npmjs.org/focus-lock/-/focus-lock-0.9.2.tgz" - integrity sha512-YtHxjX7a0IC0ZACL5wsX8QdncXofWpGPNoVMuI/nZUrPGp6LmNI6+D5j0pPj+v8Kw5EpweA+T5yImK0rnWf7oQ== +"focus-lock@^0.9.1": + "integrity" "sha512-YtHxjX7a0IC0ZACL5wsX8QdncXofWpGPNoVMuI/nZUrPGp6LmNI6+D5j0pPj+v8Kw5EpweA+T5yImK0rnWf7oQ==" + "resolved" "https://registry.npmjs.org/focus-lock/-/focus-lock-0.9.2.tgz" + "version" "0.9.2" dependencies: - tslib "^2.0.3" + "tslib" "^2.0.3" -focus-visible@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/focus-visible/-/focus-visible-5.2.0.tgz" - integrity sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ== +"focus-visible@^5.2.0": + "integrity" "sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ==" + "resolved" "https://registry.npmjs.org/focus-visible/-/focus-visible-5.2.0.tgz" + "version" "5.2.0" -framer-motion@^5.5.5, "framer-motion@3.x || 4.x || 5.x": - version "5.5.5" - resolved "https://registry.npmjs.org/framer-motion/-/framer-motion-5.5.5.tgz" - integrity sha512-+LPAF5ddo02qKh+MK4h1ChwqUFvrLkK1NDWwrHy+MuCVmQDGgiFNHvwqOSklTDGkEtbio3dCOEDy23+ZyNAa9g== +"framer-motion@^5.5.5", "framer-motion@3.x || 4.x || 5.x": + "integrity" "sha512-+LPAF5ddo02qKh+MK4h1ChwqUFvrLkK1NDWwrHy+MuCVmQDGgiFNHvwqOSklTDGkEtbio3dCOEDy23+ZyNAa9g==" + "resolved" "https://registry.npmjs.org/framer-motion/-/framer-motion-5.5.5.tgz" + "version" "5.5.5" dependencies: - framesync "6.0.1" - hey-listen "^1.0.8" - popmotion "11.0.3" - react-merge-refs "^1.1.0" - react-use-measure "^2.1.1" - style-value-types "5.0.0" - tslib "^2.1.0" + "framesync" "6.0.1" + "hey-listen" "^1.0.8" + "popmotion" "11.0.3" + "react-merge-refs" "^1.1.0" + "react-use-measure" "^2.1.1" + "style-value-types" "5.0.0" + "tslib" "^2.1.0" optionalDependencies: "@emotion/is-prop-valid" "^0.8.2" -framesync@5.3.0: - version "5.3.0" - resolved "https://registry.npmjs.org/framesync/-/framesync-5.3.0.tgz" - integrity sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA== +"framesync@5.3.0": + "integrity" "sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA==" + "resolved" "https://registry.npmjs.org/framesync/-/framesync-5.3.0.tgz" + "version" "5.3.0" dependencies: - tslib "^2.1.0" + "tslib" "^2.1.0" -framesync@6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz" - integrity sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA== +"framesync@6.0.1": + "integrity" "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==" + "resolved" "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz" + "version" "6.0.1" dependencies: - tslib "^2.1.0" + "tslib" "^2.1.0" -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +"function-bind@^1.1.1": + "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + "version" "1.1.1" -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== +"gensync@^1.0.0-beta.2": + "integrity" "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + "resolved" "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + "version" "1.0.0-beta.2" -get-nonce@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz" - integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== +"get-nonce@^1.0.0": + "integrity" "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==" + "resolved" "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz" + "version" "1.0.1" -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +"globals@^11.1.0": + "integrity" "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "resolved" "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + "version" "11.12.0" -"graphql@^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "graphql@^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", graphql@^16.2.0: - version "16.2.0" - resolved "https://registry.npmjs.org/graphql/-/graphql-16.2.0.tgz" - integrity sha512-MuQd7XXrdOcmfwuLwC2jNvx0n3rxIuNYOxUtiee5XOmfrWo613ar2U8pE7aHAKh8VwfpifubpD9IP+EdEAEOsA== +"graphql@^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "graphql@^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "graphql@^16.2.0": + "integrity" "sha512-MuQd7XXrdOcmfwuLwC2jNvx0n3rxIuNYOxUtiee5XOmfrWo613ar2U8pE7aHAKh8VwfpifubpD9IP+EdEAEOsA==" + "resolved" "https://registry.npmjs.org/graphql/-/graphql-16.2.0.tgz" + "version" "16.2.0" -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== +"has-flag@^3.0.0": + "integrity" "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + "version" "3.0.0" -has@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== +"has@^1.0.3": + "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" + "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + "version" "1.0.3" dependencies: - function-bind "^1.1.1" + "function-bind" "^1.1.1" -hey-listen@^1.0.8: - version "1.0.8" - resolved "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz" - integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q== +"hey-listen@^1.0.8": + "integrity" "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==" + "resolved" "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz" + "version" "1.0.8" -history@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/history/-/history-5.2.0.tgz" - integrity sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig== +"history@^5.2.0": + "integrity" "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==" + "resolved" "https://registry.npmjs.org/history/-/history-5.2.0.tgz" + "version" "5.2.0" dependencies: "@babel/runtime" "^7.7.6" -hoist-non-react-statics@^3.3.1: - version "3.3.2" - resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== +"hoist-non-react-statics@^3.3.1": + "integrity" "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==" + "resolved" "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" + "version" "3.3.2" dependencies: - react-is "^16.7.0" + "react-is" "^16.7.0" -html-to-draftjs@^1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/html-to-draftjs/-/html-to-draftjs-1.5.0.tgz" - integrity sha512-kggLXBNciKDwKf+KYsuE+V5gw4dZ7nHyGMX9m0wy7urzWjKGWyNFetmArRLvRV0VrxKN70WylFsJvMTJx02OBQ== +"html-to-draftjs@^1.5.0": + "integrity" "sha512-kggLXBNciKDwKf+KYsuE+V5gw4dZ7nHyGMX9m0wy7urzWjKGWyNFetmArRLvRV0VrxKN70WylFsJvMTJx02OBQ==" + "resolved" "https://registry.npmjs.org/html-to-draftjs/-/html-to-draftjs-1.5.0.tgz" + "version" "1.5.0" -immutable@~3.7.4: - version "3.7.6" - resolved "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz" - integrity sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw== +"immutable@~3.7.4": + "integrity" "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==" + "resolved" "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz" + "version" "3.7.6" "immutable@3.x.x || 4.x.x": - version "4.3.0" - resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz" - integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg== + "integrity" "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==" + "resolved" "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz" + "version" "4.3.0" -import-fresh@^3.1.0: - version "3.3.0" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== +"import-fresh@^3.1.0": + "integrity" "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==" + "resolved" "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + "version" "3.3.0" dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" + "parent-module" "^1.0.0" + "resolve-from" "^4.0.0" -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== +"invariant@^2.2.4": + "integrity" "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==" + "resolved" "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" + "version" "2.2.4" dependencies: - loose-envify "^1.0.0" + "loose-envify" "^1.0.0" -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +"is-arrayish@^0.2.1": + "integrity" "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "resolved" "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + "version" "0.2.1" -is-core-module@^2.2.0: - version "2.8.0" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz" - integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== +"is-core-module@^2.2.0": + "integrity" "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==" + "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz" + "version" "2.8.0" dependencies: - has "^1.0.3" + "has" "^1.0.3" -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +"js-tokens@^3.0.0 || ^4.0.0", "js-tokens@^4.0.0": + "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + "version" "4.0.0" -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +"jsesc@^2.5.1": + "integrity" "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + "version" "2.5.2" -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - 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== +"json-parse-even-better-errors@^2.3.0": + "integrity" "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + "resolved" "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + "version" "2.3.1" -json5@^2.2.2: - version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +"json5@^2.2.2": + "integrity" "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + "resolved" "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + "version" "2.2.3" -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +"lines-and-columns@^1.1.6": + "integrity" "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "resolved" "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + "version" "1.2.4" -linkify-it@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz" - integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw== +"linkify-it@^2.2.0": + "integrity" "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==" + "resolved" "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz" + "version" "2.2.0" dependencies: - uc.micro "^1.0.1" + "uc.micro" "^1.0.1" -lodash.mergewith@4.6.2: - version "4.6.2" - resolved "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz" - integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== +"lodash.mergewith@4.6.2": + "integrity" "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" + "resolved" "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz" + "version" "4.6.2" -lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +"lodash@^4.17.21": + "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + "version" "4.17.21" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== +"loose-envify@^1.0.0", "loose-envify@^1.1.0", "loose-envify@^1.4.0": + "integrity" "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==" + "resolved" "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + "version" "1.4.0" dependencies: - js-tokens "^3.0.0 || ^4.0.0" + "js-tokens" "^3.0.0 || ^4.0.0" -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== +"lru-cache@^5.1.1": + "integrity" "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==" + "resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + "version" "5.1.1" dependencies: - yallist "^3.0.2" + "yallist" "^3.0.2" -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +"ms@2.1.2": + "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + "version" "2.1.2" -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== +"node-fetch@2.6.7": + "integrity" "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==" + "resolved" "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" + "version" "2.6.7" dependencies: - whatwg-url "^5.0.0" + "whatwg-url" "^5.0.0" -node-releases@^2.0.8: - version "2.0.10" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz" - integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== +"node-releases@^2.0.8": + "integrity" "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "resolved" "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz" + "version" "2.0.10" -object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= +"object-assign@^4.1.0", "object-assign@^4.1.1": + "integrity" "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "resolved" "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + "version" "4.1.1" -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== +"parent-module@^1.0.0": + "integrity" "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==" + "resolved" "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + "version" "1.0.1" dependencies: - callsites "^3.0.0" + "callsites" "^3.0.0" -parse-json@^5.0.0: - version "5.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== +"parse-json@^5.0.0": + "integrity" "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==" + "resolved" "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + "version" "5.2.0" dependencies: "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" + "error-ex" "^1.3.1" + "json-parse-even-better-errors" "^2.3.0" + "lines-and-columns" "^1.1.6" -path-parse@^1.0.6: - version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +"path-parse@^1.0.6": + "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + "version" "1.0.7" -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +"path-type@^4.0.0": + "integrity" "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + "resolved" "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + "version" "4.0.0" -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +"picocolors@^1.0.0": + "integrity" "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "resolved" "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + "version" "1.0.0" -popmotion@11.0.3: - version "11.0.3" - resolved "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz" - integrity sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA== +"popmotion@11.0.3": + "integrity" "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==" + "resolved" "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz" + "version" "11.0.3" dependencies: - framesync "6.0.1" - hey-listen "^1.0.8" - style-value-types "5.0.0" - tslib "^2.1.0" + "framesync" "6.0.1" + "hey-listen" "^1.0.8" + "style-value-types" "5.0.0" + "tslib" "^2.1.0" -prettier@2.7.1: - version "2.7.1" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz" - integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== +"prettier@2.7.1": + "integrity" "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==" + "resolved" "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz" + "version" "2.7.1" -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz" - integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== +"promise@^7.1.1": + "integrity" "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==" + "resolved" "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz" + "version" "7.3.1" dependencies: - asap "~2.0.3" + "asap" "~2.0.3" -prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== +"prop-types@^15.6.2", "prop-types@^15.7.2", "prop-types@^15.8.1": + "integrity" "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" + "resolved" "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" + "version" "15.8.1" dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" + "loose-envify" "^1.4.0" + "object-assign" "^4.1.1" + "react-is" "^16.13.1" -react-clientside-effect@^1.2.5: - version "1.2.5" - resolved "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz" - integrity sha512-2bL8qFW1TGBHozGGbVeyvnggRpMjibeZM2536AKNENLECutp2yfs44IL8Hmpn8qjFQ2K7A9PnYf3vc7aQq/cPA== +"react-clientside-effect@^1.2.5": + "integrity" "sha512-2bL8qFW1TGBHozGGbVeyvnggRpMjibeZM2536AKNENLECutp2yfs44IL8Hmpn8qjFQ2K7A9PnYf3vc7aQq/cPA==" + "resolved" "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz" + "version" "1.2.5" dependencies: "@babel/runtime" "^7.12.13" -"react-dom@^16.8.0 || 17.x", react-dom@^17.0.2, react-dom@>=0.14.0, react-dom@>=16.13, react-dom@>=16.8, "react-dom@>=16.8 || ^17.0.0", react-dom@>=16.8.6, "react-dom@0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x": - version "17.0.2" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== +"react-dom@^16.8.0 || 17.x", "react-dom@^17.0.2", "react-dom@>=0.14.0", "react-dom@>=16.13", "react-dom@>=16.8", "react-dom@>=16.8 || ^17.0.0", "react-dom@>=16.8.6", "react-dom@0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x": + "integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==" + "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" + "version" "17.0.2" dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" + "loose-envify" "^1.1.0" + "object-assign" "^4.1.1" + "scheduler" "^0.20.2" -react-draft-wysiwyg@^1.15.0: - version "1.15.0" - resolved "https://registry.npmjs.org/react-draft-wysiwyg/-/react-draft-wysiwyg-1.15.0.tgz" - integrity sha512-p1cYZcWc6/ALFBVksbFoCM3b29fGQDlZLIMrXng0TU/UElxIOF2/AWWo4L5auIYVhmqKTZ0NkNjnXOzGGuxyeA== +"react-draft-wysiwyg@^1.15.0": + "integrity" "sha512-p1cYZcWc6/ALFBVksbFoCM3b29fGQDlZLIMrXng0TU/UElxIOF2/AWWo4L5auIYVhmqKTZ0NkNjnXOzGGuxyeA==" + "resolved" "https://registry.npmjs.org/react-draft-wysiwyg/-/react-draft-wysiwyg-1.15.0.tgz" + "version" "1.15.0" dependencies: - classnames "^2.2.6" - draftjs-utils "^0.10.2" - html-to-draftjs "^1.5.0" - linkify-it "^2.2.0" - prop-types "^15.7.2" + "classnames" "^2.2.6" + "draftjs-utils" "^0.10.2" + "html-to-draftjs" "^1.5.0" + "linkify-it" "^2.2.0" + "prop-types" "^15.7.2" -react-dropzone@^12.0.4: - version "12.0.4" - resolved "https://registry.npmjs.org/react-dropzone/-/react-dropzone-12.0.4.tgz" - integrity sha512-fcqHEYe1MzAghU6/Hz86lHDlBNsA+lO48nAcm7/wA+kIzwS6uuJbUG33tBZjksj7GAZ1iUQ6NHwjUURPmSGang== +"react-dropzone@^12.0.4": + "integrity" "sha512-fcqHEYe1MzAghU6/Hz86lHDlBNsA+lO48nAcm7/wA+kIzwS6uuJbUG33tBZjksj7GAZ1iUQ6NHwjUURPmSGang==" + "resolved" "https://registry.npmjs.org/react-dropzone/-/react-dropzone-12.0.4.tgz" + "version" "12.0.4" dependencies: - attr-accept "^2.2.2" - file-selector "^0.4.0" - prop-types "^15.8.1" + "attr-accept" "^2.2.2" + "file-selector" "^0.4.0" + "prop-types" "^15.8.1" -react-email-editor@^1.6.1: - version "1.6.1" - resolved "https://registry.npmjs.org/react-email-editor/-/react-email-editor-1.6.1.tgz" - integrity sha512-pEWpRmTY0ok03cwTGqEOoEldnzThhuRGTrcMnv8W3/jc5MTfcr9USU/IQ9HrVvFStLKoxYBIQnSKY+iCYWOtSQ== +"react-email-editor@^1.6.1": + "integrity" "sha512-pEWpRmTY0ok03cwTGqEOoEldnzThhuRGTrcMnv8W3/jc5MTfcr9USU/IQ9HrVvFStLKoxYBIQnSKY+iCYWOtSQ==" + "resolved" "https://registry.npmjs.org/react-email-editor/-/react-email-editor-1.6.1.tgz" + "version" "1.6.1" -react-fast-compare@3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz" - integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== +"react-fast-compare@3.2.0": + "integrity" "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + "resolved" "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz" + "version" "3.2.0" -react-focus-lock@2.5.2: - version "2.5.2" - resolved "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.5.2.tgz" - integrity sha512-WzpdOnEqjf+/A3EH9opMZWauag7gV0BxFl+EY4ElA4qFqYsUsBLnmo2sELbN5OC30S16GAWMy16B9DLPpdJKAQ== +"react-focus-lock@2.5.2": + "integrity" "sha512-WzpdOnEqjf+/A3EH9opMZWauag7gV0BxFl+EY4ElA4qFqYsUsBLnmo2sELbN5OC30S16GAWMy16B9DLPpdJKAQ==" + "resolved" "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.5.2.tgz" + "version" "2.5.2" dependencies: "@babel/runtime" "^7.0.0" - focus-lock "^0.9.1" - prop-types "^15.6.2" - react-clientside-effect "^1.2.5" - use-callback-ref "^1.2.5" - use-sidecar "^1.0.5" + "focus-lock" "^0.9.1" + "prop-types" "^15.6.2" + "react-clientside-effect" "^1.2.5" + "use-callback-ref" "^1.2.5" + "use-sidecar" "^1.0.5" -react-icons@^4.3.1: - version "4.3.1" - resolved "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz" - integrity sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ== +"react-icons@^4.3.1": + "integrity" "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==" + "resolved" "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz" + "version" "4.3.1" -react-is@^16.13.1, react-is@^16.7.0: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +"react-is@^16.13.1", "react-is@^16.7.0": + "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + "version" "16.13.1" -react-merge-refs@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz" - integrity sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ== +"react-merge-refs@^1.1.0": + "integrity" "sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==" + "resolved" "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz" + "version" "1.1.0" -react-remove-scroll-bar@^2.1.0: - version "2.2.0" - resolved "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.2.0.tgz" - integrity sha512-UU9ZBP1wdMR8qoUs7owiVcpaPwsQxUDC2lypP6mmixaGlARZa7ZIBx1jcuObLdhMOvCsnZcvetOho0wzPa9PYg== +"react-remove-scroll-bar@^2.1.0": + "integrity" "sha512-UU9ZBP1wdMR8qoUs7owiVcpaPwsQxUDC2lypP6mmixaGlARZa7ZIBx1jcuObLdhMOvCsnZcvetOho0wzPa9PYg==" + "resolved" "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.2.0.tgz" + "version" "2.2.0" dependencies: - react-style-singleton "^2.1.0" - tslib "^1.0.0" + "react-style-singleton" "^2.1.0" + "tslib" "^1.0.0" -react-remove-scroll@2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.4.1.tgz" - integrity sha512-K7XZySEzOHMTq7dDwcHsZA6Y7/1uX5RsWhRXVYv8rdh+y9Qz2nMwl9RX/Mwnj/j7JstCGmxyfyC0zbVGXYh3mA== +"react-remove-scroll@2.4.1": + "integrity" "sha512-K7XZySEzOHMTq7dDwcHsZA6Y7/1uX5RsWhRXVYv8rdh+y9Qz2nMwl9RX/Mwnj/j7JstCGmxyfyC0zbVGXYh3mA==" + "resolved" "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.4.1.tgz" + "version" "2.4.1" dependencies: - react-remove-scroll-bar "^2.1.0" - react-style-singleton "^2.1.0" - tslib "^1.0.0" - use-callback-ref "^1.2.3" - use-sidecar "^1.0.1" + "react-remove-scroll-bar" "^2.1.0" + "react-style-singleton" "^2.1.0" + "tslib" "^1.0.0" + "use-callback-ref" "^1.2.3" + "use-sidecar" "^1.0.1" -react-router-dom@^6.2.1: - version "6.2.1" - resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz" - integrity sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA== +"react-router-dom@^6.2.1": + "integrity" "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==" + "resolved" "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz" + "version" "6.2.1" dependencies: - history "^5.2.0" - react-router "6.2.1" + "history" "^5.2.0" + "react-router" "6.2.1" -react-router@6.2.1: - version "6.2.1" - resolved "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz" - integrity sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg== +"react-router@6.2.1": + "integrity" "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==" + "resolved" "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz" + "version" "6.2.1" dependencies: - history "^5.2.0" + "history" "^5.2.0" -react-style-singleton@^2.1.0: - version "2.1.1" - resolved "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.1.1.tgz" - integrity sha512-jNRp07Jza6CBqdRKNgGhT3u9umWvils1xsuMOjZlghBDH2MU0PL2WZor4PGYjXpnRCa9DQSlHMs/xnABWOwYbA== +"react-style-singleton@^2.1.0": + "integrity" "sha512-jNRp07Jza6CBqdRKNgGhT3u9umWvils1xsuMOjZlghBDH2MU0PL2WZor4PGYjXpnRCa9DQSlHMs/xnABWOwYbA==" + "resolved" "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.1.1.tgz" + "version" "2.1.1" dependencies: - get-nonce "^1.0.0" - invariant "^2.2.4" - tslib "^1.0.0" + "get-nonce" "^1.0.0" + "invariant" "^2.2.4" + "tslib" "^1.0.0" -react-use-measure@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz" - integrity sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig== +"react-use-measure@^2.1.1": + "integrity" "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==" + "resolved" "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz" + "version" "2.1.1" dependencies: - debounce "^1.2.1" + "debounce" "^1.2.1" -react@*, "react@^15.3.0 || ^16.0.0 || ^17.0.0", "react@^16.8.0 || ^17.0.0", "react@^16.8.0 || 17.x", react@^17.0.2, "react@>= 16.8", "react@>= 16.8.0", react@>=0.14.0, react@>=16.13, react@>=16.8, "react@>=16.8 || ^17.0.0", react@>=16.8.0, react@>=16.8.6, "react@0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x", "react@15.x || 16.x || 17.x", react@17.0.2: - version "17.0.2" - resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== +"react@*", "react@^15.3.0 || ^16.0.0 || ^17.0.0", "react@^16.8.0 || ^17.0.0", "react@^16.8.0 || 17.x", "react@^17.0.2", "react@>= 16.8", "react@>= 16.8.0", "react@>=0.14.0", "react@>=16.13", "react@>=16.8", "react@>=16.8 || ^17.0.0", "react@>=16.8.0", "react@>=16.8.6", "react@0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x", "react@15.x || 16.x || 17.x", "react@17.0.2": + "integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==" + "resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz" + "version" "17.0.2" dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" + "loose-envify" "^1.1.0" + "object-assign" "^4.1.1" -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +"regenerator-runtime@^0.13.4": + "integrity" "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" + "version" "0.13.9" -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +"resolve-from@^4.0.0": + "integrity" "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + "version" "4.0.0" -resolve@^1.12.0: - version "1.20.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== +"resolve@^1.12.0": + "integrity" "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==" + "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz" + "version" "1.20.0" dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" + "is-core-module" "^2.2.0" + "path-parse" "^1.0.6" -safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +"safe-buffer@~5.1.1": + "integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + "version" "5.1.2" -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== +"scheduler@^0.20.2": + "integrity" "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==" + "resolved" "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz" + "version" "0.20.2" dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" + "loose-envify" "^1.1.0" + "object-assign" "^4.1.1" -semver@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +"semver@^6.3.0": + "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + "version" "6.3.0" -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== +"setimmediate@^1.0.5": + "integrity" "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + "resolved" "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" + "version" "1.0.5" -source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= +"source-map@^0.5.7": + "integrity" "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + "version" "0.5.7" -style-value-types@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz" - integrity sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA== +"style-value-types@5.0.0": + "integrity" "sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==" + "resolved" "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz" + "version" "5.0.0" dependencies: - hey-listen "^1.0.8" - tslib "^2.1.0" + "hey-listen" "^1.0.8" + "tslib" "^2.1.0" -stylis@4.0.13: - version "4.0.13" - resolved "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz" - integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== +"stylis@4.0.13": + "integrity" "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + "resolved" "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz" + "version" "4.0.13" -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== +"supports-color@^5.3.0": + "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + "version" "5.5.0" dependencies: - has-flag "^3.0.0" + "has-flag" "^3.0.0" -tiny-invariant@^1.0.6: - version "1.2.0" - resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz" - integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== +"tiny-invariant@^1.0.6": + "integrity" "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" + "resolved" "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz" + "version" "1.2.0" -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= +"to-fast-properties@^2.0.0": + "integrity" "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "resolved" "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + "version" "2.0.0" -toggle-selection@^1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz" - integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= +"toggle-selection@^1.0.6": + "integrity" "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" + "resolved" "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz" + "version" "1.0.6" -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +"tr46@~0.0.3": + "integrity" "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "resolved" "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" + "version" "0.0.3" -tslib@^1.0.0: - version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +"tslib@^1.0.0": + "integrity" "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + "version" "1.14.1" -tslib@^1.9.3: - version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +"tslib@^1.9.3": + "integrity" "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + "version" "1.14.1" -tslib@^2.0.3, tslib@^2.1.0: - version "2.3.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +"tslib@^2.0.3", "tslib@^2.1.0": + "integrity" "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" + "version" "2.3.1" -typescript@^4.5.4: - version "4.5.4" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz" - integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== +"typescript@^4.5.4": + "integrity" "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==" + "resolved" "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz" + "version" "4.5.4" -ua-parser-js@^0.7.18: - version "0.7.35" - resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz" - integrity sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g== +"ua-parser-js@^0.7.18": + "integrity" "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==" + "resolved" "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz" + "version" "0.7.35" -uc.micro@^1.0.1: - version "1.0.6" - resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz" - integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== +"uc.micro@^1.0.1": + "integrity" "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + "resolved" "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz" + "version" "1.0.6" -update-browserslist-db@^1.0.10: - version "1.0.11" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz" - integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== +"update-browserslist-db@^1.0.10": + "integrity" "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==" + "resolved" "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz" + "version" "1.0.11" dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + "escalade" "^3.1.1" + "picocolors" "^1.0.0" -urql@^2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/urql/-/urql-2.0.6.tgz" - integrity sha512-ovK9mx7YxD/CKUwVZGbEDBzZjbCcNsr1990nIhDCKe3Ij/0gNcIa+0EIyXKceOPuYDYKavIoaNQV2kOZjQxFcw== +"urql@^2.0.6": + "integrity" "sha512-ovK9mx7YxD/CKUwVZGbEDBzZjbCcNsr1990nIhDCKe3Ij/0gNcIa+0EIyXKceOPuYDYKavIoaNQV2kOZjQxFcw==" + "resolved" "https://registry.npmjs.org/urql/-/urql-2.0.6.tgz" + "version" "2.0.6" dependencies: "@urql/core" "^2.3.6" - wonka "^4.0.14" + "wonka" "^4.0.14" -use-callback-ref@^1.2.3, use-callback-ref@^1.2.5: - version "1.2.5" - resolved "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz" - integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg== +"use-callback-ref@^1.2.3", "use-callback-ref@^1.2.5": + "integrity" "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==" + "resolved" "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz" + "version" "1.2.5" -use-sidecar@^1.0.1, use-sidecar@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.0.5.tgz" - integrity sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA== +"use-sidecar@^1.0.1", "use-sidecar@^1.0.5": + "integrity" "sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA==" + "resolved" "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.0.5.tgz" + "version" "1.0.5" dependencies: - detect-node-es "^1.1.0" - tslib "^1.9.3" + "detect-node-es" "^1.1.0" + "tslib" "^1.9.3" -warning@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz" - integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== +"warning@^4.0.3": + "integrity" "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==" + "resolved" "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz" + "version" "4.0.3" dependencies: - loose-envify "^1.0.0" + "loose-envify" "^1.0.0" -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== +"webidl-conversions@^3.0.0": + "integrity" "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "resolved" "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" + "version" "3.0.1" -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== +"whatwg-url@^5.0.0": + "integrity" "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==" + "resolved" "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" + "version" "5.0.0" dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" + "tr46" "~0.0.3" + "webidl-conversions" "^3.0.0" -wonka@^4.0.14: - version "4.0.15" - resolved "https://registry.npmjs.org/wonka/-/wonka-4.0.15.tgz" - integrity sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg== +"wonka@^4.0.14": + "integrity" "sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==" + "resolved" "https://registry.npmjs.org/wonka/-/wonka-4.0.15.tgz" + "version" "4.0.15" -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== +"yallist@^3.0.2": + "integrity" "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "resolved" "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + "version" "3.1.1" -yaml@^1.7.2: - version "1.10.2" - resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +"yaml@^1.7.2": + "integrity" "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + "resolved" "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" + "version" "1.10.2" diff --git a/server/constants/auth_methods.go b/server/constants/auth_methods.go index 9e7b9fa..dbe5175 100644 --- a/server/constants/auth_methods.go +++ b/server/constants/auth_methods.go @@ -7,6 +7,8 @@ const ( AuthRecipeMethodMobileBasicAuth = "mobile_basic_auth" // AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method AuthRecipeMethodMagicLinkLogin = "magic_link_login" + // AuthRecipeMethodMobileOTP is the mobile_otp auth method + AuthRecipeMethodMobileOTP = "mobile_otp" // AuthRecipeMethodGoogle is the google auth method AuthRecipeMethodGoogle = "google" // AuthRecipeMethodGithub is the github auth method diff --git a/server/constants/cookie.go b/server/constants/cookie.go index 71320a9..8f6399b 100644 --- a/server/constants/cookie.go +++ b/server/constants/cookie.go @@ -5,4 +5,6 @@ const ( AppCookieName = "cookie" // AdminCookieName is the name of the cookie that is used to store the admin token AdminCookieName = "authorizer-admin" + // MfaCookieName is the name of the cookie that is used to store the mfa session + MfaCookieName = "mfa" ) diff --git a/server/constants/env.go b/server/constants/env.go index c6b82ee..828d4b8 100644 --- a/server/constants/env.go +++ b/server/constants/env.go @@ -66,6 +66,8 @@ const ( EnvKeySenderName = "SENDER_NAME" // EnvKeyIsEmailServiceEnabled key for env variable IS_EMAIL_SERVICE_ENABLED EnvKeyIsEmailServiceEnabled = "IS_EMAIL_SERVICE_ENABLED" + // EnvKeyIsSMSServiceEnabled key for env variable IS_SMS_SERVICE_ENABLED + EnvKeyIsSMSServiceEnabled = "IS_SMS_SERVICE_ENABLED" // EnvKeyAppCookieSecure key for env variable APP_COOKIE_SECURE EnvKeyAppCookieSecure = "APP_COOKIE_SECURE" // EnvKeyAdminCookieSecure key for env variable ADMIN_COOKIE_SECURE @@ -158,6 +160,9 @@ const ( // 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 EnvKeyDisableMultiFactorAuthentication = "DISABLE_MULTI_FACTOR_AUTHENTICATION" + // EnvKeyDisablePhoneVerification is key for env variable DISABLE_PHONE_VERIFICATION + // this variable is used to disable phone verification + EnvKeyDisablePhoneVerification = "DISABLE_PHONE_VERIFICATION" // EnvKeyDisablePlayGround is key for env variable DISABLE_PLAYGROUND // this variable will disable or enable playground use in dashboard EnvKeyDisablePlayGround = "DISABLE_PLAYGROUND" @@ -180,12 +185,13 @@ const ( // This env is used for setting default response mode in authorize handler EnvKeyDefaultAuthorizeResponseMode = "DEFAULT_AUTHORIZE_RESPONSE_MODE" - // Phone verification setting - EnvKeyDisablePhoneVerification = "DISABLE_PHONE_VERIFICATION" - // Twilio env variables - EnvKeyTwilioAPIKey = "TWILIO_API_KEY" - EnvKeyTwilioAPISecret = "TWILIO_API_SECRET" + // EnvKeyTwilioAPIKey key for env variable TWILIO_API_KEY + EnvKeyTwilioAPIKey = "TWILIO_API_KEY" + // EnvKeyTwilioAPISecret key for env variable TWILIO_API_SECRET + EnvKeyTwilioAPISecret = "TWILIO_API_SECRET" + // EnvKeyTwilioAccountSID key for env variable TWILIO_ACCOUNT_SID EnvKeyTwilioAccountSID = "TWILIO_ACCOUNT_SID" - EnvKeyTwilioSenderFrom = "TWILIO_SENDER_FROM" + // EnvKeyTwilioSender key for env variable TWILIO_SENDER + EnvKeyTwilioSender = "TWILIO_SENDER" ) diff --git a/server/cookie/mfa_session.go b/server/cookie/mfa_session.go new file mode 100644 index 0000000..3fdcaac --- /dev/null +++ b/server/cookie/mfa_session.go @@ -0,0 +1,89 @@ +package cookie + +import ( + "net/http" + "net/url" + + log "github.com/sirupsen/logrus" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" + "github.com/gin-gonic/gin" +) + +// SetMfaSession sets the mfa session cookie in the response +func SetMfaSession(gc *gin.Context, sessionID string) { + appCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAppCookieSecure) + if err != nil { + log.Debug("Error while getting app cookie secure from env variable: %v", err) + appCookieSecure = true + } + + secure := appCookieSecure + httpOnly := appCookieSecure + hostname := parsers.GetHost(gc) + host, _ := parsers.GetHostParts(hostname) + domain := parsers.GetDomainName(hostname) + if domain != "localhost" { + domain = "." + domain + } + + // Since app cookie can come from cross site it becomes important to set this in lax mode when insecure. + // Example person using custom UI on their app domain and making request to authorizer domain. + // For more information check: + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite + // https://github.com/gin-gonic/gin/blob/master/context.go#L86 + // TODO add ability to sameSite = none / strict from dashboard + if !appCookieSecure { + gc.SetSameSite(http.SameSiteLaxMode) + } else { + gc.SetSameSite(http.SameSiteNoneMode) + } + // TODO allow configuring from dashboard + age := 60 + + gc.SetCookie(constants.MfaCookieName+"_session", sessionID, age, "/", host, secure, httpOnly) + gc.SetCookie(constants.MfaCookieName+"_session_domain", sessionID, age, "/", domain, secure, httpOnly) +} + +// DeleteMfaSession deletes the mfa session cookies to expire +func DeleteMfaSession(gc *gin.Context) { + appCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAppCookieSecure) + if err != nil { + log.Debug("Error while getting app cookie secure from env variable: %v", err) + appCookieSecure = true + } + + secure := appCookieSecure + httpOnly := appCookieSecure + hostname := parsers.GetHost(gc) + host, _ := parsers.GetHostParts(hostname) + domain := parsers.GetDomainName(hostname) + if domain != "localhost" { + domain = "." + domain + } + + gc.SetSameSite(http.SameSiteNoneMode) + gc.SetCookie(constants.MfaCookieName+"_session", "", -1, "/", host, secure, httpOnly) + gc.SetCookie(constants.MfaCookieName+"_session_domain", "", -1, "/", domain, secure, httpOnly) +} + +// GetMfaSession gets the mfa session cookie from context +func GetMfaSession(gc *gin.Context) (string, error) { + var cookie *http.Cookie + var err error + cookie, err = gc.Request.Cookie(constants.MfaCookieName + "_session") + if err != nil { + cookie, err = gc.Request.Cookie(constants.MfaCookieName + "_session_domain") + if err != nil { + return "", err + } + } + + decodedValue, err := url.PathUnescape(cookie.Value) + if err != nil { + return "", err + } + return decodedValue, nil +} diff --git a/server/db/models/model.go b/server/db/models/model.go index a0d5763..5061c41 100644 --- a/server/db/models/model.go +++ b/server/db/models/model.go @@ -2,14 +2,14 @@ package models // Collections / Tables available for authorizer in the database type CollectionList struct { - User string - VerificationRequest string - Session string - Env string - Webhook string - WebhookLog string - EmailTemplate string - OTP string + User string + VerificationRequest string + Session string + Env string + Webhook string + WebhookLog string + EmailTemplate string + OTP string SMSVerificationRequest string } @@ -18,14 +18,14 @@ var ( Prefix = "authorizer_" // Collections / Tables available for authorizer in the database (used for dbs other than gorm) Collections = CollectionList{ - User: Prefix + "users", - VerificationRequest: Prefix + "verification_requests", - Session: Prefix + "sessions", - Env: Prefix + "env", - Webhook: Prefix + "webhooks", - WebhookLog: Prefix + "webhook_logs", - EmailTemplate: Prefix + "email_templates", - OTP: Prefix + "otps", - SMSVerificationRequest: Prefix + "sms_verification_requests", + User: Prefix + "users", + VerificationRequest: Prefix + "verification_requests", + Session: Prefix + "sessions", + Env: Prefix + "env", + Webhook: Prefix + "webhooks", + WebhookLog: Prefix + "webhook_logs", + EmailTemplate: Prefix + "email_templates", + OTP: Prefix + "otps", + SMSVerificationRequest: Prefix + "sms_verification_requests", } ) diff --git a/server/db/models/otp.go b/server/db/models/otp.go index ac9732b..bd0b41c 100644 --- a/server/db/models/otp.go +++ b/server/db/models/otp.go @@ -1,14 +1,22 @@ package models +const ( + // FieldName email is the field name for email + FieldNameEmail = "email" + // FieldNamePhoneNumber is the field name for phone number + FieldNamePhoneNumber = "phone_number" +) + // OTP model for database type OTP 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"` - Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"` - Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"` - ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_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"` + 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"` + Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"` + PhoneNumber string `gorm:"index:unique_index_phone_number,unique" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number"` + Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"` + ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_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"` } type Paging struct { diff --git a/server/db/models/sms_verification_requests.go b/server/db/models/sms_verification_requests.go deleted file mode 100644 index 2a70d5e..0000000 --- a/server/db/models/sms_verification_requests.go +++ /dev/null @@ -1,11 +0,0 @@ -package models - -// SMS verification requests model for database -type SMSVerificationRequest struct { - ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` - PhoneNumber string `gorm:"unique" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number" index:"phone_number,hash"` - Code string `json:"code" bson:"code" cql:"code" dynamo:"code"` - CodeExpiresAt int64 `json:"code_expires_at" bson:"code_expires_at" cql:"code_expires_at" dynamo:"code_expires_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"` -} diff --git a/server/db/models/user.go b/server/db/models/user.go index 4628359..a262823 100644 --- a/server/db/models/user.go +++ b/server/db/models/user.go @@ -33,12 +33,14 @@ type User struct { IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled" bson:"is_multi_factor_auth_enabled" cql:"is_multi_factor_auth_enabled" dynamo:"is_multi_factor_auth_enabled"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` + AppData *string `json:"app_data" bson:"app_data" cql:"app_data" dynamo:"app_data"` } func (user *User) AsAPIUser() *model.User { isEmailVerified := user.EmailVerifiedAt != nil isPhoneVerified := user.PhoneNumberVerifiedAt != nil - + appDataMap := make(map[string]interface{}) + json.Unmarshal([]byte(refs.StringValue(user.AppData)), &appDataMap) // id := user.ID // if strings.Contains(id, Collections.User+"/") { // id = strings.TrimPrefix(id, Collections.User+"/") @@ -63,6 +65,7 @@ func (user *User) AsAPIUser() *model.User { IsMultiFactorAuthEnabled: user.IsMultiFactorAuthEnabled, CreatedAt: refs.NewInt64Ref(user.CreatedAt), UpdatedAt: refs.NewInt64Ref(user.UpdatedAt), + AppData: appDataMap, } } diff --git a/server/db/providers/arangodb/email_template.go b/server/db/providers/arangodb/email_template.go index 8134cbe..30c0fd0 100644 --- a/server/db/providers/arangodb/email_template.go +++ b/server/db/providers/arangodb/email_template.go @@ -12,16 +12,14 @@ import ( ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() emailTemplate.Key = emailTemplate.ID } - emailTemplate.Key = emailTemplate.ID emailTemplate.CreatedAt = time.Now().Unix() emailTemplate.UpdatedAt = time.Now().Unix() - emailTemplateCollection, _ := p.db.Collection(ctx, models.Collections.EmailTemplate) _, err := emailTemplateCollection.CreateDocument(ctx, emailTemplate) if err != nil { @@ -31,74 +29,63 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { emailTemplate.UpdatedAt = time.Now().Unix() - emailTemplateCollection, _ := p.db.Collection(ctx, models.Collections.EmailTemplate) meta, err := emailTemplateCollection.UpdateDocument(ctx, emailTemplate.Key, emailTemplate) if err != nil { return nil, err } - emailTemplate.Key = meta.Key emailTemplate.ID = meta.ID.String() return emailTemplate.AsAPIEmailTemplate(), nil } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) { +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { emailTemplates := []*model.EmailTemplate{} - query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.EmailTemplate, pagination.Offset, pagination.Limit) - sctx := arangoDriver.WithQueryFullCount(ctx) cursor, err := p.db.Query(sctx, query, nil) if err != nil { return nil, err } defer cursor.Close() - paginationClone := pagination paginationClone.Total = cursor.Statistics().FullCount() - for { - var emailTemplate models.EmailTemplate + var emailTemplate *models.EmailTemplate meta, err := cursor.ReadDocument(ctx, &emailTemplate) - if arangoDriver.IsNoMoreDocuments(err) { break } else if err != nil { return nil, err } - if meta.Key != "" { emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate()) } } - return &model.EmailTemplates{ - Pagination: &paginationClone, + Pagination: paginationClone, EmailTemplates: emailTemplates, }, nil } // GetEmailTemplateByID to get EmailTemplate by id func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { - var emailTemplate models.EmailTemplate + var emailTemplate *models.EmailTemplate query := fmt.Sprintf("FOR d in %s FILTER d._key == @email_template_id RETURN d", models.Collections.EmailTemplate) bindVars := map[string]interface{}{ "email_template_id": emailTemplateID, } - cursor, err := p.db.Query(ctx, query, bindVars) if err != nil { return nil, err } defer cursor.Close() - for { if !cursor.HasMore() { - if emailTemplate.Key == "" { + if emailTemplate == nil { return nil, fmt.Errorf("email template not found") } break @@ -113,21 +100,19 @@ func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID str // GetEmailTemplateByEventName to get EmailTemplate by event_name func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { - var emailTemplate models.EmailTemplate + var emailTemplate *models.EmailTemplate query := fmt.Sprintf("FOR d in %s FILTER d.event_name == @event_name RETURN d", models.Collections.EmailTemplate) bindVars := map[string]interface{}{ "event_name": eventName, } - cursor, err := p.db.Query(ctx, query, bindVars) if err != nil { return nil, err } defer cursor.Close() - for { if !cursor.HasMore() { - if emailTemplate.Key == "" { + if emailTemplate == nil { return nil, fmt.Errorf("email template not found") } break diff --git a/server/db/providers/arangodb/env.go b/server/db/providers/arangodb/env.go index 29687a8..bb4610a 100644 --- a/server/db/providers/arangodb/env.go +++ b/server/db/providers/arangodb/env.go @@ -12,7 +12,7 @@ import ( ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { if env.ID == "" { env.ID = uuid.New().String() env.Key = env.ID @@ -31,7 +31,7 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro } // UpdateEnv to update environment information in database -func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) { env.UpdatedAt = time.Now().Unix() collection, _ := p.db.Collection(ctx, models.Collections.Env) meta, err := collection.UpdateDocument(ctx, env.Key, env) @@ -45,19 +45,17 @@ func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, e } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (models.Env, error) { - var env models.Env +func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { + var env *models.Env query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.Env) - cursor, err := p.db.Query(ctx, query, nil) if err != nil { return env, err } defer cursor.Close() - for { if !cursor.HasMore() { - if env.Key == "" { + if env == nil { return env, fmt.Errorf("config not found") } break diff --git a/server/db/providers/arangodb/otp.go b/server/db/providers/arangodb/otp.go index 29f265a..3f8f464 100644 --- a/server/db/providers/arangodb/otp.go +++ b/server/db/providers/arangodb/otp.go @@ -2,6 +2,7 @@ package arangodb import ( "context" + "errors" "fmt" "time" @@ -12,27 +13,39 @@ import ( // UpsertOTP to add or update otp func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { - otp, _ := p.GetOTPByEmail(ctx, otpParam.Email) + // check if email or phone number is present + if otpParam.Email == "" && otpParam.PhoneNumber == "" { + return nil, errors.New("email or phone_number is required") + } + uniqueField := models.FieldNameEmail + if otpParam.Email == "" && otpParam.PhoneNumber != "" { + uniqueField = models.FieldNamePhoneNumber + } + var otp *models.OTP + if uniqueField == models.FieldNameEmail { + otp, _ = p.GetOTPByEmail(ctx, otpParam.Email) + } else { + otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber) + } shouldCreate := false if otp == nil { id := uuid.NewString() otp = &models.OTP{ - ID: id, - Key: id, - Otp: otpParam.Otp, - Email: otpParam.Email, - ExpiresAt: otpParam.ExpiresAt, - CreatedAt: time.Now().Unix(), + ID: id, + Key: id, + Otp: otpParam.Otp, + Email: otpParam.Email, + PhoneNumber: otpParam.PhoneNumber, + ExpiresAt: otpParam.ExpiresAt, + CreatedAt: time.Now().Unix(), } shouldCreate = true } else { otp.Otp = otpParam.Otp otp.ExpiresAt = otpParam.ExpiresAt } - otp.UpdatedAt = time.Now().Unix() otpCollection, _ := p.db.Collection(ctx, models.Collections.OTP) - var meta driver.DocumentMeta var err error if shouldCreate { @@ -40,11 +53,9 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models } else { meta, err = otpCollection.UpdateDocument(ctx, otp.Key, otp) } - if err != nil { return nil, err } - otp.Key = meta.Key otp.ID = meta.ID.String() return otp, nil @@ -52,22 +63,20 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models // GetOTPByEmail to get otp for a given email address func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { - var otp models.OTP + var otp *models.OTP query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.OTP) bindVars := map[string]interface{}{ "email": emailAddress, } - cursor, err := p.db.Query(ctx, query, bindVars) if err != nil { return nil, err } defer cursor.Close() - for { if !cursor.HasMore() { - if otp.Key == "" { - return nil, fmt.Errorf("email template not found") + if otp == nil { + return nil, fmt.Errorf("otp with given email not found") } break } @@ -76,8 +85,34 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod return nil, err } } + return otp, nil +} - return &otp, nil +// GetOTPByPhoneNumber to get otp for a given phone number +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { + var otp *models.OTP + query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.OTP) + bindVars := map[string]interface{}{ + "phone_number": phoneNumber, + } + cursor, err := p.db.Query(ctx, query, bindVars) + if err != nil { + return nil, err + } + defer cursor.Close() + for { + if !cursor.HasMore() { + if otp == nil { + return nil, fmt.Errorf("otp with given phone_number not found") + } + break + } + _, err := cursor.ReadDocument(ctx, &otp) + if err != nil { + return nil, err + } + } + return otp, nil } // DeleteOTP to delete otp @@ -87,6 +122,5 @@ func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { if err != nil { return err } - return nil } diff --git a/server/db/providers/arangodb/provider.go b/server/db/providers/arangodb/provider.go index 5488428..507a938 100644 --- a/server/db/providers/arangodb/provider.go +++ b/server/db/providers/arangodb/provider.go @@ -61,7 +61,6 @@ func NewProvider() (*provider, error) { if err != nil { return nil, err } - var arangodb arangoDriver.Database dbName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName arangodb_exists, err := arangoClient.DatabaseExists(ctx, dbName) @@ -79,7 +78,6 @@ func NewProvider() (*provider, error) { return nil, err } } - userCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.User) if err != nil { return nil, err @@ -113,7 +111,6 @@ func NewProvider() (*provider, error) { return nil, err } } - verificationRequestCollection, err := arangodb.Collection(ctx, models.Collections.VerificationRequest) if err != nil { return nil, err @@ -136,7 +133,6 @@ func NewProvider() (*provider, error) { return nil, err } } - sessionCollection, err := arangodb.Collection(ctx, models.Collections.Session) if err != nil { return nil, err @@ -144,7 +140,6 @@ func NewProvider() (*provider, error) { sessionCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{ Sparse: true, }) - envCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Env) if err != nil { return nil, err @@ -155,7 +150,6 @@ func NewProvider() (*provider, error) { return nil, err } } - webhookCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Webhook) if err != nil { return nil, err @@ -166,7 +160,6 @@ func NewProvider() (*provider, error) { return nil, err } } - webhookCollection, err := arangodb.Collection(ctx, models.Collections.Webhook) if err != nil { return nil, err @@ -186,7 +179,6 @@ func NewProvider() (*provider, error) { return nil, err } } - webhookLogCollection, err := arangodb.Collection(ctx, models.Collections.WebhookLog) if err != nil { return nil, err @@ -194,7 +186,6 @@ func NewProvider() (*provider, error) { webhookLogCollection.EnsureHashIndex(ctx, []string{"webhook_id"}, &arangoDriver.EnsureHashIndexOptions{ Sparse: true, }) - emailTemplateCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.EmailTemplate) if err != nil { return nil, err @@ -205,7 +196,6 @@ func NewProvider() (*provider, error) { return nil, err } } - emailTemplateCollection, err := arangodb.Collection(ctx, models.Collections.EmailTemplate) if err != nil { return nil, err @@ -214,7 +204,6 @@ func NewProvider() (*provider, error) { Unique: true, Sparse: true, }) - otpCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.OTP) if err != nil { return nil, err @@ -225,16 +214,14 @@ func NewProvider() (*provider, error) { return nil, err } } - otpCollection, err := arangodb.Collection(ctx, models.Collections.OTP) if err != nil { return nil, err } - otpCollection.EnsureHashIndex(ctx, []string{"email"}, &arangoDriver.EnsureHashIndexOptions{ + otpCollection.EnsureHashIndex(ctx, []string{models.FieldNameEmail, models.FieldNamePhoneNumber}, &arangoDriver.EnsureHashIndexOptions{ Unique: true, Sparse: true, }) - return &provider{ db: arangodb, }, err diff --git a/server/db/providers/arangodb/session.go b/server/db/providers/arangodb/session.go index 9bc46ca..5dc981d 100644 --- a/server/db/providers/arangodb/session.go +++ b/server/db/providers/arangodb/session.go @@ -9,12 +9,11 @@ import ( ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *models.Session) error { if session.ID == "" { session.ID = uuid.New().String() session.Key = session.ID } - session.CreatedAt = time.Now().Unix() session.UpdatedAt = time.Now().Unix() sessionCollection, _ := p.db.Collection(ctx, models.Collections.Session) @@ -24,3 +23,8 @@ func (p *provider) AddSession(ctx context.Context, session models.Session) error } return nil } + +// DeleteSession to delete session information from database +func (p *provider) DeleteSession(ctx context.Context, userId string) error { + return nil +} diff --git a/server/db/providers/arangodb/sms_verification_requests.go b/server/db/providers/arangodb/sms_verification_requests.go deleted file mode 100644 index 4dee5bd..0000000 --- a/server/db/providers/arangodb/sms_verification_requests.go +++ /dev/null @@ -1,23 +0,0 @@ -package arangodb - -import ( - "context" - - "github.com/authorizerdev/authorizer/server/db/models" - -) - -// SMS verification Request -func (p *provider) UpsertSMSRequest(ctx context.Context, sms_code *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) { - return sms_code, nil -} - -func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) { - var sms_verification_request models.SMSVerificationRequest - - return &sms_verification_request, nil -} - -func(p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error { - return nil -} diff --git a/server/db/providers/arangodb/user.go b/server/db/providers/arangodb/user.go index cccbf94..926cdb9 100644 --- a/server/db/providers/arangodb/user.go +++ b/server/db/providers/arangodb/user.go @@ -18,7 +18,7 @@ import ( ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { if user.ID == "" { user.ID = uuid.New().String() user.Key = user.ID @@ -52,7 +52,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, } // 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() collection, _ := p.db.Collection(ctx, models.Collections.User) @@ -67,13 +67,12 @@ func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.Use } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user models.User) error { +func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { collection, _ := p.db.Collection(ctx, models.Collections.User) _, err := collection.RemoveDocument(ctx, user.Key) if err != nil { return err } - query := fmt.Sprintf(`FOR d IN %s FILTER d.user_id == @user_id REMOVE { _key: d._key } IN %s`, models.Collections.Session, models.Collections.Session) bindVars := map[string]interface{}{ "user_id": user.Key, @@ -83,65 +82,55 @@ func (p *provider) DeleteUser(ctx context.Context, user models.User) error { return err } defer cursor.Close() - return nil } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) { +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { var users []*model.User sctx := arangoDriver.WithQueryFullCount(ctx) query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.User, pagination.Offset, pagination.Limit) - cursor, err := p.db.Query(sctx, query, nil) if err != nil { return nil, err } defer cursor.Close() - paginationClone := pagination paginationClone.Total = cursor.Statistics().FullCount() - for { - var user models.User + var user *models.User meta, err := cursor.ReadDocument(ctx, &user) - if arangoDriver.IsNoMoreDocuments(err) { break } else if err != nil { return nil, err } - if meta.Key != "" { users = append(users, user.AsAPIUser()) } } - return &model.Users{ - Pagination: &paginationClone, + Pagination: paginationClone, Users: users, }, nil } // GetUserByEmail to get user information from database using email address -func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) { - var user models.User - +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) { + var user *models.User query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.User) bindVars := map[string]interface{}{ "email": email, } - cursor, err := p.db.Query(ctx, query, bindVars) if err != nil { return user, err } defer cursor.Close() - for { if !cursor.HasMore() { - if user.Key == "" { + if user == nil { return user, fmt.Errorf("user not found") } break @@ -151,28 +140,24 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.Use return user, err } } - return user, nil } // GetUserByID to get user information from database using user ID -func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) { - var user models.User - +func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) { + var user *models.User query := fmt.Sprintf("FOR d in %s FILTER d._id == @id LIMIT 1 RETURN d", models.Collections.User) bindVars := map[string]interface{}{ "id": id, } - cursor, err := p.db.Query(ctx, query, bindVars) if err != nil { return user, err } defer cursor.Close() - for { if !cursor.HasMore() { - if user.Key == "" { + if user == nil { return user, fmt.Errorf("user not found") } break @@ -182,7 +167,6 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, err return user, err } } - return user, nil } @@ -191,12 +175,10 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, err func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error { // set updated_at time for all users data["updated_at"] = time.Now().Unix() - userInfoBytes, err := json.Marshal(data) if err != nil { return err } - query := "" if len(ids) > 0 { keysArray := "" @@ -209,33 +191,28 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } else { query = fmt.Sprintf("FOR u IN %s UPDATE u._key with %s IN %s", models.Collections.User, string(userInfoBytes), models.Collections.User) } - _, err = p.db.Query(ctx, query, nil) if err != nil { return err } - return nil } // GetUserByPhoneNumber to get user information from database using phone number func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) { - var user models.User - + var user *models.User query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.User) bindVars := map[string]interface{}{ "phone_number": phoneNumber, } - cursor, err := p.db.Query(ctx, query, bindVars) if err != nil { return nil, err } defer cursor.Close() - for { if !cursor.HasMore() { - if user.Key == "" { + if user == nil { return nil, fmt.Errorf("user not found") } break @@ -245,6 +222,5 @@ func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) return nil, err } } - - return &user, nil + return user, nil } diff --git a/server/db/providers/arangodb/verification_requests.go b/server/db/providers/arangodb/verification_requests.go index f69bcb0..05a8186 100644 --- a/server/db/providers/arangodb/verification_requests.go +++ b/server/db/providers/arangodb/verification_requests.go @@ -12,12 +12,11 @@ import ( ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() verificationRequest.Key = verificationRequest.ID } - verificationRequest.CreatedAt = time.Now().Unix() verificationRequest.UpdatedAt = time.Now().Unix() verificationRequestRequestCollection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest) @@ -27,27 +26,24 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque } verificationRequest.Key = meta.Key verificationRequest.ID = meta.ID.String() - return verificationRequest, nil } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { + var verificationRequest *models.VerificationRequest query := fmt.Sprintf("FOR d in %s FILTER d.token == @token LIMIT 1 RETURN d", models.Collections.VerificationRequest) bindVars := map[string]interface{}{ "token": token, } - cursor, err := p.db.Query(ctx, query, bindVars) if err != nil { return verificationRequest, err } defer cursor.Close() - for { if !cursor.HasMore() { - if verificationRequest.Key == "" { + if verificationRequest == nil { return verificationRequest, fmt.Errorf("verification request not found") } break @@ -57,29 +53,25 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri return verificationRequest, err } } - return verificationRequest, nil } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest - +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { + var verificationRequest *models.VerificationRequest query := fmt.Sprintf("FOR d in %s FILTER d.email == @email FILTER d.identifier == @identifier LIMIT 1 RETURN d", models.Collections.VerificationRequest) bindVars := map[string]interface{}{ "email": email, "identifier": identifier, } - cursor, err := p.db.Query(ctx, query, bindVars) if err != nil { return verificationRequest, err } defer cursor.Close() - for { if !cursor.HasMore() { - if verificationRequest.Key == "" { + if verificationRequest == nil { return verificationRequest, fmt.Errorf("verification request not found") } break @@ -89,27 +81,23 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri return verificationRequest, err } } - return verificationRequest, nil } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) { +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { var verificationRequests []*model.VerificationRequest sctx := arangoDriver.WithQueryFullCount(ctx) query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.VerificationRequest, pagination.Offset, pagination.Limit) - cursor, err := p.db.Query(sctx, query, nil) if err != nil { return nil, err } defer cursor.Close() - paginationClone := pagination paginationClone.Total = cursor.Statistics().FullCount() - for { - var verificationRequest models.VerificationRequest + var verificationRequest *models.VerificationRequest meta, err := cursor.ReadDocument(ctx, &verificationRequest) if arangoDriver.IsNoMoreDocuments(err) { @@ -123,15 +111,14 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode } } - return &model.VerificationRequests{ VerificationRequests: verificationRequests, - Pagination: &paginationClone, + Pagination: paginationClone, }, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error { +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { collection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest) _, err := collection.RemoveDocument(ctx, verificationRequest.Key) if err != nil { diff --git a/server/db/providers/arangodb/webhook.go b/server/db/providers/arangodb/webhook.go index 73cefad..dbdc9e4 100644 --- a/server/db/providers/arangodb/webhook.go +++ b/server/db/providers/arangodb/webhook.go @@ -14,7 +14,7 @@ import ( ) // AddWebhook to add webhook -func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() webhook.Key = webhook.ID @@ -33,7 +33,7 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod } // UpdateWebhook to update webhook -func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { webhook.UpdatedAt = time.Now().Unix() // Event is changed if !strings.Contains(webhook.EventName, "-") { @@ -50,11 +50,9 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (* } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) { +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { webhooks := []*model.Webhook{} - query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.Webhook, pagination.Offset, pagination.Limit) - sctx := arangoDriver.WithQueryFullCount(ctx) cursor, err := p.db.Query(sctx, query, nil) if err != nil { @@ -64,9 +62,8 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) paginationClone := pagination paginationClone.Total = cursor.Statistics().FullCount() for { - var webhook models.Webhook + var webhook *models.Webhook meta, err := cursor.ReadDocument(ctx, &webhook) - if arangoDriver.IsNoMoreDocuments(err) { break } else if err != nil { @@ -79,14 +76,14 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) } return &model.Webhooks{ - Pagination: &paginationClone, + Pagination: paginationClone, Webhooks: webhooks, }, nil } // GetWebhookByID to get webhook by id func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) { - var webhook models.Webhook + var webhook *models.Webhook query := fmt.Sprintf("FOR d in %s FILTER d._key == @webhook_id RETURN d", models.Collections.Webhook) bindVars := map[string]interface{}{ "webhook_id": webhookID, @@ -98,7 +95,7 @@ func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model defer cursor.Close() for { if !cursor.HasMore() { - if webhook.Key == "" { + if webhook == nil { return nil, fmt.Errorf("webhook not found") } break @@ -124,7 +121,7 @@ func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) defer cursor.Close() webhooks := []*model.Webhook{} for { - var webhook models.Webhook + var webhook *models.Webhook if _, err := cursor.ReadDocument(ctx, &webhook); driver.IsNoMoreDocuments(err) { // We're done break diff --git a/server/db/providers/arangodb/webhook_log.go b/server/db/providers/arangodb/webhook_log.go index 42de751..64db2cb 100644 --- a/server/db/providers/arangodb/webhook_log.go +++ b/server/db/providers/arangodb/webhook_log.go @@ -12,12 +12,11 @@ import ( ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() webhookLog.Key = webhookLog.ID } - webhookLog.Key = webhookLog.ID webhookLog.CreatedAt = time.Now().Unix() webhookLog.UpdatedAt = time.Now().Unix() @@ -30,46 +29,38 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookL } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) { +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { webhookLogs := []*model.WebhookLog{} bindVariables := map[string]interface{}{} - query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.WebhookLog, pagination.Offset, pagination.Limit) - if webhookID != "" { query = fmt.Sprintf("FOR d in %s FILTER d.webhook_id == @webhook_id SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.WebhookLog, pagination.Offset, pagination.Limit) bindVariables = map[string]interface{}{ "webhook_id": webhookID, } } - sctx := arangoDriver.WithQueryFullCount(ctx) cursor, err := p.db.Query(sctx, query, bindVariables) if err != nil { return nil, err } defer cursor.Close() - paginationClone := pagination paginationClone.Total = cursor.Statistics().FullCount() - for { - var webhookLog models.WebhookLog + var webhookLog *models.WebhookLog meta, err := cursor.ReadDocument(ctx, &webhookLog) - if arangoDriver.IsNoMoreDocuments(err) { break } else if err != nil { return nil, err } - if meta.Key != "" { webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog()) } } - return &model.WebhookLogs{ - Pagination: &paginationClone, + Pagination: paginationClone, WebhookLogs: webhookLogs, }, nil } diff --git a/server/db/providers/cassandradb/email_template.go b/server/db/providers/cassandradb/email_template.go index 7cb64cb..9adb768 100644 --- a/server/db/providers/cassandradb/email_template.go +++ b/server/db/providers/cassandradb/email_template.go @@ -15,33 +15,28 @@ import ( ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() } - emailTemplate.Key = emailTemplate.ID emailTemplate.CreatedAt = time.Now().Unix() emailTemplate.UpdatedAt = time.Now().Unix() - existingEmailTemplate, _ := p.GetEmailTemplateByEventName(ctx, emailTemplate.EventName) if existingEmailTemplate != nil { return nil, fmt.Errorf("Email template with %s event_name already exists", emailTemplate.EventName) } - insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_name, subject, design, template, created_at, updated_at) VALUES ('%s', '%s', '%s','%s','%s', %d, %d)", KeySpace+"."+models.Collections.EmailTemplate, emailTemplate.ID, emailTemplate.EventName, emailTemplate.Subject, emailTemplate.Design, emailTemplate.Template, emailTemplate.CreatedAt, emailTemplate.UpdatedAt) err := p.db.Query(insertQuery).Exec() if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { emailTemplate.UpdatedAt = time.Now().Unix() - bytes, err := json.Marshal(emailTemplate) if err != nil { return nil, err @@ -54,22 +49,18 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models if err != nil { return nil, err } - updateFields := "" for key, value := range emailTemplateMap { 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)) @@ -90,7 +81,7 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) { +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { emailTemplates := []*model.EmailTemplate{} paginationClone := pagination @@ -120,7 +111,7 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin } return &model.EmailTemplates{ - Pagination: &paginationClone, + Pagination: paginationClone, EmailTemplates: emailTemplates, }, nil } diff --git a/server/db/providers/cassandradb/env.go b/server/db/providers/cassandradb/env.go index 384b539..636f9f4 100644 --- a/server/db/providers/cassandradb/env.go +++ b/server/db/providers/cassandradb/env.go @@ -11,11 +11,10 @@ import ( ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { if env.ID == "" { env.ID = uuid.New().String() } - env.CreatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix() insertEnvQuery := fmt.Sprintf("INSERT INTO %s (id, env, hash, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.Env, env.ID, env.EnvData, env.Hash, env.CreatedAt, env.UpdatedAt) @@ -28,9 +27,8 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro } // UpdateEnv to update environment information in database -func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) { env.UpdatedAt = time.Now().Unix() - updateEnvQuery := fmt.Sprintf("UPDATE %s SET env = '%s', updated_at = %d WHERE id = '%s'", KeySpace+"."+models.Collections.Env, env.EnvData, env.UpdatedAt, env.ID) err := p.db.Query(updateEnvQuery).Exec() if err != nil { @@ -40,14 +38,12 @@ func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, e } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (models.Env, error) { +func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { var env models.Env - query := fmt.Sprintf("SELECT id, env, hash, created_at, updated_at FROM %s LIMIT 1", KeySpace+"."+models.Collections.Env) err := p.db.Query(query).Consistency(gocql.One).Scan(&env.ID, &env.EnvData, &env.Hash, &env.CreatedAt, &env.UpdatedAt) if err != nil { - return env, err + return nil, err } - - return env, nil + return &env, nil } diff --git a/server/db/providers/cassandradb/otp.go b/server/db/providers/cassandradb/otp.go index bfe481d..e453242 100644 --- a/server/db/providers/cassandradb/otp.go +++ b/server/db/providers/cassandradb/otp.go @@ -2,6 +2,7 @@ package cassandradb import ( "context" + "errors" "fmt" "time" @@ -12,17 +13,31 @@ import ( // UpsertOTP to add or update otp func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { - otp, _ := p.GetOTPByEmail(ctx, otpParam.Email) + // check if email or phone number is present + if otpParam.Email == "" && otpParam.PhoneNumber == "" { + return nil, errors.New("email or phone_number is required") + } + uniqueField := models.FieldNameEmail + if otpParam.Email == "" && otpParam.PhoneNumber != "" { + uniqueField = models.FieldNamePhoneNumber + } + var otp *models.OTP + if uniqueField == models.FieldNameEmail { + otp, _ = p.GetOTPByEmail(ctx, otpParam.Email) + } else { + otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber) + } shouldCreate := false if otp == nil { shouldCreate = true otp = &models.OTP{ - ID: uuid.NewString(), - Otp: otpParam.Otp, - Email: otpParam.Email, - ExpiresAt: otpParam.ExpiresAt, - CreatedAt: time.Now().Unix(), - UpdatedAt: time.Now().Unix(), + ID: uuid.NewString(), + Otp: otpParam.Otp, + Email: otpParam.Email, + PhoneNumber: otpParam.PhoneNumber, + ExpiresAt: otpParam.ExpiresAt, + CreatedAt: time.Now().Unix(), + UpdatedAt: time.Now().Unix(), } } else { otp.Otp = otpParam.Otp @@ -32,7 +47,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models otp.UpdatedAt = time.Now().Unix() query := "" if shouldCreate { - query = fmt.Sprintf(`INSERT INTO %s (id, email, otp, expires_at, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d, %d)`, KeySpace+"."+models.Collections.OTP, otp.ID, otp.Email, otp.Otp, otp.ExpiresAt, otp.CreatedAt, otp.UpdatedAt) + query = fmt.Sprintf(`INSERT INTO %s (id, email, phone_number, otp, expires_at, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)`, KeySpace+"."+models.Collections.OTP, otp.ID, otp.Email, otp.PhoneNumber, otp.Otp, otp.ExpiresAt, otp.CreatedAt, otp.UpdatedAt) } else { query = fmt.Sprintf(`UPDATE %s SET otp = '%s', expires_at = %d, updated_at = %d WHERE id = '%s'`, KeySpace+"."+models.Collections.OTP, otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID) } @@ -48,8 +63,19 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models // GetOTPByEmail to get otp for a given email address func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { var otp models.OTP - query := fmt.Sprintf(`SELECT id, email, otp, expires_at, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.OTP, emailAddress) - err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt) + query := fmt.Sprintf(`SELECT id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.OTP, emailAddress) + err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.PhoneNumber, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt) + if err != nil { + return nil, err + } + return &otp, nil +} + +// GetOTPByPhoneNumber to get otp for a given phone number +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { + var otp models.OTP + query := fmt.Sprintf(`SELECT id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.OTP, phoneNumber) + err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.PhoneNumber, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt) if err != nil { return nil, err } diff --git a/server/db/providers/cassandradb/provider.go b/server/db/providers/cassandradb/provider.go index 1d8fa49..6f1fe6b 100644 --- a/server/db/providers/cassandradb/provider.go +++ b/server/db/providers/cassandradb/provider.go @@ -254,7 +254,19 @@ func NewProvider() (*provider, error) { if err != nil { return nil, err } - + // Add phone_number column to otp table + otpAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (phone_number text);`, KeySpace, models.Collections.OTP) + err = session.Query(otpAlterQuery).Exec() + if err != nil { + log.Debug("Failed to alter table as column exists: ", err) + // continue + } + // Add phone number index + otpIndexQueryPhoneNumber := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_otp_phone_number ON %s.%s (phone_number)", KeySpace, models.Collections.OTP) + err = session.Query(otpIndexQueryPhoneNumber).Exec() + if err != nil { + return nil, err + } return &provider{ db: session, }, err diff --git a/server/db/providers/cassandradb/session.go b/server/db/providers/cassandradb/session.go index e6042ea..bdf205c 100644 --- a/server/db/providers/cassandradb/session.go +++ b/server/db/providers/cassandradb/session.go @@ -10,14 +10,12 @@ import ( ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *models.Session) error { if session.ID == "" { session.ID = uuid.New().String() } - session.CreatedAt = time.Now().Unix() session.UpdatedAt = time.Now().Unix() - insertSessionQuery := fmt.Sprintf("INSERT INTO %s (id, user_id, user_agent, ip, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.Session, session.ID, session.UserID, session.UserAgent, session.IP, session.CreatedAt, session.UpdatedAt) err := p.db.Query(insertSessionQuery).Exec() if err != nil { @@ -25,3 +23,8 @@ func (p *provider) AddSession(ctx context.Context, session models.Session) error } return nil } + +// DeleteSession to delete session information from database +func (p *provider) DeleteSession(ctx context.Context, userId string) error { + return nil +} diff --git a/server/db/providers/cassandradb/sms_verification_requests.go b/server/db/providers/cassandradb/sms_verification_requests.go deleted file mode 100644 index 3c67c1b..0000000 --- a/server/db/providers/cassandradb/sms_verification_requests.go +++ /dev/null @@ -1,23 +0,0 @@ -package cassandradb - -import ( - "context" - - "github.com/authorizerdev/authorizer/server/db/models" - -) - -// SMS verification Request -func (p *provider) UpsertSMSRequest(ctx context.Context, sms_code *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) { - return sms_code, nil -} - -func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) { - var sms_verification_request models.SMSVerificationRequest - - return &sms_verification_request, nil -} - -func(p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error { - return nil -} diff --git a/server/db/providers/cassandradb/user.go b/server/db/providers/cassandradb/user.go index f8be709..376a6db 100644 --- a/server/db/providers/cassandradb/user.go +++ b/server/db/providers/cassandradb/user.go @@ -18,7 +18,7 @@ import ( ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { if user.ID == "" { user.ID = uuid.New().String() } @@ -77,7 +77,6 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, values = values[:len(values)-1] + ")" query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.User, fields, values) - err = p.db.Query(query).Exec() if err != nil { return user, err @@ -87,7 +86,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, } // 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() bytes, err := json.Marshal(user) @@ -138,13 +137,12 @@ func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.Use } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user models.User) error { +func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, user.ID) err := p.db.Query(query).Exec() if err != nil { return err } - getSessionsQuery := fmt.Sprintf("SELECT id FROM %s WHERE user_id = '%s' ALLOW FILTERING", KeySpace+"."+models.Collections.Session, user.ID) scanner := p.db.Query(getSessionsQuery).Iter().Scanner() sessionIDs := "" @@ -167,7 +165,7 @@ func (p *provider) DeleteUser(ctx context.Context, user models.User) error { } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) { +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { responseUsers := []*model.User{} paginationClone := pagination totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.User) @@ -180,7 +178,6 @@ func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) ( // so we fetch till limit + offset // 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, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.User, pagination.Limit+pagination.Offset) - scanner := p.db.Query(query).Iter().Scanner() counter := int64(0) for scanner.Next() { @@ -195,31 +192,31 @@ func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) ( counter++ } return &model.Users{ + Pagination: paginationClone, Users: responseUsers, - Pagination: &paginationClone, }, nil } // GetUserByEmail to get user information from database using email address -func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) { +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) { var user models.User 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, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, email) err := p.db.Query(query).Consistency(gocql.One).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.CreatedAt, &user.UpdatedAt) if err != nil { - return user, err + return nil, err } - return user, nil + return &user, nil } // GetUserByID to get user information from database using user ID -func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) { +func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) { var user models.User 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, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1", KeySpace+"."+models.Collections.User, id) err := p.db.Query(query).Consistency(gocql.One).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.CreatedAt, &user.UpdatedAt) if err != nil { - return user, err + return nil, err } - return user, nil + return &user, nil } // UpdateUsers to update multiple users, with parameters of user IDs slice @@ -252,9 +249,8 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } updateFields = strings.Trim(updateFields, " ") updateFields = strings.TrimSuffix(updateFields, ",") - query := "" - if ids != nil && len(ids) > 0 { + if len(ids) > 0 { idsString := "" for _, id := range ids { idsString += fmt.Sprintf("'%s', ", id) diff --git a/server/db/providers/cassandradb/verification_requests.go b/server/db/providers/cassandradb/verification_requests.go index 3786a2b..aa8e66d 100644 --- a/server/db/providers/cassandradb/verification_requests.go +++ b/server/db/providers/cassandradb/verification_requests.go @@ -12,7 +12,7 @@ import ( ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() } @@ -29,41 +29,39 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) { +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { var verificationRequest models.VerificationRequest query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE jwt_token = '%s' LIMIT 1`, KeySpace+"."+models.Collections.VerificationRequest, token) err := p.db.Query(query).Consistency(gocql.One).Scan(&verificationRequest.ID, &verificationRequest.Token, &verificationRequest.Identifier, &verificationRequest.ExpiresAt, &verificationRequest.Email, &verificationRequest.Nonce, &verificationRequest.RedirectURI, &verificationRequest.CreatedAt, &verificationRequest.UpdatedAt) if err != nil { - return verificationRequest, err + return nil, err } - return verificationRequest, nil + return &verificationRequest, nil } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) { +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { var verificationRequest models.VerificationRequest query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE email = '%s' AND identifier = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.VerificationRequest, email, identifier) err := p.db.Query(query).Consistency(gocql.One).Scan(&verificationRequest.ID, &verificationRequest.Token, &verificationRequest.Identifier, &verificationRequest.ExpiresAt, &verificationRequest.Email, &verificationRequest.Nonce, &verificationRequest.RedirectURI, &verificationRequest.CreatedAt, &verificationRequest.UpdatedAt) if err != nil { - return verificationRequest, err + return nil, err } - return verificationRequest, nil + return &verificationRequest, nil } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) { +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { var verificationRequests []*model.VerificationRequest - paginationClone := pagination totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.VerificationRequest) err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total) if err != nil { return nil, err } - // there is no offset in cassandra // so we fetch till limit + offset // and return the results from offset to limit @@ -85,12 +83,12 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode return &model.VerificationRequests{ VerificationRequests: verificationRequests, - Pagination: &paginationClone, + Pagination: paginationClone, }, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error { +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.VerificationRequest, verificationRequest.ID) err := p.db.Query(query).Exec() if err != nil { diff --git a/server/db/providers/cassandradb/webhook.go b/server/db/providers/cassandradb/webhook.go index cb50f08..e80dfdd 100644 --- a/server/db/providers/cassandradb/webhook.go +++ b/server/db/providers/cassandradb/webhook.go @@ -15,7 +15,7 @@ import ( ) // AddWebhook to add webhook -func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() } @@ -33,7 +33,7 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod } // UpdateWebhook to update webhook -func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { webhook.UpdatedAt = time.Now().Unix() // Event is changed if !strings.Contains(webhook.EventName, "-") { @@ -81,7 +81,7 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (* } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) { +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { webhooks := []*model.Webhook{} paginationClone := pagination totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.Webhook) @@ -108,7 +108,7 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) } return &model.Webhooks{ - Pagination: &paginationClone, + Pagination: paginationClone, Webhooks: webhooks, }, nil } diff --git a/server/db/providers/cassandradb/webhook_log.go b/server/db/providers/cassandradb/webhook_log.go index 9ecf939..d587e02 100644 --- a/server/db/providers/cassandradb/webhook_log.go +++ b/server/db/providers/cassandradb/webhook_log.go @@ -12,7 +12,7 @@ import ( ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } @@ -30,7 +30,7 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookL } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) { +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { webhookLogs := []*model.WebhookLog{} paginationClone := pagination totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.WebhookLog) @@ -38,7 +38,6 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat // so we fetch till limit + offset // and return the results from offset to limit query := fmt.Sprintf("SELECT id, http_status, response, request, webhook_id, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.WebhookLog, pagination.Limit+pagination.Offset) - if webhookID != "" { totalCountQuery = fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE webhook_id='%s' ALLOW FILTERING`, KeySpace+"."+models.Collections.WebhookLog, webhookID) query = fmt.Sprintf("SELECT id, http_status, response, request, webhook_id, created_at, updated_at FROM %s WHERE webhook_id = '%s' LIMIT %d ALLOW FILTERING", KeySpace+"."+models.Collections.WebhookLog, webhookID, pagination.Limit+pagination.Offset) @@ -64,7 +63,7 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat } return &model.WebhookLogs{ - Pagination: &paginationClone, + Pagination: paginationClone, WebhookLogs: webhookLogs, }, nil } diff --git a/server/db/providers/couchbase/email_template.go b/server/db/providers/couchbase/email_template.go index bd37482..14f5ba9 100644 --- a/server/db/providers/couchbase/email_template.go +++ b/server/db/providers/couchbase/email_template.go @@ -15,7 +15,7 @@ import ( ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() @@ -37,7 +37,7 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { bytes, err := json.Marshal(emailTemplate) if err != nil { return nil, err @@ -67,7 +67,7 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) { +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { emailTemplates := []*model.EmailTemplate{} paginationClone := pagination total, err := p.GetTotalDocs(ctx, models.Collections.EmailTemplate) @@ -88,7 +88,7 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin } for queryResult.Next() { - emailTemplate := models.EmailTemplate{} + var emailTemplate *models.EmailTemplate err := queryResult.Row(&emailTemplate) if err != nil { log.Fatal(err) @@ -102,54 +102,46 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin } return &model.EmailTemplates{ - Pagination: &paginationClone, + Pagination: paginationClone, EmailTemplates: emailTemplates, }, nil } // GetEmailTemplateByID to get EmailTemplate by id func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { - emailTemplate := models.EmailTemplate{} - + var emailTemplate *models.EmailTemplate query := fmt.Sprintf(`SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1`, p.scopeName, models.Collections.EmailTemplate) q, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, PositionalParameters: []interface{}{emailTemplateID}, }) - if err != nil { return nil, err } err = q.One(&emailTemplate) - if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil } // GetEmailTemplateByEventName to get EmailTemplate by event_name func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { - emailTemplate := models.EmailTemplate{} - + var emailTemplate models.EmailTemplate query := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE event_name=$1 LIMIT 1", p.scopeName, models.Collections.EmailTemplate) q, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, PositionalParameters: []interface{}{eventName}, }) - if err != nil { return nil, err } err = q.One(&emailTemplate) - if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil } diff --git a/server/db/providers/couchbase/env.go b/server/db/providers/couchbase/env.go index 3addb9f..3f24937 100644 --- a/server/db/providers/couchbase/env.go +++ b/server/db/providers/couchbase/env.go @@ -11,7 +11,7 @@ import ( ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { if env.ID == "" { env.ID = uuid.New().String() } @@ -19,7 +19,6 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro env.UpdatedAt = time.Now().Unix() env.Key = env.ID env.EncryptionKey = env.Hash - insertOpt := gocb.InsertOptions{ Context: ctx, } @@ -31,7 +30,7 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro } // UpdateEnv to update environment information in database -func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) { env.UpdatedAt = time.Now().Unix() env.EncryptionKey = env.Hash @@ -40,17 +39,15 @@ func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, e Context: ctx, PositionalParameters: []interface{}{env.EnvData, env.UpdatedAt, env.UpdatedAt, env.ID}, }) - if err != nil { return env, err } - return env, nil } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (models.Env, error) { - var env models.Env +func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { + var env *models.Env query := fmt.Sprintf("SELECT _id, env, encryption_key, created_at, updated_at FROM %s.%s LIMIT 1", p.scopeName, models.Collections.Env) q, err := p.db.Query(query, &gocb.QueryOptions{ @@ -61,7 +58,6 @@ func (p *provider) GetEnv(ctx context.Context) (models.Env, error) { return env, err } err = q.One(&env) - if err != nil { return env, err } diff --git a/server/db/providers/couchbase/otp.go b/server/db/providers/couchbase/otp.go index cdcfde9..1fe6532 100644 --- a/server/db/providers/couchbase/otp.go +++ b/server/db/providers/couchbase/otp.go @@ -2,6 +2,7 @@ package couchbase import ( "context" + "errors" "fmt" "time" @@ -12,24 +13,36 @@ import ( // UpsertOTP to add or update otp func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { - otp, _ := p.GetOTPByEmail(ctx, otpParam.Email) - + // check if email or phone number is present + if otpParam.Email == "" && otpParam.PhoneNumber == "" { + return nil, errors.New("email or phone_number is required") + } + uniqueField := models.FieldNameEmail + if otpParam.Email == "" && otpParam.PhoneNumber != "" { + uniqueField = models.FieldNamePhoneNumber + } + var otp *models.OTP + if uniqueField == models.FieldNameEmail { + otp, _ = p.GetOTPByEmail(ctx, otpParam.Email) + } else { + otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber) + } shouldCreate := false if otp == nil { shouldCreate = true otp = &models.OTP{ - ID: uuid.NewString(), - Otp: otpParam.Otp, - Email: otpParam.Email, - ExpiresAt: otpParam.ExpiresAt, - CreatedAt: time.Now().Unix(), - UpdatedAt: time.Now().Unix(), + ID: uuid.NewString(), + Otp: otpParam.Otp, + Email: otpParam.Email, + PhoneNumber: otpParam.PhoneNumber, + ExpiresAt: otpParam.ExpiresAt, + CreatedAt: time.Now().Unix(), + UpdatedAt: time.Now().Unix(), } } else { otp.Otp = otpParam.Otp otp.ExpiresAt = otpParam.ExpiresAt } - otp.UpdatedAt = time.Now().Unix() if shouldCreate { insertOpt := gocb.InsertOptions{ @@ -54,7 +67,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models // GetOTPByEmail to get otp for a given email address func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { otp := models.OTP{} - query := fmt.Sprintf(`SELECT _id, email, otp, expires_at, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1`, p.scopeName, models.Collections.OTP) + query := fmt.Sprintf(`SELECT _id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1`, p.scopeName, models.Collections.OTP) q, err := p.db.Query(query, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, PositionalParameters: []interface{}{emailAddress}, @@ -63,11 +76,27 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod return nil, err } err = q.One(&otp) - if err != nil { return nil, err } + return &otp, nil +} +// GetOTPByPhoneNumber to get otp for a given phone number +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { + otp := models.OTP{} + query := fmt.Sprintf(`SELECT _id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1`, p.scopeName, models.Collections.OTP) + q, err := p.db.Query(query, &gocb.QueryOptions{ + ScanConsistency: gocb.QueryScanConsistencyRequestPlus, + PositionalParameters: []interface{}{phoneNumber}, + }) + if err != nil { + return nil, err + } + err = q.One(&otp) + if err != nil { + return nil, err + } return &otp, nil } diff --git a/server/db/providers/couchbase/provider.go b/server/db/providers/couchbase/provider.go index c5d5404..723e47a 100644 --- a/server/db/providers/couchbase/provider.go +++ b/server/db/providers/couchbase/provider.go @@ -166,5 +166,9 @@ func GetIndex(scopeName string) map[string][]string { otpIndex1 := fmt.Sprintf("CREATE INDEX OTPEmailIndex ON %s.%s(email)", scopeName, models.Collections.OTP) indices[models.Collections.OTP] = []string{otpIndex1} + // OTP index + otpIndex2 := fmt.Sprintf("CREATE INDEX OTPPhoneNumberIndex ON %s.%s(phone_number)", scopeName, models.Collections.OTP) + indices[models.Collections.OTP] = []string{otpIndex2} + return indices } diff --git a/server/db/providers/couchbase/session.go b/server/db/providers/couchbase/session.go index 6f0d84f..a3b9915 100644 --- a/server/db/providers/couchbase/session.go +++ b/server/db/providers/couchbase/session.go @@ -10,11 +10,10 @@ import ( ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *models.Session) error { if session.ID == "" { session.ID = uuid.New().String() } - session.CreatedAt = time.Now().Unix() session.UpdatedAt = time.Now().Unix() insertOpt := gocb.InsertOptions{ @@ -24,7 +23,6 @@ func (p *provider) AddSession(ctx context.Context, session models.Session) error if err != nil { return err } - return nil } diff --git a/server/db/providers/couchbase/shared.go b/server/db/providers/couchbase/shared.go index 104ad02..00a8cfa 100644 --- a/server/db/providers/couchbase/shared.go +++ b/server/db/providers/couchbase/shared.go @@ -11,24 +11,19 @@ import ( func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interface{}) { params := make(map[string]interface{}, 1) - updateFields := "" - for key, value := range webhookMap { if key == "_id" { continue } - if key == "_key" { continue } - if value == nil { updateFields += fmt.Sprintf("%s=$%s,", key, key) params[key] = "null" continue } - valueType := reflect.TypeOf(value) if valueType.Name() == "string" { updateFields += fmt.Sprintf("%s = $%s, ", key, key) @@ -46,14 +41,11 @@ func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interfa func (p *provider) GetTotalDocs(ctx context.Context, collection string) (int64, error) { totalDocs := TotalDocs{} - countQuery := fmt.Sprintf("SELECT COUNT(*) as Total FROM %s.%s", p.scopeName, collection) queryRes, err := p.db.Query(countQuery, &gocb.QueryOptions{ Context: ctx, }) - queryRes.One(&totalDocs) - if err != nil { return totalDocs.Total, err } diff --git a/server/db/providers/couchbase/sms_verification_requests.go b/server/db/providers/couchbase/sms_verification_requests.go deleted file mode 100644 index 9201d73..0000000 --- a/server/db/providers/couchbase/sms_verification_requests.go +++ /dev/null @@ -1,23 +0,0 @@ -package couchbase - -import ( - "context" - - "github.com/authorizerdev/authorizer/server/db/models" - -) - -// SMS verification Request -func (p *provider) UpsertSMSRequest(ctx context.Context, sms_code *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) { - return sms_code, nil -} - -func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) { - var sms_verification_request models.SMSVerificationRequest - - return &sms_verification_request, nil -} - -func(p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error { - return nil -} diff --git a/server/db/providers/couchbase/user.go b/server/db/providers/couchbase/user.go index 2dc813c..f5d2195 100644 --- a/server/db/providers/couchbase/user.go +++ b/server/db/providers/couchbase/user.go @@ -15,7 +15,7 @@ import ( ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { if user.ID == "" { user.ID = uuid.New().String() } @@ -41,7 +41,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, } // 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() unsertOpt := gocb.UpsertOptions{ Context: ctx, @@ -54,7 +54,7 @@ func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.Use } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user models.User) error { +func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { removeOpt := gocb.RemoveOptions{ Context: ctx, } @@ -66,12 +66,10 @@ func (p *provider) DeleteUser(ctx context.Context, user models.User) error { } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) { +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { users := []*model.User{} paginationClone := pagination - userQuery := 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, created_at, updated_at FROM %s.%s ORDER BY id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.User) - queryResult, err := p.db.Query(userQuery, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, Context: ctx, @@ -97,21 +95,20 @@ func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) ( return nil, err } return &model.Users{ - Pagination: &paginationClone, + Pagination: paginationClone, Users: users, }, nil } // GetUserByEmail to get user information from database using email address -func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) { - user := models.User{} +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) { + var user *models.User 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, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1", p.scopeName, models.Collections.User) q, err := p.db.Query(query, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, Context: ctx, PositionalParameters: []interface{}{email}, }) - if err != nil { return user, err } @@ -119,13 +116,12 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.Use if err != nil { return user, err } - return user, nil } // GetUserByID to get user information from database using user ID -func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) { - user := models.User{} +func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) { + var user *models.User 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, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1", p.scopeName, models.Collections.User) q, err := p.db.Query(query, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, @@ -139,7 +135,6 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, err if err != nil { return user, err } - return user, nil } @@ -174,7 +169,6 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, return err } } - return nil } @@ -194,6 +188,5 @@ func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) if err != nil { return user, err } - return user, nil } diff --git a/server/db/providers/couchbase/verification_requests.go b/server/db/providers/couchbase/verification_requests.go index 6971065..314f69a 100644 --- a/server/db/providers/couchbase/verification_requests.go +++ b/server/db/providers/couchbase/verification_requests.go @@ -13,11 +13,10 @@ import ( ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() } - verificationRequest.Key = verificationRequest.ID verificationRequest.CreatedAt = time.Now().Unix() verificationRequest.UpdatedAt = time.Now().Unix() @@ -28,13 +27,12 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque if err != nil { return verificationRequest, err } - return verificationRequest, nil } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) { - verificationRequest := models.VerificationRequest{} +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { + var verificationRequest *models.VerificationRequest params := make(map[string]interface{}, 1) params["token"] = token query := fmt.Sprintf("SELECT _id, token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE token=$1 LIMIT 1", p.scopeName, models.Collections.VerificationRequest) @@ -57,7 +55,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) { +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { query := fmt.Sprintf("SELECT _id, identifier, token, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE email=$1 AND identifier=$2 LIMIT 1", p.scopeName, models.Collections.VerificationRequest) queryResult, err := p.db.Query(query, &gocb.QueryOptions{ @@ -65,14 +63,11 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri PositionalParameters: []interface{}{email, identifier}, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, }) - verificationRequest := models.VerificationRequest{} - if err != nil { - return verificationRequest, err + return nil, err } - + var verificationRequest *models.VerificationRequest err = queryResult.One(&verificationRequest) - if err != nil { return verificationRequest, err } @@ -80,7 +75,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) { +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { var verificationRequests []*model.VerificationRequest paginationClone := pagination total, err := p.GetTotalDocs(ctx, models.Collections.VerificationRequest) @@ -111,12 +106,12 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode } return &model.VerificationRequests{ VerificationRequests: verificationRequests, - Pagination: &paginationClone, + Pagination: paginationClone, }, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error { +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { removeOpt := gocb.RemoveOptions{ Context: ctx, } diff --git a/server/db/providers/couchbase/webhook.go b/server/db/providers/couchbase/webhook.go index 2f51acd..92b0111 100644 --- a/server/db/providers/couchbase/webhook.go +++ b/server/db/providers/couchbase/webhook.go @@ -15,7 +15,7 @@ import ( ) // AddWebhook to add webhook -func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() } @@ -35,7 +35,7 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod } // UpdateWebhook to update webhook -func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { webhook.UpdatedAt = time.Now().Unix() // Event is changed if !strings.Contains(webhook.EventName, "-") { @@ -68,7 +68,7 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (* } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) { +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { webhooks := []*model.Webhook{} paginationClone := pagination params := make(map[string]interface{}, 1) @@ -100,14 +100,14 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) return nil, err } return &model.Webhooks{ - Pagination: &paginationClone, + Pagination: paginationClone, Webhooks: webhooks, }, nil } // GetWebhookByID to get webhook by id func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) { - var webhook models.Webhook + var webhook *models.Webhook params := make(map[string]interface{}, 1) params["_id"] = webhookID query := fmt.Sprintf(`SELECT _id, event_description, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s.%s WHERE _id=$_id LIMIT 1`, p.scopeName, models.Collections.Webhook) @@ -141,7 +141,7 @@ func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) } webhooks := []*model.Webhook{} for queryResult.Next() { - var webhook models.Webhook + var webhook *models.Webhook err := queryResult.Row(&webhook) if err != nil { log.Fatal(err) @@ -162,11 +162,9 @@ func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) er Context: ctx, } _, err := p.db.Collection(models.Collections.Webhook).Remove(webhook.ID, &removeOpt) - if err != nil { return err } - query := fmt.Sprintf(`DELETE FROM %s.%s WHERE webhook_id=$webhook_id`, p.scopeName, models.Collections.WebhookLog) _, err = p.db.Query(query, &gocb.QueryOptions{ Context: ctx, @@ -176,6 +174,5 @@ func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) er if err != nil { return err } - return nil } diff --git a/server/db/providers/couchbase/webhook_log.go b/server/db/providers/couchbase/webhook_log.go index 7c4fd15..0482394 100644 --- a/server/db/providers/couchbase/webhook_log.go +++ b/server/db/providers/couchbase/webhook_log.go @@ -13,15 +13,13 @@ import ( ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } - webhookLog.Key = webhookLog.ID webhookLog.CreatedAt = time.Now().Unix() webhookLog.UpdatedAt = time.Now().Unix() - insertOpt := gocb.InsertOptions{ Context: ctx, } @@ -29,19 +27,16 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookL if err != nil { return webhookLog.AsAPIWebhookLog(), err } - return webhookLog.AsAPIWebhookLog(), nil } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) { +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { var query string var err error - webhookLogs := []*model.WebhookLog{} params := make(map[string]interface{}, 1) paginationClone := pagination - params["webhookID"] = webhookID params["offset"] = paginationClone.Offset params["limit"] = paginationClone.Limit @@ -55,13 +50,11 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat } else { query = fmt.Sprintf("SELECT _id, http_status, response, request, webhook_id, created_at, updated_at FROM %s.%s OFFSET $offset LIMIT $limit", p.scopeName, models.Collections.WebhookLog) } - queryResult, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, NamedParameters: params, }) - if err != nil { return nil, err } @@ -73,13 +66,12 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat } webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog()) } - if err := queryResult.Err(); err != nil { return nil, err } return &model.WebhookLogs{ - Pagination: &paginationClone, + Pagination: paginationClone, WebhookLogs: webhookLogs, }, nil } diff --git a/server/db/providers/dynamodb/email_template.go b/server/db/providers/dynamodb/email_template.go index 08745cf..7355bbb 100644 --- a/server/db/providers/dynamodb/email_template.go +++ b/server/db/providers/dynamodb/email_template.go @@ -12,7 +12,7 @@ import ( ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { collection := p.db.Table(models.Collections.EmailTemplate) if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() @@ -31,7 +31,7 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { collection := p.db.Table(models.Collections.EmailTemplate) emailTemplate.UpdatedAt = time.Now().Unix() err := UpdateByHashKey(collection, "id", emailTemplate.ID, emailTemplate) @@ -42,23 +42,19 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) { - - var emailTemplate models.EmailTemplate +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { + var emailTemplate *models.EmailTemplate var iter dynamo.PagingIter var lastEval dynamo.PagingKey var iteration int64 = 0 - collection := p.db.Table(models.Collections.EmailTemplate) emailTemplates := []*model.EmailTemplate{} paginationClone := pagination scanner := collection.Scan() count, err := scanner.Count() - if err != nil { return nil, err } - for (paginationClone.Offset + paginationClone.Limit) > iteration { iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter() for iter.NextWithContext(ctx, &emailTemplate) { @@ -69,11 +65,9 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin lastEval = iter.LastEvaluatedKey() iteration += paginationClone.Limit } - paginationClone.Total = count - return &model.EmailTemplates{ - Pagination: &paginationClone, + Pagination: paginationClone, EmailTemplates: emailTemplates, }, nil } @@ -81,7 +75,7 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin // GetEmailTemplateByID to get EmailTemplate by id func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { collection := p.db.Table(models.Collections.EmailTemplate) - var emailTemplate models.EmailTemplate + var emailTemplate *models.EmailTemplate err := collection.Get("id", emailTemplateID).OneWithContext(ctx, &emailTemplate) if err != nil { return nil, err @@ -92,9 +86,8 @@ func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID str // GetEmailTemplateByEventName to get EmailTemplate by event_name func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { collection := p.db.Table(models.Collections.EmailTemplate) - var emailTemplates []models.EmailTemplate - var emailTemplate models.EmailTemplate - + var emailTemplates []*models.EmailTemplate + var emailTemplate *models.EmailTemplate err := collection.Scan().Index("event_name").Filter("'event_name' = ?", eventName).Limit(1).AllWithContext(ctx, &emailTemplates) if err != nil { return nil, err @@ -112,7 +105,6 @@ func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName st func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error { collection := p.db.Table(models.Collections.EmailTemplate) err := collection.Delete("id", emailTemplate.ID).RunWithContext(ctx) - if err != nil { return err } diff --git a/server/db/providers/dynamodb/env.go b/server/db/providers/dynamodb/env.go index d491e19..0b356f7 100644 --- a/server/db/providers/dynamodb/env.go +++ b/server/db/providers/dynamodb/env.go @@ -11,34 +11,26 @@ import ( ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { collection := p.db.Table(models.Collections.Env) - if env.ID == "" { env.ID = uuid.New().String() } - env.Key = env.ID - env.CreatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix() - err := collection.Put(env).RunWithContext(ctx) - if err != nil { return env, err } - return env, nil } // UpdateEnv to update environment information in database -func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) { collection := p.db.Table(models.Collections.Env) env.UpdatedAt = time.Now().Unix() - err := UpdateByHashKey(collection, "id", env.ID, env) - if err != nil { return env, err } @@ -46,26 +38,21 @@ func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, e } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (models.Env, error) { - var env models.Env - +func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { + var env *models.Env collection := p.db.Table(models.Collections.Env) // As there is no Findone supported. iter := collection.Scan().Limit(1).Iter() - for iter.NextWithContext(ctx, &env) { - if env.ID == "" { + if env == nil { return env, errors.New("no documets found") } else { return env, nil } } - err := iter.Err() - if err != nil { return env, fmt.Errorf("config not found") } - return env, nil } diff --git a/server/db/providers/dynamodb/otp.go b/server/db/providers/dynamodb/otp.go index 063f634..23273e2 100644 --- a/server/db/providers/dynamodb/otp.go +++ b/server/db/providers/dynamodb/otp.go @@ -11,27 +11,39 @@ import ( // UpsertOTP to add or update otp func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { - otp, _ := p.GetOTPByEmail(ctx, otpParam.Email) + // check if email or phone number is present + if otpParam.Email == "" && otpParam.PhoneNumber == "" { + return nil, errors.New("email or phone_number is required") + } + uniqueField := models.FieldNameEmail + if otpParam.Email == "" && otpParam.PhoneNumber != "" { + uniqueField = models.FieldNamePhoneNumber + } + var otp *models.OTP + if uniqueField == models.FieldNameEmail { + otp, _ = p.GetOTPByEmail(ctx, otpParam.Email) + } else { + otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber) + } shouldCreate := false if otp == nil { id := uuid.NewString() otp = &models.OTP{ - ID: id, - Key: id, - Otp: otpParam.Otp, - Email: otpParam.Email, - ExpiresAt: otpParam.ExpiresAt, - CreatedAt: time.Now().Unix(), + ID: id, + Key: id, + Otp: otpParam.Otp, + Email: otpParam.Email, + PhoneNumber: otpParam.PhoneNumber, + ExpiresAt: otpParam.ExpiresAt, + CreatedAt: time.Now().Unix(), } shouldCreate = true } else { otp.Otp = otpParam.Otp otp.ExpiresAt = otpParam.ExpiresAt } - collection := p.db.Table(models.Collections.OTP) otp.UpdatedAt = time.Now().Unix() - var err error if shouldCreate { err = collection.Put(otp).RunWithContext(ctx) @@ -41,7 +53,6 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models if err != nil { return nil, err } - return otp, nil } @@ -49,32 +60,42 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { var otps []models.OTP var otp models.OTP - collection := p.db.Table(models.Collections.OTP) - err := collection.Scan().Index("email").Filter("'email' = ?", emailAddress).Limit(1).AllWithContext(ctx, &otps) - if err != nil { return nil, err } if len(otps) > 0 { otp = otps[0] return &otp, nil - } else { - return nil, errors.New("no docuemnt found") } + return nil, errors.New("no docuemnt found") +} + +// GetOTPByPhoneNumber to get otp for a given phone number +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { + var otps []models.OTP + var otp models.OTP + collection := p.db.Table(models.Collections.OTP) + err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).Limit(1).AllWithContext(ctx, &otps) + if err != nil { + return nil, err + } + if len(otps) > 0 { + otp = otps[0] + return &otp, nil + } + return nil, errors.New("no docuemnt found") } // DeleteOTP to delete otp func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { collection := p.db.Table(models.Collections.OTP) - if otp.ID != "" { err := collection.Delete("id", otp.ID).RunWithContext(ctx) if err != nil { return err } } - return nil } diff --git a/server/db/providers/dynamodb/provider.go b/server/db/providers/dynamodb/provider.go index 4bf3345..4cc4084 100644 --- a/server/db/providers/dynamodb/provider.go +++ b/server/db/providers/dynamodb/provider.go @@ -31,21 +31,19 @@ func NewProvider() (*provider, error) { if awsRegion != "" { config.Region = aws.String(awsRegion) } - // custom awsAccessKeyID, awsSecretAccessKey took first priority, if not then fetch config from aws credentials if awsAccessKeyID != "" && awsSecretAccessKey != "" { config.Credentials = credentials.NewStaticCredentials(awsAccessKeyID, awsSecretAccessKey, "") } else if dbURL != "" { + log.Debug("Tring to use database url for dynamodb") // static config in case of testing or local-setup config.Credentials = credentials.NewStaticCredentials("key", "key", "") config.Endpoint = aws.String(dbURL) } else { log.Debugf("%s or %s or %s not found. Trying to load default credentials from aws config", constants.EnvAwsRegion, constants.EnvAwsAccessKeyID, constants.EnvAwsSecretAccessKey) } - session := session.Must(session.NewSession(&config)) db := dynamo.New(session) - db.CreateTable(models.Collections.User, models.User{}).Wait() db.CreateTable(models.Collections.Session, models.Session{}).Wait() db.CreateTable(models.Collections.EmailTemplate, models.EmailTemplate{}).Wait() @@ -54,7 +52,6 @@ func NewProvider() (*provider, error) { db.CreateTable(models.Collections.VerificationRequest, models.VerificationRequest{}).Wait() db.CreateTable(models.Collections.Webhook, models.Webhook{}).Wait() db.CreateTable(models.Collections.WebhookLog, models.WebhookLog{}).Wait() - return &provider{ db: db, }, nil diff --git a/server/db/providers/dynamodb/session.go b/server/db/providers/dynamodb/session.go index 68457e5..d65da9a 100644 --- a/server/db/providers/dynamodb/session.go +++ b/server/db/providers/dynamodb/session.go @@ -9,13 +9,11 @@ import ( ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *models.Session) error { collection := p.db.Table(models.Collections.Session) - if session.ID == "" { session.ID = uuid.New().String() } - session.CreatedAt = time.Now().Unix() session.UpdatedAt = time.Now().Unix() err := collection.Put(session).RunWithContext(ctx) diff --git a/server/db/providers/dynamodb/shared.go b/server/db/providers/dynamodb/shared.go index ed91eca..5597c0a 100644 --- a/server/db/providers/dynamodb/shared.go +++ b/server/db/providers/dynamodb/shared.go @@ -9,16 +9,13 @@ import ( func UpdateByHashKey(table dynamo.Table, hashKey string, hashValue string, item interface{}) error { existingValue, err := dynamo.MarshalItem(item) var i interface{} - if err != nil { return err } - nullableValue, err := dynamodbattribute.MarshalMap(item) if err != nil { return err } - u := table.Update(hashKey, hashValue) for k, v := range existingValue { if k == hashKey { @@ -26,7 +23,6 @@ func UpdateByHashKey(table dynamo.Table, hashKey string, hashValue string, item } u = u.Set(k, v) } - for k, v := range nullableValue { if k == hashKey { continue @@ -36,11 +32,9 @@ func UpdateByHashKey(table dynamo.Table, hashKey string, hashValue string, item u = u.SetNullable(k, v) } } - err = u.Run() if err != nil { return err } - return nil } diff --git a/server/db/providers/dynamodb/sms_verification_requests.go b/server/db/providers/dynamodb/sms_verification_requests.go deleted file mode 100644 index bd47bce..0000000 --- a/server/db/providers/dynamodb/sms_verification_requests.go +++ /dev/null @@ -1,23 +0,0 @@ -package dynamodb - -import ( - "context" - - "github.com/authorizerdev/authorizer/server/db/models" - -) - -// SMS verification Request -func (p *provider) UpsertSMSRequest(ctx context.Context, sms_code *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) { - return sms_code, nil -} - -func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) { - var sms_verification_request models.SMSVerificationRequest - - return &sms_verification_request, nil -} - -func(p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error { - return nil -} diff --git a/server/db/providers/dynamodb/user.go b/server/db/providers/dynamodb/user.go index d7c47e3..f93956b 100644 --- a/server/db/providers/dynamodb/user.go +++ b/server/db/providers/dynamodb/user.go @@ -18,13 +18,11 @@ import ( ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { collection := p.db.Table(models.Collections.User) - if user.ID == "" { user.ID = uuid.New().String() } - if user.Roles == "" { defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) if err != nil { @@ -32,18 +30,14 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, } user.Roles = defaultRoles } - if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" { if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil { return user, fmt.Errorf("user with given phone number already exists") } } - user.CreatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix() - err := collection.Put(user).RunWithContext(ctx) - if err != nil { return user, err } @@ -51,18 +45,14 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, } // 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) { collection := p.db.Table(models.Collections.User) - if user.ID != "" { - user.UpdatedAt = time.Now().Unix() - err := UpdateByHashKey(collection, "id", user.ID, user) if err != nil { return user, err } - if err != nil { return user, err } @@ -72,18 +62,15 @@ func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.Use } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user models.User) error { +func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { collection := p.db.Table(models.Collections.User) sessionCollection := p.db.Table(models.Collections.Session) - if user.ID != "" { err := collection.Delete("id", user.ID).Run() if err != nil { return err } - _, err = sessionCollection.Batch("id").Write().Delete(dynamo.Keys{"user_id", user.ID}).RunWithContext(ctx) - if err != nil { return err } @@ -92,23 +79,19 @@ func (p *provider) DeleteUser(ctx context.Context, user models.User) error { } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) { - var user models.User +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { + var user *models.User var lastEval dynamo.PagingKey var iter dynamo.PagingIter var iteration int64 = 0 - collection := p.db.Table(models.Collections.User) users := []*model.User{} - paginationClone := pagination scanner := collection.Scan() count, err := scanner.Count() - if err != nil { return nil, err } - for (paginationClone.Offset + paginationClone.Limit) > iteration { iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter() for iter.NextWithContext(ctx, &user) { @@ -119,48 +102,39 @@ func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) ( lastEval = iter.LastEvaluatedKey() iteration += paginationClone.Limit } - err = iter.Err() - if err != nil { return nil, err } - paginationClone.Total = count - return &model.Users{ - Pagination: &paginationClone, + Pagination: paginationClone, Users: users, }, nil } // GetUserByEmail to get user information from database using email address -func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) { - var users []models.User - var user models.User - +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) { + var users []*models.User + var user *models.User collection := p.db.Table(models.Collections.User) err := collection.Scan().Index("email").Filter("'email' = ?", email).AllWithContext(ctx, &users) - if err != nil { return user, nil } - if len(users) > 0 { user = users[0] return user, nil } else { return user, errors.New("no record found") } - } // GetUserByID to get user information from database using user ID -func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) { +func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) { collection := p.db.Table(models.Collections.User) - var user models.User + var user *models.User err := collection.Get("id", id).OneWithContext(ctx, &user) - if err != nil { if user.Email == "" { return user, errors.New("no documets found") @@ -186,7 +160,6 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } else { // as there is no facility to update all doc - https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SQLtoNoSQL.UpdateData.html userCollection.Scan().All(&allUsers) - for _, user := range allUsers { err = UpdateByHashKey(userCollection, "id", user.ID, data) if err == nil { @@ -194,7 +167,6 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } } } - if err != nil { return err } else { @@ -205,19 +177,16 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, // GetUserByPhoneNumber to get user information from database using phone number func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) { - var users []models.User - var user models.User - + var users []*models.User + var user *models.User collection := p.db.Table(models.Collections.User) err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).AllWithContext(ctx, &users) - if err != nil { return nil, err } - if len(users) > 0 { user = users[0] - return &user, nil + return user, nil } else { return nil, errors.New("no record found") } diff --git a/server/db/providers/dynamodb/verification_requests.go b/server/db/providers/dynamodb/verification_requests.go index 990c288..5fdf078 100644 --- a/server/db/providers/dynamodb/verification_requests.go +++ b/server/db/providers/dynamodb/verification_requests.go @@ -11,9 +11,8 @@ import ( ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { collection := p.db.Table(models.Collections.VerificationRequest) - if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() verificationRequest.CreatedAt = time.Now().Unix() @@ -23,20 +22,17 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque return verificationRequest, err } } - return verificationRequest, nil } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) { +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { collection := p.db.Table(models.Collections.VerificationRequest) - var verificationRequest models.VerificationRequest - + var verificationRequest *models.VerificationRequest iter := collection.Scan().Filter("'token' = ?", token).Iter() for iter.NextWithContext(ctx, &verificationRequest) { return verificationRequest, nil } - err := iter.Err() if err != nil { return verificationRequest, err @@ -45,14 +41,13 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { + var verificationRequest *models.VerificationRequest collection := p.db.Table(models.Collections.VerificationRequest) iter := collection.Scan().Filter("'email' = ?", email).Filter("'identifier' = ?", identifier).Iter() for iter.NextWithContext(ctx, &verificationRequest) { return verificationRequest, nil } - err := iter.Err() if err != nil { return verificationRequest, err @@ -61,23 +56,19 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) { +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { verificationRequests := []*model.VerificationRequest{} - var verificationRequest models.VerificationRequest + var verificationRequest *models.VerificationRequest var lastEval dynamo.PagingKey var iter dynamo.PagingIter var iteration int64 = 0 - collection := p.db.Table(models.Collections.VerificationRequest) paginationClone := pagination - scanner := collection.Scan() count, err := scanner.Count() - if err != nil { return nil, err } - for (paginationClone.Offset + paginationClone.Limit) > iteration { iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter() for iter.NextWithContext(ctx, &verificationRequest) { @@ -92,20 +83,17 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode lastEval = iter.LastEvaluatedKey() iteration += paginationClone.Limit } - paginationClone.Total = count - return &model.VerificationRequests{ VerificationRequests: verificationRequests, - Pagination: &paginationClone, + Pagination: paginationClone, }, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error { +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { collection := p.db.Table(models.Collections.VerificationRequest) - - if verificationRequest.ID != "" { + if verificationRequest != nil { err := collection.Delete("id", verificationRequest.ID).RunWithContext(ctx) if err != nil { diff --git a/server/db/providers/dynamodb/webhook.go b/server/db/providers/dynamodb/webhook.go index 8f1ffb7..c50e1fb 100644 --- a/server/db/providers/dynamodb/webhook.go +++ b/server/db/providers/dynamodb/webhook.go @@ -15,7 +15,7 @@ import ( ) // AddWebhook to add webhook -func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { collection := p.db.Table(models.Collections.Webhook) if webhook.ID == "" { webhook.ID = uuid.New().String() @@ -33,7 +33,7 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod } // UpdateWebhook to update webhook -func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { webhook.UpdatedAt = time.Now().Unix() // Event is changed if !strings.Contains(webhook.EventName, "-") { @@ -48,9 +48,9 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (* } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) { +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { webhooks := []*model.Webhook{} - var webhook models.Webhook + var webhook *models.Webhook var lastEval dynamo.PagingKey var iter dynamo.PagingIter var iteration int64 = 0 @@ -77,7 +77,7 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) } paginationClone.Total = count return &model.Webhooks{ - Pagination: &paginationClone, + Pagination: paginationClone, Webhooks: webhooks, }, nil } @@ -85,7 +85,7 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) // GetWebhookByID to get webhook by id func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) { collection := p.db.Table(models.Collections.Webhook) - var webhook models.Webhook + var webhook *models.Webhook err := collection.Get("id", webhookID).OneWithContext(ctx, &webhook) if err != nil { return nil, err @@ -114,14 +114,14 @@ func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) // DeleteWebhook to delete webhook func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error { // Also delete webhook logs for given webhook id - if webhook.ID != "" { + if webhook != nil { webhookCollection := p.db.Table(models.Collections.Webhook) - pagination := model.Pagination{} webhookLogCollection := p.db.Table(models.Collections.WebhookLog) err := webhookCollection.Delete("id", webhook.ID).RunWithContext(ctx) if err != nil { return err } + pagination := &model.Pagination{} webhookLogs, errIs := p.ListWebhookLogs(ctx, pagination, webhook.ID) for _, webhookLog := range webhookLogs.WebhookLogs { err = webhookLogCollection.Delete("id", webhookLog.ID).RunWithContext(ctx) diff --git a/server/db/providers/dynamodb/webhook_log.go b/server/db/providers/dynamodb/webhook_log.go index e9d1dcd..18ba261 100644 --- a/server/db/providers/dynamodb/webhook_log.go +++ b/server/db/providers/dynamodb/webhook_log.go @@ -11,18 +11,15 @@ import ( ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { collection := p.db.Table(models.Collections.WebhookLog) - if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } - webhookLog.Key = webhookLog.ID webhookLog.CreatedAt = time.Now().Unix() webhookLog.UpdatedAt = time.Now().Unix() err := collection.Put(webhookLog).RunWithContext(ctx) - if err != nil { return nil, err } @@ -30,9 +27,9 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookL } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) { +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { webhookLogs := []*model.WebhookLog{} - var webhookLog models.WebhookLog + var webhookLog *models.WebhookLog var lastEval dynamo.PagingKey var iter dynamo.PagingIter var iteration int64 = 0 @@ -42,7 +39,6 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat collection := p.db.Table(models.Collections.WebhookLog) paginationClone := pagination scanner := collection.Scan() - if webhookID != "" { iter = scanner.Index("webhook_id").Filter("'webhook_id' = ?", webhookID).Iter() for iter.NextWithContext(ctx, &webhookLog) { @@ -68,11 +64,10 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat iteration += paginationClone.Limit } } - paginationClone.Total = count // paginationClone.Cursor = iter.LastEvaluatedKey() return &model.WebhookLogs{ - Pagination: &paginationClone, + Pagination: paginationClone, WebhookLogs: webhookLogs, }, nil } diff --git a/server/db/providers/mongodb/email_template.go b/server/db/providers/mongodb/email_template.go index 0a0d1d9..c3fa31b 100644 --- a/server/db/providers/mongodb/email_template.go +++ b/server/db/providers/mongodb/email_template.go @@ -12,15 +12,13 @@ import ( ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() } - emailTemplate.Key = emailTemplate.ID emailTemplate.CreatedAt = time.Now().Unix() emailTemplate.UpdatedAt = time.Now().Unix() - emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection()) _, err := emailTemplateCollection.InsertOne(ctx, emailTemplate) if err != nil { @@ -30,60 +28,52 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { emailTemplate.UpdatedAt = time.Now().Unix() - emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection()) _, err := emailTemplateCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": emailTemplate.ID}}, bson.M{"$set": emailTemplate}, options.MergeUpdateOptions()) if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) { +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { var emailTemplates []*model.EmailTemplate opts := options.Find() opts.SetLimit(pagination.Limit) opts.SetSkip(pagination.Offset) opts.SetSort(bson.M{"created_at": -1}) - paginationClone := pagination - emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection()) count, err := emailTemplateCollection.CountDocuments(ctx, bson.M{}, options.Count()) if err != nil { return nil, err } - paginationClone.Total = count - cursor, err := emailTemplateCollection.Find(ctx, bson.M{}, opts) if err != nil { return nil, err } defer cursor.Close(ctx) - for cursor.Next(ctx) { - var emailTemplate models.EmailTemplate + var emailTemplate *models.EmailTemplate err := cursor.Decode(&emailTemplate) if err != nil { return nil, err } emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate()) } - return &model.EmailTemplates{ - Pagination: &paginationClone, + Pagination: paginationClone, EmailTemplates: emailTemplates, }, nil } // GetEmailTemplateByID to get EmailTemplate by id func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { - var emailTemplate models.EmailTemplate + var emailTemplate *models.EmailTemplate emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection()) err := emailTemplateCollection.FindOne(ctx, bson.M{"_id": emailTemplateID}).Decode(&emailTemplate) if err != nil { @@ -94,7 +84,7 @@ func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID str // GetEmailTemplateByEventName to get EmailTemplate by event_name func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { - var emailTemplate models.EmailTemplate + var emailTemplate *models.EmailTemplate emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection()) err := emailTemplateCollection.FindOne(ctx, bson.M{"event_name": eventName}).Decode(&emailTemplate) if err != nil { @@ -110,6 +100,5 @@ func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model if err != nil { return err } - return nil } diff --git a/server/db/providers/mongodb/env.go b/server/db/providers/mongodb/env.go index a4b114c..b725612 100644 --- a/server/db/providers/mongodb/env.go +++ b/server/db/providers/mongodb/env.go @@ -12,11 +12,10 @@ import ( ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { if env.ID == "" { env.ID = uuid.New().String() } - env.CreatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix() env.Key = env.ID @@ -29,7 +28,7 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro } // UpdateEnv to update environment information in database -func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) { env.UpdatedAt = time.Now().Unix() configCollection := p.db.Collection(models.Collections.Env, options.Collection()) _, err := configCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions()) @@ -40,25 +39,22 @@ func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, e } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (models.Env, error) { - var env models.Env +func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { + var env *models.Env configCollection := p.db.Collection(models.Collections.Env, options.Collection()) cursor, err := configCollection.Find(ctx, bson.M{}, options.Find()) if err != nil { return env, err } defer cursor.Close(ctx) - for cursor.Next(nil) { err := cursor.Decode(&env) if err != nil { return env, err } } - - if env.ID == "" { + if env == nil { return env, fmt.Errorf("config not found") } - return env, nil } diff --git a/server/db/providers/mongodb/otp.go b/server/db/providers/mongodb/otp.go index d6ff2df..d70818d 100644 --- a/server/db/providers/mongodb/otp.go +++ b/server/db/providers/mongodb/otp.go @@ -2,6 +2,7 @@ package mongodb import ( "context" + "errors" "time" "github.com/authorizerdev/authorizer/server/db/models" @@ -12,17 +13,31 @@ import ( // UpsertOTP to add or update otp func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { - otp, _ := p.GetOTPByEmail(ctx, otpParam.Email) + // check if email or phone number is present + if otpParam.Email == "" && otpParam.PhoneNumber == "" { + return nil, errors.New("email or phone_number is required") + } + uniqueField := models.FieldNameEmail + if otpParam.Email == "" && otpParam.PhoneNumber != "" { + uniqueField = models.FieldNamePhoneNumber + } + var otp *models.OTP + if uniqueField == models.FieldNameEmail { + otp, _ = p.GetOTPByEmail(ctx, otpParam.Email) + } else { + otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber) + } shouldCreate := false if otp == nil { id := uuid.NewString() otp = &models.OTP{ - ID: id, - Key: id, - Otp: otpParam.Otp, - Email: otpParam.Email, - ExpiresAt: otpParam.ExpiresAt, - CreatedAt: time.Now().Unix(), + ID: id, + Key: id, + Otp: otpParam.Otp, + Email: otpParam.Email, + PhoneNumber: otpParam.PhoneNumber, + ExpiresAt: otpParam.ExpiresAt, + CreatedAt: time.Now().Unix(), } shouldCreate = true } else { @@ -41,20 +56,28 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models if err != nil { return nil, err } - return otp, nil } // GetOTPByEmail to get otp for a given email address func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { var otp models.OTP - otpCollection := p.db.Collection(models.Collections.OTP, options.Collection()) err := otpCollection.FindOne(ctx, bson.M{"email": emailAddress}).Decode(&otp) if err != nil { return nil, err } + return &otp, nil +} +// GetOTPByPhoneNumber to get otp for a given phone number +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { + var otp models.OTP + otpCollection := p.db.Collection(models.Collections.OTP, options.Collection()) + err := otpCollection.FindOne(ctx, bson.M{"phone_number": phoneNumber}).Decode(&otp) + if err != nil { + return nil, err + } return &otp, nil } diff --git a/server/db/providers/mongodb/provider.go b/server/db/providers/mongodb/provider.go index fd4a0b2..30af342 100644 --- a/server/db/providers/mongodb/provider.go +++ b/server/db/providers/mongodb/provider.go @@ -118,10 +118,7 @@ func NewProvider() (*provider, error) { Options: options.Index().SetUnique(true).SetSparse(true), }, }, options.CreateIndexes()) - - mongodb.CreateCollection(ctx, models.Collections.SMSVerificationRequest, options.CreateCollection()) - smsCollection := mongodb.Collection(models.Collections.SMSVerificationRequest, options.Collection()) - smsCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ + otpCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ { Keys: bson.M{"phone_number": 1}, Options: options.Index().SetUnique(true).SetSparse(true), diff --git a/server/db/providers/mongodb/session.go b/server/db/providers/mongodb/session.go index 4030130..860eeef 100644 --- a/server/db/providers/mongodb/session.go +++ b/server/db/providers/mongodb/session.go @@ -10,7 +10,7 @@ import ( ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *models.Session) error { if session.ID == "" { session.ID = uuid.New().String() } @@ -25,3 +25,8 @@ func (p *provider) AddSession(ctx context.Context, session models.Session) error } return nil } + +// DeleteSession to delete session information from database +func (p *provider) DeleteSession(ctx context.Context, userId string) error { + return nil +} diff --git a/server/db/providers/mongodb/sms_verification_requests.go b/server/db/providers/mongodb/sms_verification_requests.go deleted file mode 100644 index b2d3a13..0000000 --- a/server/db/providers/mongodb/sms_verification_requests.go +++ /dev/null @@ -1,69 +0,0 @@ -package mongodb - -import ( - "context" - "time" - - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/google/uuid" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo/options" -) - -// SMS verification Request -func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) { - smsVerificationRequest, _ := p.GetCodeByPhone(ctx, smsRequest.PhoneNumber) - shouldCreate := false - - if smsVerificationRequest == nil { - id := uuid.NewString() - - smsVerificationRequest = &models.SMSVerificationRequest{ - ID: id, - CreatedAt: time.Now().Unix(), - Code: smsRequest.Code, - PhoneNumber: smsRequest.PhoneNumber, - CodeExpiresAt: smsRequest.CodeExpiresAt, - } - shouldCreate = true - } - - smsVerificationRequest.UpdatedAt = time.Now().Unix() - smsRequestCollection := p.db.Collection(models.Collections.SMSVerificationRequest, options.Collection()) - - var err error - if shouldCreate { - _, err = smsRequestCollection.InsertOne(ctx, smsVerificationRequest) - } else { - _, err = smsRequestCollection.UpdateOne(ctx, bson.M{"phone_number": bson.M{"$eq": smsRequest.PhoneNumber}}, bson.M{"$set": smsVerificationRequest}, options.MergeUpdateOptions()) - } - - if err != nil { - return nil, err - } - - return smsVerificationRequest, nil -} - -func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) { - var smsVerificationRequest models.SMSVerificationRequest - - smsRequestCollection := p.db.Collection(models.Collections.SMSVerificationRequest, options.Collection()) - err := smsRequestCollection.FindOne(ctx, bson.M{"phone_number": phoneNumber}).Decode(&smsVerificationRequest) - - if err != nil { - return nil, err - } - - return &smsVerificationRequest, nil -} - -func (p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error { - smsVerificationRequests := p.db.Collection(models.Collections.SMSVerificationRequest, options.Collection()) - _, err := smsVerificationRequests.DeleteOne(nil, bson.M{"_id": smsRequest.ID}, options.Delete()) - if err != nil { - return err - } - - return nil -} diff --git a/server/db/providers/mongodb/user.go b/server/db/providers/mongodb/user.go index 32b6a17..078322e 100644 --- a/server/db/providers/mongodb/user.go +++ b/server/db/providers/mongodb/user.go @@ -16,11 +16,10 @@ import ( ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { if user.ID == "" { user.ID = uuid.New().String() } - if user.Roles == "" { defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) if err != nil { @@ -36,12 +35,11 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, if err != nil { return user, err } - return user, nil } // 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() userCollection := p.db.Collection(models.Collections.User, options.Collection()) _, err := userCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions()) @@ -52,83 +50,72 @@ func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.Use } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user models.User) error { +func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { userCollection := p.db.Collection(models.Collections.User, options.Collection()) _, err := userCollection.DeleteOne(ctx, bson.M{"_id": user.ID}, options.Delete()) if err != nil { return err } - sessionCollection := p.db.Collection(models.Collections.Session, options.Collection()) _, err = sessionCollection.DeleteMany(ctx, bson.M{"user_id": user.ID}, options.Delete()) if err != nil { return err } - return nil } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) { +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { var users []*model.User opts := options.Find() opts.SetLimit(pagination.Limit) opts.SetSkip(pagination.Offset) opts.SetSort(bson.M{"created_at": -1}) - paginationClone := pagination - userCollection := p.db.Collection(models.Collections.User, options.Collection()) count, err := userCollection.CountDocuments(ctx, bson.M{}, options.Count()) if err != nil { return nil, err } - paginationClone.Total = count - cursor, err := userCollection.Find(ctx, bson.M{}, opts) if err != nil { return nil, err } defer cursor.Close(ctx) - for cursor.Next(ctx) { - var user models.User + var user *models.User err := cursor.Decode(&user) if err != nil { return nil, err } users = append(users, user.AsAPIUser()) } - return &model.Users{ - Pagination: &paginationClone, + Pagination: paginationClone, Users: users, }, nil } // GetUserByEmail to get user information from database using email address -func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) { - var user models.User +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) { + var user *models.User userCollection := p.db.Collection(models.Collections.User, options.Collection()) err := userCollection.FindOne(ctx, bson.M{"email": email}).Decode(&user) if err != nil { return user, err } - return user, nil } // GetUserByID to get user information from database using user ID -func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) { - var user models.User - +func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) { + var user *models.User userCollection := p.db.Collection(models.Collections.User, options.Collection()) err := userCollection.FindOne(ctx, bson.M{"_id": id}).Decode(&user) if err != nil { return user, err } - return user, nil } @@ -137,17 +124,14 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, err func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error { // set updated_at time for all users data["updated_at"] = time.Now().Unix() - userCollection := p.db.Collection(models.Collections.User, options.Collection()) - var res *mongo.UpdateResult var err error - if ids != nil && len(ids) > 0 { + if len(ids) > 0 { res, err = userCollection.UpdateMany(ctx, bson.M{"_id": bson.M{"$in": ids}}, bson.M{"$set": data}) } else { res, err = userCollection.UpdateMany(ctx, bson.M{}, bson.M{"$set": data}) } - if err != nil { return err } else { @@ -158,13 +142,11 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, // GetUserByPhoneNumber to get user information from database using phone number func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) { - var user models.User - + var user *models.User userCollection := p.db.Collection(models.Collections.User, options.Collection()) err := userCollection.FindOne(ctx, bson.M{"phone_number": phoneNumber}).Decode(&user) if err != nil { return nil, err } - - return &user, nil + return user, nil } diff --git a/server/db/providers/mongodb/verification_requests.go b/server/db/providers/mongodb/verification_requests.go index ff6f908..532d8c8 100644 --- a/server/db/providers/mongodb/verification_requests.go +++ b/server/db/providers/mongodb/verification_requests.go @@ -12,7 +12,7 @@ import ( ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() @@ -30,8 +30,8 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { + var verificationRequest *models.VerificationRequest verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) err := verificationRequestCollection.FindOne(ctx, bson.M{"token": token}).Decode(&verificationRequest) @@ -43,8 +43,8 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { + var verificationRequest *models.VerificationRequest verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) err := verificationRequestCollection.FindOne(ctx, bson.M{"email": email, "identifier": identifier}).Decode(&verificationRequest) @@ -56,7 +56,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) { +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { var verificationRequests []*model.VerificationRequest opts := options.Find() @@ -77,7 +77,7 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode defer cursor.Close(ctx) for cursor.Next(ctx) { - var verificationRequest models.VerificationRequest + var verificationRequest *models.VerificationRequest err := cursor.Decode(&verificationRequest) if err != nil { return nil, err @@ -87,12 +87,12 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode return &model.VerificationRequests{ VerificationRequests: verificationRequests, - Pagination: &paginationClone, + Pagination: paginationClone, }, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error { +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) _, err := verificationRequestCollection.DeleteOne(ctx, bson.M{"_id": verificationRequest.ID}, options.Delete()) if err != nil { diff --git a/server/db/providers/mongodb/webhook.go b/server/db/providers/mongodb/webhook.go index 843aec9..ef6b382 100644 --- a/server/db/providers/mongodb/webhook.go +++ b/server/db/providers/mongodb/webhook.go @@ -14,7 +14,7 @@ import ( ) // AddWebhook to add webhook -func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() } @@ -32,7 +32,7 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod } // UpdateWebhook to update webhook -func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { webhook.UpdatedAt = time.Now().Unix() // Event is changed if !strings.Contains(webhook.EventName, "-") { @@ -47,7 +47,7 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (* } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) { +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { webhooks := []*model.Webhook{} opts := options.Find() opts.SetLimit(pagination.Limit) @@ -66,7 +66,7 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) } defer cursor.Close(ctx) for cursor.Next(ctx) { - var webhook models.Webhook + var webhook *models.Webhook err := cursor.Decode(&webhook) if err != nil { return nil, err @@ -74,14 +74,14 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) webhooks = append(webhooks, webhook.AsAPIWebhook()) } return &model.Webhooks{ - Pagination: &paginationClone, + Pagination: paginationClone, Webhooks: webhooks, }, nil } // GetWebhookByID to get webhook by id func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) { - var webhook models.Webhook + var webhook *models.Webhook webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection()) err := webhookCollection.FindOne(ctx, bson.M{"_id": webhookID}).Decode(&webhook) if err != nil { @@ -104,7 +104,7 @@ func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) } defer cursor.Close(ctx) for cursor.Next(ctx) { - var webhook models.Webhook + var webhook *models.Webhook err := cursor.Decode(&webhook) if err != nil { return nil, err diff --git a/server/db/providers/mongodb/webhook_log.go b/server/db/providers/mongodb/webhook_log.go index 6e1081c..0c464d8 100644 --- a/server/db/providers/mongodb/webhook_log.go +++ b/server/db/providers/mongodb/webhook_log.go @@ -12,7 +12,7 @@ import ( ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } @@ -30,7 +30,7 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookL } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) { +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { webhookLogs := []*model.WebhookLog{} opts := options.Find() opts.SetLimit(pagination.Limit) @@ -59,7 +59,7 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat defer cursor.Close(ctx) for cursor.Next(ctx) { - var webhookLog models.WebhookLog + var webhookLog *models.WebhookLog err := cursor.Decode(&webhookLog) if err != nil { return nil, err @@ -68,7 +68,7 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat } return &model.WebhookLogs{ - Pagination: &paginationClone, + Pagination: paginationClone, WebhookLogs: webhookLogs, }, nil } diff --git a/server/db/providers/provider_template/email_template.go b/server/db/providers/provider_template/email_template.go index e6a1f50..a306479 100644 --- a/server/db/providers/provider_template/email_template.go +++ b/server/db/providers/provider_template/email_template.go @@ -10,7 +10,7 @@ import ( ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() } @@ -22,13 +22,13 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { emailTemplate.UpdatedAt = time.Now().Unix() return emailTemplate.AsAPIEmailTemplate(), nil } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) { +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { return nil, nil } diff --git a/server/db/providers/provider_template/env.go b/server/db/providers/provider_template/env.go index af232e8..823d4e3 100644 --- a/server/db/providers/provider_template/env.go +++ b/server/db/providers/provider_template/env.go @@ -9,7 +9,7 @@ import ( ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { if env.ID == "" { env.ID = uuid.New().String() } @@ -20,14 +20,14 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro } // UpdateEnv to update environment information in database -func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) { env.UpdatedAt = time.Now().Unix() return env, nil } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (models.Env, error) { - var env models.Env +func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { + var env *models.Env return env, nil } diff --git a/server/db/providers/provider_template/otp.go b/server/db/providers/provider_template/otp.go index d8685e7..0716711 100644 --- a/server/db/providers/provider_template/otp.go +++ b/server/db/providers/provider_template/otp.go @@ -16,6 +16,11 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod return nil, nil } +// GetOTPByPhoneNumber to get otp for a given phone number +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { + return nil, nil +} + // DeleteOTP to delete otp func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { return nil diff --git a/server/db/providers/provider_template/session.go b/server/db/providers/provider_template/session.go index c6f45ec..e398e8c 100644 --- a/server/db/providers/provider_template/session.go +++ b/server/db/providers/provider_template/session.go @@ -9,11 +9,10 @@ import ( ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *models.Session) error { if session.ID == "" { session.ID = uuid.New().String() } - session.CreatedAt = time.Now().Unix() session.UpdatedAt = time.Now().Unix() return nil diff --git a/server/db/providers/provider_template/user.go b/server/db/providers/provider_template/user.go index 286e74d..9f4c7f8 100644 --- a/server/db/providers/provider_template/user.go +++ b/server/db/providers/provider_template/user.go @@ -12,11 +12,10 @@ import ( ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { if user.ID == "" { user.ID = uuid.New().String() } - if user.Roles == "" { defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) if err != nil { @@ -24,40 +23,36 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, } user.Roles = defaultRoles } - user.CreatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix() - return user, nil } // 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() return user, nil } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user models.User) error { +func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { return nil } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) { +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { return nil, nil } // GetUserByEmail to get user information from database using email address -func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) { - var user models.User - +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) { + var user *models.User return user, nil } // GetUserByID to get user information from database using user ID -func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) { - var user models.User - +func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) { + var user *models.User return user, nil } @@ -66,13 +61,11 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, err func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error { // set updated_at time for all users data["updated_at"] = time.Now().Unix() - return nil } // GetUserByPhoneNumber to get user information from database using phone number func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) { var user *models.User - return user, nil } diff --git a/server/db/providers/provider_template/verification_requests.go b/server/db/providers/provider_template/verification_requests.go index 577d2f6..c3a7f18 100644 --- a/server/db/providers/provider_template/verification_requests.go +++ b/server/db/providers/provider_template/verification_requests.go @@ -10,7 +10,7 @@ import ( ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() } @@ -22,25 +22,25 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { + var verificationRequest *models.VerificationRequest return verificationRequest, nil } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { + var verificationRequest *models.VerificationRequest return verificationRequest, nil } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) { +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { return nil, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error { +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { return nil } diff --git a/server/db/providers/provider_template/webhook.go b/server/db/providers/provider_template/webhook.go index faf18fa..cf0edbe 100644 --- a/server/db/providers/provider_template/webhook.go +++ b/server/db/providers/provider_template/webhook.go @@ -12,7 +12,7 @@ import ( ) // AddWebhook to add webhook -func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() } @@ -25,7 +25,7 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod } // UpdateWebhook to update webhook -func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { webhook.UpdatedAt = time.Now().Unix() // Event is changed if !strings.Contains(webhook.EventName, "-") { @@ -35,7 +35,7 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (* } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) { +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { return nil, nil } diff --git a/server/db/providers/provider_template/webhook_log.go b/server/db/providers/provider_template/webhook_log.go index 9814bc3..9ad81d2 100644 --- a/server/db/providers/provider_template/webhook_log.go +++ b/server/db/providers/provider_template/webhook_log.go @@ -10,7 +10,7 @@ import ( ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } @@ -22,6 +22,6 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookL } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) { +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { return nil, nil } diff --git a/server/db/providers/providers.go b/server/db/providers/providers.go index 28fbf78..65b9010 100644 --- a/server/db/providers/providers.go +++ b/server/db/providers/providers.go @@ -9,50 +9,52 @@ import ( type Provider interface { // AddUser to save user information in database - AddUser(ctx context.Context, user models.User) (models.User, error) + AddUser(ctx context.Context, user *models.User) (*models.User, error) // UpdateUser to update user information in database - UpdateUser(ctx context.Context, user models.User) (models.User, error) + UpdateUser(ctx context.Context, user *models.User) (*models.User, error) // DeleteUser to delete user information from database - DeleteUser(ctx context.Context, user models.User) error + DeleteUser(ctx context.Context, user *models.User) error // ListUsers to get list of users from database - ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) + ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) // GetUserByEmail to get user information from database using email address - GetUserByEmail(ctx context.Context, email string) (models.User, error) + GetUserByEmail(ctx context.Context, email string) (*models.User, error) // GetUserByPhoneNumber to get user information from database using phone number GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) // GetUserByID to get user information from database using user ID - GetUserByID(ctx context.Context, id string) (models.User, error) + GetUserByID(ctx context.Context, id string) (*models.User, error) // UpdateUsers to update multiple users, with parameters of user IDs slice // If ids set to nil / empty all the users will be updated UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error // AddVerification 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(ctx context.Context, token string) (models.VerificationRequest, error) + GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) // GetVerificationRequestByEmail to get verification request by email from database - GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) + GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) // ListVerificationRequests to get list of verification requests from database - ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) + ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) // DeleteVerificationRequest to delete verification request from database - DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error + DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error // AddSession to save session information in database - AddSession(ctx context.Context, session models.Session) error + AddSession(ctx context.Context, session *models.Session) error + // DeleteSession to delete session information from database + DeleteSession(ctx context.Context, userId string) error // AddEnv to save environment information in database - AddEnv(ctx context.Context, env models.Env) (models.Env, error) + AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) // UpdateEnv to update environment information in database - UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) + UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) // GetEnv to get environment information from database - GetEnv(ctx context.Context) (models.Env, error) + GetEnv(ctx context.Context) (*models.Env, error) // AddWebhook to add webhook - 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(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) + UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) // ListWebhooks 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(ctx context.Context, webhookID string) (*model.Webhook, error) // GetWebhookByEventName to get webhook by event_name @@ -61,16 +63,16 @@ type Provider interface { DeleteWebhook(ctx context.Context, webhook *model.Webhook) error // AddWebhookLog to add webhook log - AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) + AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) // ListWebhookLogs to list webhook logs - ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) + ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) // AddEmailTemplate to add EmailTemplate - 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(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) + UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) // ListEmailTemplates 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(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) // GetEmailTemplateByEventName to get EmailTemplate by event_name @@ -82,13 +84,8 @@ type Provider interface { UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, error) // GetOTPByEmail to get otp for a given email address GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) + // GetOTPByPhoneNumber to get otp for a given phone number + GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) // DeleteOTP to delete otp DeleteOTP(ctx context.Context, otp *models.OTP) error - - // Upsert SMS code request - UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) - // Get sms code by phone number - GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) - // Delete sms - DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error } diff --git a/server/db/providers/sql/email_template.go b/server/db/providers/sql/email_template.go index 1a8e0d2..8928b6f 100644 --- a/server/db/providers/sql/email_template.go +++ b/server/db/providers/sql/email_template.go @@ -10,7 +10,7 @@ import ( ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() } @@ -27,7 +27,7 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { emailTemplate.UpdatedAt = time.Now().Unix() res := p.db.Save(&emailTemplate) @@ -38,9 +38,8 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) { - var emailTemplates []models.EmailTemplate - +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { + var emailTemplates []*models.EmailTemplate result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&emailTemplates) if result.Error != nil { return nil, result.Error @@ -60,14 +59,14 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin responseEmailTemplates = append(responseEmailTemplates, w.AsAPIEmailTemplate()) } return &model.EmailTemplates{ - Pagination: &paginationClone, + Pagination: paginationClone, EmailTemplates: responseEmailTemplates, }, nil } // GetEmailTemplateByID to get EmailTemplate by id func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { - var emailTemplate models.EmailTemplate + var emailTemplate *models.EmailTemplate result := p.db.Where("id = ?", emailTemplateID).First(&emailTemplate) if result.Error != nil { @@ -78,7 +77,7 @@ func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID str // GetEmailTemplateByEventName to get EmailTemplate by event_name func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { - var emailTemplate models.EmailTemplate + var emailTemplate *models.EmailTemplate result := p.db.Where("event_name = ?", eventName).First(&emailTemplate) if result.Error != nil { @@ -95,6 +94,5 @@ func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model if result.Error != nil { return result.Error } - return nil } diff --git a/server/db/providers/sql/env.go b/server/db/providers/sql/env.go index 1f34c38..11584a0 100644 --- a/server/db/providers/sql/env.go +++ b/server/db/providers/sql/env.go @@ -9,7 +9,7 @@ import ( ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { if env.ID == "" { env.ID = uuid.New().String() } @@ -26,10 +26,9 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro } // UpdateEnv to update environment information in database -func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) { +func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) { env.UpdatedAt = time.Now().Unix() result := p.db.Save(&env) - if result.Error != nil { return env, result.Error } @@ -37,13 +36,11 @@ func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, e } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (models.Env, error) { - var env models.Env +func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { + var env *models.Env result := p.db.First(&env) - if result.Error != nil { return env, result.Error } - return env, nil } diff --git a/server/db/providers/sql/otp.go b/server/db/providers/sql/otp.go index 9aabcab..5503a7d 100644 --- a/server/db/providers/sql/otp.go +++ b/server/db/providers/sql/otp.go @@ -2,6 +2,7 @@ package sql import ( "context" + "errors" "time" "github.com/authorizerdev/authorizer/server/db/models" @@ -14,13 +15,19 @@ func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, if otp.ID == "" { otp.ID = uuid.New().String() } - + // check if email or phone number is present + if otp.Email == "" && otp.PhoneNumber == "" { + return nil, errors.New("email or phone_number is required") + } + uniqueField := models.FieldNameEmail + if otp.Email == "" && otp.PhoneNumber != "" { + uniqueField = models.FieldNamePhoneNumber + } otp.Key = otp.ID otp.CreatedAt = time.Now().Unix() otp.UpdatedAt = time.Now().Unix() - res := p.db.Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "email"}}, + Columns: []clause.Column{{Name: uniqueField}}, DoUpdates: clause.AssignmentColumns([]string{"otp", "expires_at", "updated_at"}), }).Create(&otp) if res.Error != nil { @@ -33,7 +40,6 @@ func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, // GetOTPByEmail to get otp for a given email address func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { var otp models.OTP - result := p.db.Where("email = ?", emailAddress).First(&otp) if result.Error != nil { return nil, result.Error @@ -41,6 +47,16 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod return &otp, nil } +// GetOTPByPhoneNumber to get otp for a given phone number +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { + var otp models.OTP + result := p.db.Where("phone_number = ?", phoneNumber).First(&otp) + if result.Error != nil { + return nil, result.Error + } + return &otp, nil +} + // DeleteOTP to delete otp func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { result := p.db.Delete(&models.OTP{ diff --git a/server/db/providers/sql/provider.go b/server/db/providers/sql/provider.go index 89ea31b..0512ecf 100644 --- a/server/db/providers/sql/provider.go +++ b/server/db/providers/sql/provider.go @@ -77,7 +77,7 @@ func NewProvider() (*provider, error) { 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{}, &models.SMSVerificationRequest{}) + err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}, &models.Webhook{}, &models.WebhookLog{}, &models.EmailTemplate{}, &models.OTP{}) if err != nil { return nil, err } diff --git a/server/db/providers/sql/session.go b/server/db/providers/sql/session.go index 0ed7317..a7e3e13 100644 --- a/server/db/providers/sql/session.go +++ b/server/db/providers/sql/session.go @@ -10,7 +10,7 @@ import ( ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *models.Session) error { if session.ID == "" { session.ID = uuid.New().String() } @@ -27,3 +27,8 @@ func (p *provider) AddSession(ctx context.Context, session models.Session) error } return nil } + +// DeleteSession to delete session information from database +func (p *provider) DeleteSession(ctx context.Context, userId string) error { + return nil +} diff --git a/server/db/providers/sql/sms_verification_requests.go b/server/db/providers/sql/sms_verification_requests.go deleted file mode 100644 index 5035c54..0000000 --- a/server/db/providers/sql/sms_verification_requests.go +++ /dev/null @@ -1,51 +0,0 @@ -package sql - -import ( - "context" - "time" - - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/google/uuid" - "gorm.io/gorm/clause" -) - -// SMS verification Request -func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) { - if smsRequest.ID == "" { - smsRequest.ID = uuid.New().String() - } - - smsRequest.CreatedAt = time.Now().Unix() - smsRequest.UpdatedAt = time.Now().Unix() - - res := p.db.Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "phone_number"}}, - DoUpdates: clause.AssignmentColumns([]string{"code", "code_expires_at"}), - }).Create(smsRequest) - if res.Error != nil { - return nil, res.Error - } - - return smsRequest, nil -} - -// GetOTPByEmail to get otp for a given email address -func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) { - var sms_verification_request models.SMSVerificationRequest - - result := p.db.Where("phone_number = ?", phoneNumber).First(&sms_verification_request) - if result.Error != nil { - return nil, result.Error - } - return &sms_verification_request, nil -} - -func(p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error { - result := p.db.Delete(&models.SMSVerificationRequest{ - ID: smsRequest.ID, - }) - if result.Error != nil { - return result.Error - } - return nil -} diff --git a/server/db/providers/sql/user.go b/server/db/providers/sql/user.go index a4b40c0..5243ad6 100644 --- a/server/db/providers/sql/user.go +++ b/server/db/providers/sql/user.go @@ -17,7 +17,7 @@ import ( ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { if user.ID == "" { user.ID = uuid.New().String() } @@ -53,7 +53,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, } // 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() result := p.db.Save(&user) @@ -66,7 +66,7 @@ func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.Use } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user models.User) error { +func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { result := p.db.Where("user_id = ?", user.ID).Delete(&models.Session{}) if result.Error != nil { return result.Error @@ -81,7 +81,7 @@ func (p *provider) DeleteUser(ctx context.Context, user models.User) error { } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) { +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { var users []models.User result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&users) if result.Error != nil { @@ -103,31 +103,28 @@ func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) ( paginationClone.Total = total return &model.Users{ - Pagination: &paginationClone, + Pagination: paginationClone, Users: responseUsers, }, nil } // GetUserByEmail to get user information from database using email address -func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) { - var user models.User +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) { + var user *models.User result := p.db.Where("email = ?", email).First(&user) if result.Error != nil { return user, result.Error } - return user, nil } // GetUserByID to get user information from database using user ID -func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) { - var user models.User - +func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) { + var user *models.User result := p.db.Where("id = ?", id).First(&user) if result.Error != nil { return user, result.Error } - return user, nil } @@ -136,14 +133,12 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, err func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error { // set updated_at time for all users data["updated_at"] = time.Now().Unix() - var res *gorm.DB - if ids != nil && len(ids) > 0 { + if len(ids) > 0 { res = p.db.Model(&models.User{}).Where("id in ?", ids).Updates(data) } else { res = p.db.Model(&models.User{}).Updates(data) } - if res.Error != nil { return res.Error } @@ -154,10 +149,8 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) { var user *models.User result := p.db.Where("phone_number = ?", phoneNumber).First(&user) - if result.Error != nil { return nil, result.Error } - return user, nil } diff --git a/server/db/providers/sql/verification_requests.go b/server/db/providers/sql/verification_requests.go index 5b413b0..ac91bec 100644 --- a/server/db/providers/sql/verification_requests.go +++ b/server/db/providers/sql/verification_requests.go @@ -11,11 +11,10 @@ import ( ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() } - verificationRequest.Key = verificationRequest.ID verificationRequest.CreatedAt = time.Now().Unix() verificationRequest.UpdatedAt = time.Now().Unix() @@ -23,75 +22,61 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque Columns: []clause.Column{{Name: "email"}, {Name: "identifier"}}, DoUpdates: clause.AssignmentColumns([]string{"token", "expires_at", "nonce", "redirect_uri"}), }).Create(&verificationRequest) - if result.Error != nil { return verificationRequest, result.Error } - return verificationRequest, nil } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { + var verificationRequest *models.VerificationRequest result := p.db.Where("token = ?", token).First(&verificationRequest) - if result.Error != nil { return verificationRequest, result.Error } - return verificationRequest, nil } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest - +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { + var verificationRequest *models.VerificationRequest result := p.db.Where("email = ? AND identifier = ?", email, identifier).First(&verificationRequest) - if result.Error != nil { return verificationRequest, result.Error } - return verificationRequest, nil } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) { +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { var verificationRequests []models.VerificationRequest - result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&verificationRequests) if result.Error != nil { return nil, result.Error } - responseVerificationRequests := []*model.VerificationRequest{} for _, v := range verificationRequests { responseVerificationRequests = append(responseVerificationRequests, v.AsAPIVerificationRequest()) } - var total int64 totalRes := p.db.Model(&models.VerificationRequest{}).Count(&total) if totalRes.Error != nil { return nil, totalRes.Error } - paginationClone := pagination paginationClone.Total = total - return &model.VerificationRequests{ VerificationRequests: responseVerificationRequests, - Pagination: &paginationClone, + Pagination: paginationClone, }, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error { +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { result := p.db.Delete(&verificationRequest) - if result.Error != nil { return result.Error } - return nil } diff --git a/server/db/providers/sql/webhook.go b/server/db/providers/sql/webhook.go index 72f3cb4..54e2d13 100644 --- a/server/db/providers/sql/webhook.go +++ b/server/db/providers/sql/webhook.go @@ -12,7 +12,7 @@ import ( ) // AddWebhook to add webhook -func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() } @@ -29,7 +29,7 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod } // UpdateWebhook to update webhook -func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) { +func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { webhook.UpdatedAt = time.Now().Unix() // Event is changed if !strings.Contains(webhook.EventName, "-") { @@ -43,7 +43,7 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (* } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) { +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { var webhooks []models.Webhook result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&webhooks) if result.Error != nil { @@ -61,14 +61,14 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) responseWebhooks = append(responseWebhooks, w.AsAPIWebhook()) } return &model.Webhooks{ - Pagination: &paginationClone, + Pagination: paginationClone, Webhooks: responseWebhooks, }, nil } // GetWebhookByID to get webhook by id func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) { - var webhook models.Webhook + var webhook *models.Webhook result := p.db.Where("id = ?", webhookID).First(&webhook) if result.Error != nil { diff --git a/server/db/providers/sql/webhook_log.go b/server/db/providers/sql/webhook_log.go index 0ccbca2..cf50be2 100644 --- a/server/db/providers/sql/webhook_log.go +++ b/server/db/providers/sql/webhook_log.go @@ -12,7 +12,7 @@ import ( ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } @@ -32,7 +32,7 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookL } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) { +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { var webhookLogs []models.WebhookLog var result *gorm.DB var totalRes *gorm.DB @@ -63,6 +63,6 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat } return &model.WebhookLogs{ WebhookLogs: responseWebhookLogs, - Pagination: &paginationClone, + Pagination: paginationClone, }, nil } diff --git a/server/email/email.go b/server/email/email.go index 1b7d84d..e7222ac 100644 --- a/server/email/email.go +++ b/server/email/email.go @@ -72,7 +72,6 @@ func getEmailTemplate(event string, data map[string]interface{}) (*model.EmailTe return nil, err } subjectString := buf.String() - return &model.EmailTemplate{ Template: templateString, Subject: subjectString, diff --git a/server/env/env.go b/server/env/env.go index 45676ac..3f65cf2 100644 --- a/server/env/env.go +++ b/server/env/env.go @@ -19,7 +19,7 @@ import ( // InitEnv to initialize EnvData and through error if required env are not present func InitAllEnv() error { envData, err := GetEnvData() - if err != nil { + if err != nil || envData == nil { log.Info("No env data found in db, using local clone of env data") // get clone of current store envData, err = memorystore.Provider.GetEnvStore() @@ -104,23 +104,22 @@ func InitAllEnv() error { osDisableStrongPassword := os.Getenv(constants.EnvKeyDisableStrongPassword) osEnforceMultiFactorAuthentication := os.Getenv(constants.EnvKeyEnforceMultiFactorAuthentication) osDisableMultiFactorAuthentication := os.Getenv(constants.EnvKeyDisableMultiFactorAuthentication) + // phone verification var + osDisablePhoneVerification := os.Getenv(constants.EnvKeyDisablePhoneVerification) osDisablePlayground := os.Getenv(constants.EnvKeyDisablePlayGround) + // twilio vars + osTwilioApiKey := os.Getenv(constants.EnvKeyTwilioAPIKey) + osTwilioApiSecret := os.Getenv(constants.EnvKeyTwilioAPISecret) + osTwilioAccountSid := os.Getenv(constants.EnvKeyTwilioAccountSID) + osTwilioSender := os.Getenv(constants.EnvKeyTwilioSender) + // os slice vars osAllowedOrigins := os.Getenv(constants.EnvKeyAllowedOrigins) osRoles := os.Getenv(constants.EnvKeyRoles) osDefaultRoles := os.Getenv(constants.EnvKeyDefaultRoles) osProtectedRoles := os.Getenv(constants.EnvKeyProtectedRoles) - // phone verification var - osDisablePhoneVerification := os.Getenv(constants.EnvKeyDisablePhoneVerification) - - // twilio vars - osTwilioApiKey := os.Getenv(constants.EnvKeyTwilioAPIKey) - osTwilioApiSecret := os.Getenv(constants.EnvKeyTwilioAPISecret) - osTwilioAccountSid := os.Getenv(constants.EnvKeyTwilioAccountSID) - osTwilioSenderFrom := os.Getenv(constants.EnvKeyTwilioSenderFrom) - ienv, ok := envData[constants.EnvKeyEnv] if !ok || ienv == "" { envData[constants.EnvKeyEnv] = osEnv @@ -692,11 +691,11 @@ func InitAllEnv() error { envData[constants.EnvKeyIsEmailServiceEnabled] = false } - 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 } - if envData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && !envData[constants.EnvKeyIsEmailServiceEnabled].(bool) { + 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") } @@ -778,29 +777,39 @@ func InitAllEnv() error { envData[constants.EnvKeyDefaultAuthorizeResponseMode] = osAuthorizeResponseMode } + if val, ok := envData[constants.EnvKeyTwilioAPISecret]; !ok || val == "" { + envData[constants.EnvKeyTwilioAPISecret] = osTwilioApiSecret + } if osTwilioApiSecret != "" && envData[constants.EnvKeyTwilioAPISecret] != osTwilioApiSecret { envData[constants.EnvKeyTwilioAPISecret] = osTwilioApiSecret } + if val, ok := envData[constants.EnvKeyTwilioAPIKey]; !ok || val == "" { + envData[constants.EnvKeyTwilioAPIKey] = osTwilioApiKey + } if osTwilioApiKey != "" && envData[constants.EnvKeyTwilioAPIKey] != osTwilioApiKey { envData[constants.EnvKeyTwilioAPIKey] = osTwilioApiKey } + if val, ok := envData[constants.EnvKeyTwilioAccountSID]; !ok || val == "" { + envData[constants.EnvKeyTwilioAccountSID] = osTwilioAccountSid + } if osTwilioAccountSid != "" && envData[constants.EnvKeyTwilioAccountSID] != osTwilioAccountSid { envData[constants.EnvKeyTwilioAccountSID] = osTwilioAccountSid } - if osTwilioSenderFrom != "" && envData[constants.EnvKeyTwilioSenderFrom] != osTwilioSenderFrom { - envData[constants.EnvKeyTwilioSenderFrom] = osTwilioSenderFrom + if val, ok := envData[constants.EnvKeyTwilioSender]; !ok || val == "" { + envData[constants.EnvKeyTwilioSender] = osTwilioSender + } + if osTwilioSender != "" && envData[constants.EnvKeyTwilioSender] != osTwilioSender { + envData[constants.EnvKeyTwilioSender] = osTwilioSender } if _, ok := envData[constants.EnvKeyDisablePhoneVerification]; !ok { envData[constants.EnvKeyDisablePhoneVerification] = osDisablePhoneVerification == "false" } - if osDisablePhoneVerification != "" { boolValue, err := strconv.ParseBool(osDisablePhoneVerification) - if err != nil { return err } @@ -809,6 +818,15 @@ func InitAllEnv() error { } } + if envData[constants.EnvKeyTwilioAPIKey] == "" || envData[constants.EnvKeyTwilioAPISecret] == "" || envData[constants.EnvKeyTwilioAccountSID] == "" || envData[constants.EnvKeyTwilioSender] == "" { + envData[constants.EnvKeyDisablePhoneVerification] = true + envData[constants.EnvKeyIsSMSServiceEnabled] = false + } + if envData[constants.EnvKeyTwilioAPIKey] != "" && envData[constants.EnvKeyTwilioAPISecret] != "" && envData[constants.EnvKeyTwilioAccountSID] != "" && envData[constants.EnvKeyTwilioSender] != "" { + envData[constants.EnvKeyDisablePhoneVerification] = false + envData[constants.EnvKeyIsSMSServiceEnabled] = true + } + if _, ok := envData[constants.EnvKeyDisablePlayGround]; !ok { envData[constants.EnvKeyDisablePlayGround] = osDisablePlayground == "true" } diff --git a/server/env/persist_env.go b/server/env/persist_env.go index c3d4ad1..eb0b64f 100644 --- a/server/env/persist_env.go +++ b/server/env/persist_env.go @@ -62,7 +62,7 @@ func GetEnvData() (map[string]interface{}, error) { ctx := context.Background() env, err := db.Provider.GetEnv(ctx) // config not found in db - if err != nil { + if err != nil || env == nil { log.Debug("Error while getting env data from db: ", err) return result, err } @@ -112,7 +112,7 @@ func PersistEnv() error { ctx := context.Background() env, err := db.Provider.GetEnv(ctx) // config not found in db - if err != nil || env.EnvData == "" { + if err != nil || env == nil { // AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid hash := uuid.New().String()[:36-4] err := memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, hash) @@ -121,25 +121,21 @@ func PersistEnv() error { return err } encodedHash := crypto.EncryptB64(hash) - res, err := memorystore.Provider.GetEnvStore() if err != nil { log.Debug("Error while getting env store: ", err) return err } - encryptedConfig, err := crypto.EncryptEnvData(res) if err != nil { log.Debug("Error while encrypting env data: ", err) return err } - - env = models.Env{ + env = &models.Env{ Hash: encodedHash, EnvData: encryptedConfig, } - - env, err = db.Provider.AddEnv(ctx, env) + _, err = db.Provider.AddEnv(ctx, env) if err != nil { log.Debug("Error while persisting env data to db: ", err) return err @@ -200,7 +196,7 @@ func PersistEnv() error { envValue := strings.TrimSpace(os.Getenv(key)) if envValue != "" { switch key { - case constants.EnvKeyIsProd, constants.EnvKeyDisablePlayGround, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure, constants.EnvKeyDisablePhoneVerification: + 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: if envValueBool, err := strconv.ParseBool(envValue); err == nil { if value.(bool) != envValueBool { storeData[key] = envValueBool diff --git a/server/go.mod b/server/go.mod index 3408404..d1747e2 100644 --- a/server/go.mod +++ b/server/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( github.com/99designs/gqlgen v0.17.20 github.com/arangodb/go-driver v1.2.1 - github.com/aws/aws-sdk-go v1.44.109 + github.com/aws/aws-sdk-go v1.44.298 github.com/coreos/go-oidc/v3 v3.1.0 github.com/couchbase/gocb/v2 v2.6.0 github.com/gin-gonic/gin v1.8.1 @@ -17,7 +17,7 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-cmp v0.5.6 // indirect github.com/google/uuid v1.3.0 - github.com/guregu/dynamo v1.16.0 + github.com/guregu/dynamo v1.20.0 github.com/joho/godotenv v1.3.0 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect @@ -30,7 +30,7 @@ require ( go.mongodb.org/mongo-driver v1.8.1 golang.org/x/crypto v0.4.0 golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 - google.golang.org/appengine v1.6.7 // indirect + google.golang.org/appengine v1.6.7 google.golang.org/protobuf v1.28.1 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/mail.v2 v2.3.1 diff --git a/server/go.sum b/server/go.sum index 224e06d..4a2c928 100644 --- a/server/go.sum +++ b/server/go.sum @@ -51,9 +51,8 @@ github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e h1:Xg+hGrY2 github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e/go.mod h1:mq7Shfa/CaixoDxiyAAc5jZ6CVBAyPaNQCGS7mkj4Ho= 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/aws/aws-sdk-go v1.42.47/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= -github.com/aws/aws-sdk-go v1.44.109 h1:+Na5JPeS0kiEHoBp5Umcuuf+IDqXqD0lXnM920E31YI= -github.com/aws/aws-sdk-go v1.44.109/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.298 h1:5qTxdubgV7PptZJmp/2qDwD2JL187ePL7VOxsSh1i3g= +github.com/aws/aws-sdk-go v1.44.298/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= @@ -63,8 +62,8 @@ github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= -github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -130,8 +129,6 @@ github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gocql/gocql v1.2.0 h1:TZhsCd7fRuye4VyHr3WCvWwIQaZUmjsqnSIXK9FcVCE= github.com/gocql/gocql v1.2.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= -github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= -github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= 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= @@ -206,8 +203,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/guregu/dynamo v1.16.0 h1:gmI8oi1VHwYQtq7+RPBeOiSssVLgxH/Az2t+NtDtL2c= -github.com/guregu/dynamo v1.16.0/go.mod h1:W2Gqcf3MtkrS+Q6fHPGAmRtT0Dyq+TGrqfqrUC9+R/c= +github.com/guregu/dynamo v1.20.0 h1:PDdVVhRSXQFFIHlkhoKF6D8kiwI9IU6uUdz/fF6Iiy4= +github.com/guregu/dynamo v1.20.0/go.mod h1:YQ92BTYVSMIKpFEzhaVqmCJnnSIGxbNF5zvECUaEZRE= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -438,12 +435,12 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -462,8 +459,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc= golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -508,12 +506,16 @@ golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -523,8 +525,10 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/server/graph/generated/generated.go b/server/graph/generated/generated.go index 0175d3d..f323e42 100644 --- a/server/graph/generated/generated.go +++ b/server/graph/generated/generated.go @@ -45,13 +45,14 @@ type DirectiveRoot struct { type ComplexityRoot struct { AuthResponse struct { - AccessToken func(childComplexity int) int - ExpiresIn func(childComplexity int) int - IDToken func(childComplexity int) int - Message func(childComplexity int) int - RefreshToken func(childComplexity int) int - ShouldShowOtpScreen func(childComplexity int) int - User func(childComplexity int) int + AccessToken func(childComplexity int) int + ExpiresIn func(childComplexity int) int + IDToken func(childComplexity int) int + Message func(childComplexity int) int + RefreshToken func(childComplexity int) int + ShouldShowEmailOtpScreen func(childComplexity int) int + ShouldShowMobileOtpScreen func(childComplexity int) int + User func(childComplexity int) int } EmailTemplate struct { @@ -199,7 +200,6 @@ type ComplexityRoot struct { UpdateUser func(childComplexity int, params model.UpdateUserInput) int UpdateWebhook func(childComplexity int, params model.UpdateWebhookRequest) int VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int - VerifyMobile func(childComplexity int, params model.VerifyMobileRequest) int VerifyOtp func(childComplexity int, params model.VerifyOTPRequest) int } @@ -220,6 +220,7 @@ type ComplexityRoot struct { User func(childComplexity int, params model.GetUserRequest) int Users func(childComplexity int, params *model.PaginatedInput) int ValidateJwtToken func(childComplexity int, params model.ValidateJWTTokenInput) int + ValidateSession func(childComplexity int, params *model.ValidateSessionInput) int VerificationRequests func(childComplexity int, params *model.PaginatedInput) int Webhook func(childComplexity int, params model.WebhookRequest) int WebhookLogs func(childComplexity int, params *model.ListWebhookLogRequest) int @@ -245,6 +246,7 @@ type ComplexityRoot struct { } User struct { + AppData func(childComplexity int) int Birthdate func(childComplexity int) int CreatedAt func(childComplexity int) int Email func(childComplexity int) int @@ -276,6 +278,11 @@ type ComplexityRoot struct { IsValid func(childComplexity int) int } + ValidateSessionResponse struct { + IsValid func(childComplexity int) int + User func(childComplexity int) int + } + VerificationRequest struct { CreatedAt func(childComplexity int) int Email func(childComplexity int) int @@ -340,7 +347,6 @@ type MutationResolver interface { Revoke(ctx context.Context, params model.OAuthRevokeInput) (*model.Response, error) VerifyOtp(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error) ResendOtp(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error) - VerifyMobile(ctx context.Context, params model.VerifyMobileRequest) (*model.AuthResponse, error) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error) AdminSignup(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) @@ -364,6 +370,7 @@ type QueryResolver interface { Session(ctx context.Context, params *model.SessionQueryInput) (*model.AuthResponse, error) Profile(ctx context.Context) (*model.User, error) ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) + ValidateSession(ctx context.Context, params *model.ValidateSessionInput) (*model.ValidateSessionResponse, error) Users(ctx context.Context, params *model.PaginatedInput) (*model.Users, error) User(ctx context.Context, params model.GetUserRequest) (*model.User, error) VerificationRequests(ctx context.Context, params *model.PaginatedInput) (*model.VerificationRequests, error) @@ -425,12 +432,19 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.AuthResponse.RefreshToken(childComplexity), true - case "AuthResponse.should_show_otp_screen": - if e.complexity.AuthResponse.ShouldShowOtpScreen == nil { + case "AuthResponse.should_show_email_otp_screen": + if e.complexity.AuthResponse.ShouldShowEmailOtpScreen == nil { break } - return e.complexity.AuthResponse.ShouldShowOtpScreen(childComplexity), true + return e.complexity.AuthResponse.ShouldShowEmailOtpScreen(childComplexity), true + + case "AuthResponse.should_show_mobile_otp_screen": + if e.complexity.AuthResponse.ShouldShowMobileOtpScreen == nil { + break + } + + return e.complexity.AuthResponse.ShouldShowMobileOtpScreen(childComplexity), true case "AuthResponse.user": if e.complexity.AuthResponse.User == nil { @@ -1440,18 +1454,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.VerifyEmail(childComplexity, args["params"].(model.VerifyEmailInput)), true - case "Mutation.verify_mobile": - if e.complexity.Mutation.VerifyMobile == nil { - break - } - - args, err := ec.field_Mutation_verify_mobile_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Mutation.VerifyMobile(childComplexity, args["params"].(model.VerifyMobileRequest)), true - case "Mutation.verify_otp": if e.complexity.Mutation.VerifyOtp == nil { break @@ -1580,6 +1582,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.ValidateJwtToken(childComplexity, args["params"].(model.ValidateJWTTokenInput)), true + case "Query.validate_session": + if e.complexity.Query.ValidateSession == nil { + break + } + + args, err := ec.field_Query_validate_session_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.ValidateSession(childComplexity, args["params"].(*model.ValidateSessionInput)), true + case "Query._verification_requests": if e.complexity.Query.VerificationRequests == nil { break @@ -1691,6 +1705,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.TestEndpointResponse.Response(childComplexity), true + case "User.app_data": + if e.complexity.User.AppData == nil { + break + } + + return e.complexity.User.AppData(childComplexity), true + case "User.birthdate": if e.complexity.User.Birthdate == nil { break @@ -1852,6 +1873,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ValidateJWTTokenResponse.IsValid(childComplexity), true + case "ValidateSessionResponse.is_valid": + if e.complexity.ValidateSessionResponse.IsValid == nil { + break + } + + return e.complexity.ValidateSessionResponse.IsValid(childComplexity), true + + case "ValidateSessionResponse.user": + if e.complexity.ValidateSessionResponse.User == nil { + break + } + + return e.complexity.ValidateSessionResponse.User(childComplexity), true + case "VerificationRequest.created_at": if e.complexity.VerificationRequest.CreatedAt == nil { break @@ -2101,8 +2136,8 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputUpdateUserInput, ec.unmarshalInputUpdateWebhookRequest, ec.unmarshalInputValidateJWTTokenInput, + ec.unmarshalInputValidateSessionInput, ec.unmarshalInputVerifyEmailInput, - ec.unmarshalInputVerifyMobileRequest, ec.unmarshalInputVerifyOTPRequest, ec.unmarshalInputWebhookRequest, ) @@ -2218,6 +2253,7 @@ type User { updated_at: Int64 revoked_timestamp: Int64 is_multi_factor_auth_enabled: Boolean + app_data: Map } type Users { @@ -2251,11 +2287,6 @@ type SMSVerificationRequests { updated_at: Int64 } -input VerifyMobileRequest { - phone_number: String! - code: String! -} - type Error { message: String! reason: String! @@ -2263,7 +2294,8 @@ type Error { type AuthResponse { message: String! - should_show_otp_screen: Boolean + should_show_email_otp_screen: Boolean + should_show_mobile_otp_screen: Boolean access_token: String id_token: String refresh_token: String @@ -2350,6 +2382,11 @@ type ValidateJWTTokenResponse { claims: Map } +type ValidateSessionResponse { + is_valid: Boolean! + user: User! +} + type GenerateJWTKeysResponse { secret: String public_key: String @@ -2491,6 +2528,7 @@ input MobileSignUpInput { # 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 state: String + app_data: Map } input SignUpInput { @@ -2513,6 +2551,7 @@ input SignUpInput { # 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 state: String + app_data: Map } input LoginInput { @@ -2568,6 +2607,7 @@ input UpdateProfileInput { phone_number: String picture: String is_multi_factor_auth_enabled: Boolean + app_data: Map } input UpdateUserInput { @@ -2584,6 +2624,7 @@ input UpdateUserInput { picture: String roles: [String] is_multi_factor_auth_enabled: Boolean + app_data: Map } input ForgotPasswordInput { @@ -2643,6 +2684,11 @@ input ValidateJWTTokenInput { roles: [String!] } +input ValidateSessionInput { + cookie: String! + roles: [String!] +} + input GenerateJWTKeysInput { type: String! } @@ -2676,6 +2722,7 @@ input WebhookRequest { input TestEndpointRequest { endpoint: String! event_name: String! + event_description: String headers: Map } @@ -2703,7 +2750,9 @@ input DeleteEmailTemplateRequest { } input VerifyOTPRequest { - email: String! + # either email or phone_number is required + email: String + phone_number: String otp: String! # state is used for authorization code grant flow # it is used to get code for an on-going auth process during login @@ -2712,7 +2761,8 @@ input VerifyOTPRequest { } input ResendOTPRequest { - email: String! + email: String + phone_number: String # state is used for authorization code grant flow # 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 @@ -2739,7 +2789,6 @@ type Mutation { revoke(params: OAuthRevokeInput!): Response! verify_otp(params: VerifyOTPRequest!): AuthResponse! resend_otp(params: ResendOTPRequest!): Response! - verify_mobile(params: VerifyMobileRequest!): AuthResponse! # admin only apis _delete_user(params: DeleteUserInput!): Response! _update_user(params: UpdateUserInput!): User! @@ -2765,6 +2814,7 @@ type Query { session(params: SessionQueryInput): AuthResponse! profile: User! validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse! + validate_session(params: ValidateSessionInput): ValidateSessionResponse! # admin only apis _users(params: PaginatedInput): Users! _user(params: GetUserRequest!): User! @@ -3204,21 +3254,6 @@ func (ec *executionContext) field_Mutation_verify_email_args(ctx context.Context return args, nil } -func (ec *executionContext) field_Mutation_verify_mobile_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.VerifyMobileRequest - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNVerifyMobileRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerifyMobileRequest(ctx, tmp) - if err != nil { - return nil, err - } - } - args["params"] = arg0 - return args, nil -} - func (ec *executionContext) field_Mutation_verify_otp_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -3384,6 +3419,21 @@ func (ec *executionContext) field_Query_validate_jwt_token_args(ctx context.Cont return args, nil } +func (ec *executionContext) field_Query_validate_session_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *model.ValidateSessionInput + if tmp, ok := rawArgs["params"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + arg0, err = ec.unmarshalOValidateSessionInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateSessionInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["params"] = arg0 + return args, nil +} + func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -3466,8 +3516,8 @@ func (ec *executionContext) fieldContext_AuthResponse_message(ctx context.Contex return fc, nil } -func (ec *executionContext) _AuthResponse_should_show_otp_screen(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field) +func (ec *executionContext) _AuthResponse_should_show_email_otp_screen(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field) if err != nil { return graphql.Null } @@ -3480,7 +3530,7 @@ func (ec *executionContext) _AuthResponse_should_show_otp_screen(ctx context.Con }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.ShouldShowOtpScreen, nil + return obj.ShouldShowEmailOtpScreen, nil }) if err != nil { ec.Error(ctx, err) @@ -3494,7 +3544,48 @@ func (ec *executionContext) _AuthResponse_should_show_otp_screen(ctx context.Con return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_AuthResponse_should_show_otp_screen(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_AuthResponse_should_show_email_otp_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_should_show_mobile_otp_screen(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AuthResponse_should_show_mobile_otp_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.ShouldShowMobileOtpScreen, 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_mobile_otp_screen(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "AuthResponse", Field: field, @@ -3745,6 +3836,8 @@ func (ec *executionContext) fieldContext_AuthResponse_user(ctx context.Context, return ec.fieldContext_User_revoked_timestamp(ctx, field) case "is_multi_factor_auth_enabled": return ec.fieldContext_User_is_multi_factor_auth_enabled(ctx, field) + case "app_data": + return ec.fieldContext_User_app_data(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, @@ -7084,6 +7177,8 @@ func (ec *executionContext) fieldContext_InviteMembersResponse_Users(ctx context return ec.fieldContext_User_revoked_timestamp(ctx, field) case "is_multi_factor_auth_enabled": return ec.fieldContext_User_is_multi_factor_auth_enabled(ctx, field) + case "app_data": + return ec.fieldContext_User_app_data(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, @@ -7792,8 +7887,10 @@ func (ec *executionContext) fieldContext_Mutation_signup(ctx context.Context, fi switch field.Name { case "message": return ec.fieldContext_AuthResponse_message(ctx, field) - case "should_show_otp_screen": - return ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field) + case "should_show_email_otp_screen": + return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field) + case "should_show_mobile_otp_screen": + return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field) case "access_token": return ec.fieldContext_AuthResponse_access_token(ctx, field) case "id_token": @@ -7863,8 +7960,10 @@ func (ec *executionContext) fieldContext_Mutation_mobile_signup(ctx context.Cont switch field.Name { case "message": return ec.fieldContext_AuthResponse_message(ctx, field) - case "should_show_otp_screen": - return ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field) + case "should_show_email_otp_screen": + return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field) + case "should_show_mobile_otp_screen": + return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field) case "access_token": return ec.fieldContext_AuthResponse_access_token(ctx, field) case "id_token": @@ -7934,8 +8033,10 @@ func (ec *executionContext) fieldContext_Mutation_login(ctx context.Context, fie switch field.Name { case "message": return ec.fieldContext_AuthResponse_message(ctx, field) - case "should_show_otp_screen": - return ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field) + case "should_show_email_otp_screen": + return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field) + case "should_show_mobile_otp_screen": + return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field) case "access_token": return ec.fieldContext_AuthResponse_access_token(ctx, field) case "id_token": @@ -8005,8 +8106,10 @@ func (ec *executionContext) fieldContext_Mutation_mobile_login(ctx context.Conte switch field.Name { case "message": return ec.fieldContext_AuthResponse_message(ctx, field) - case "should_show_otp_screen": - return ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field) + case "should_show_email_otp_screen": + return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field) + case "should_show_mobile_otp_screen": + return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field) case "access_token": return ec.fieldContext_AuthResponse_access_token(ctx, field) case "id_token": @@ -8242,8 +8345,10 @@ func (ec *executionContext) fieldContext_Mutation_verify_email(ctx context.Conte switch field.Name { case "message": return ec.fieldContext_AuthResponse_message(ctx, field) - case "should_show_otp_screen": - return ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field) + case "should_show_email_otp_screen": + return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field) + case "should_show_mobile_otp_screen": + return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field) case "access_token": return ec.fieldContext_AuthResponse_access_token(ctx, field) case "id_token": @@ -8549,8 +8654,10 @@ func (ec *executionContext) fieldContext_Mutation_verify_otp(ctx context.Context switch field.Name { case "message": return ec.fieldContext_AuthResponse_message(ctx, field) - case "should_show_otp_screen": - return ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field) + case "should_show_email_otp_screen": + return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field) + case "should_show_mobile_otp_screen": + return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field) case "access_token": return ec.fieldContext_AuthResponse_access_token(ctx, field) case "id_token": @@ -8638,77 +8745,6 @@ func (ec *executionContext) fieldContext_Mutation_resend_otp(ctx context.Context return fc, nil } -func (ec *executionContext) _Mutation_verify_mobile(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_verify_mobile(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 ec.resolvers.Mutation().VerifyMobile(rctx, fc.Args["params"].(model.VerifyMobileRequest)) - }) - 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.(*model.AuthResponse) - fc.Result = res - return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_verify_mobile(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "message": - return ec.fieldContext_AuthResponse_message(ctx, field) - case "should_show_otp_screen": - return ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field) - case "access_token": - return ec.fieldContext_AuthResponse_access_token(ctx, field) - case "id_token": - return ec.fieldContext_AuthResponse_id_token(ctx, field) - case "refresh_token": - return ec.fieldContext_AuthResponse_refresh_token(ctx, field) - case "expires_in": - return ec.fieldContext_AuthResponse_expires_in(ctx, field) - case "user": - return ec.fieldContext_AuthResponse_user(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_verify_mobile_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - func (ec *executionContext) _Mutation__delete_user(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Mutation__delete_user(ctx, field) if err != nil { @@ -8845,6 +8881,8 @@ func (ec *executionContext) fieldContext_Mutation__update_user(ctx context.Conte return ec.fieldContext_User_revoked_timestamp(ctx, field) case "is_multi_factor_auth_enabled": return ec.fieldContext_User_is_multi_factor_auth_enabled(ctx, field) + case "app_data": + return ec.fieldContext_User_app_data(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, @@ -10038,8 +10076,10 @@ func (ec *executionContext) fieldContext_Query_session(ctx context.Context, fiel switch field.Name { case "message": return ec.fieldContext_AuthResponse_message(ctx, field) - case "should_show_otp_screen": - return ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field) + case "should_show_email_otp_screen": + return ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field) + case "should_show_mobile_otp_screen": + return ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field) case "access_token": return ec.fieldContext_AuthResponse_access_token(ctx, field) case "id_token": @@ -10145,6 +10185,8 @@ func (ec *executionContext) fieldContext_Query_profile(ctx context.Context, fiel return ec.fieldContext_User_revoked_timestamp(ctx, field) case "is_multi_factor_auth_enabled": return ec.fieldContext_User_is_multi_factor_auth_enabled(ctx, field) + case "app_data": + return ec.fieldContext_User_app_data(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, @@ -10213,6 +10255,67 @@ func (ec *executionContext) fieldContext_Query_validate_jwt_token(ctx context.Co return fc, nil } +func (ec *executionContext) _Query_validate_session(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_validate_session(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 ec.resolvers.Query().ValidateSession(rctx, fc.Args["params"].(*model.ValidateSessionInput)) + }) + 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.(*model.ValidateSessionResponse) + fc.Result = res + return ec.marshalNValidateSessionResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateSessionResponse(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_validate_session(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "is_valid": + return ec.fieldContext_ValidateSessionResponse_is_valid(ctx, field) + case "user": + return ec.fieldContext_ValidateSessionResponse_user(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ValidateSessionResponse", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_validate_session_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return + } + return fc, nil +} + func (ec *executionContext) _Query__users(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query__users(ctx, field) if err != nil { @@ -10351,6 +10454,8 @@ func (ec *executionContext) fieldContext_Query__user(ctx context.Context, field return ec.fieldContext_User_revoked_timestamp(ctx, field) case "is_multi_factor_auth_enabled": return ec.fieldContext_User_is_multi_factor_auth_enabled(ctx, field) + case "app_data": + return ec.fieldContext_User_app_data(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, @@ -12214,6 +12319,47 @@ func (ec *executionContext) fieldContext_User_is_multi_factor_auth_enabled(ctx c return fc, nil } +func (ec *executionContext) _User_app_data(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_User_app_data(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.AppData, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_User_app_data(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "User", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Map does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Users_pagination(ctx context.Context, field graphql.CollectedField, obj *model.Users) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Users_pagination(ctx, field) if err != nil { @@ -12345,6 +12491,8 @@ func (ec *executionContext) fieldContext_Users_users(ctx context.Context, field return ec.fieldContext_User_revoked_timestamp(ctx, field) case "is_multi_factor_auth_enabled": return ec.fieldContext_User_is_multi_factor_auth_enabled(ctx, field) + case "app_data": + return ec.fieldContext_User_app_data(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, @@ -12437,6 +12585,136 @@ func (ec *executionContext) fieldContext_ValidateJWTTokenResponse_claims(ctx con return fc, nil } +func (ec *executionContext) _ValidateSessionResponse_is_valid(ctx context.Context, field graphql.CollectedField, obj *model.ValidateSessionResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ValidateSessionResponse_is_valid(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.IsValid, 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_ValidateSessionResponse_is_valid(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ValidateSessionResponse", + 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) _ValidateSessionResponse_user(ctx context.Context, field graphql.CollectedField, obj *model.ValidateSessionResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ValidateSessionResponse_user(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.User, 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.(*model.User) + fc.Result = res + return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ValidateSessionResponse_user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ValidateSessionResponse", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "email": + return ec.fieldContext_User_email(ctx, field) + case "email_verified": + return ec.fieldContext_User_email_verified(ctx, field) + case "signup_methods": + return ec.fieldContext_User_signup_methods(ctx, field) + case "given_name": + return ec.fieldContext_User_given_name(ctx, field) + case "family_name": + return ec.fieldContext_User_family_name(ctx, field) + case "middle_name": + return ec.fieldContext_User_middle_name(ctx, field) + case "nickname": + return ec.fieldContext_User_nickname(ctx, field) + case "preferred_username": + return ec.fieldContext_User_preferred_username(ctx, field) + case "gender": + return ec.fieldContext_User_gender(ctx, field) + case "birthdate": + return ec.fieldContext_User_birthdate(ctx, field) + case "phone_number": + return ec.fieldContext_User_phone_number(ctx, field) + case "phone_number_verified": + return ec.fieldContext_User_phone_number_verified(ctx, field) + case "picture": + return ec.fieldContext_User_picture(ctx, field) + case "roles": + return ec.fieldContext_User_roles(ctx, field) + case "created_at": + return ec.fieldContext_User_created_at(ctx, field) + case "updated_at": + return ec.fieldContext_User_updated_at(ctx, field) + case "revoked_timestamp": + return ec.fieldContext_User_revoked_timestamp(ctx, field) + case "is_multi_factor_auth_enabled": + return ec.fieldContext_User_is_multi_factor_auth_enabled(ctx, field) + case "app_data": + return ec.fieldContext_User_app_data(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _VerificationRequest_id(ctx context.Context, field graphql.CollectedField, obj *model.VerificationRequest) (ret graphql.Marshaler) { fc, err := ec.fieldContext_VerificationRequest_id(ctx, field) if err != nil { @@ -16142,7 +16420,7 @@ func (ec *executionContext) unmarshalInputMobileSignUpInput(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"email", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "password", "confirm_password", "roles", "scope", "redirect_uri", "is_multi_factor_auth_enabled", "state"} + fieldsInOrder := [...]string{"email", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "password", "confirm_password", "roles", "scope", "redirect_uri", "is_multi_factor_auth_enabled", "state", "app_data"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -16277,6 +16555,14 @@ func (ec *executionContext) unmarshalInputMobileSignUpInput(ctx context.Context, if err != nil { return it, err } + case "app_data": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("app_data")) + it.AppData, err = ec.unmarshalOMap2map(ctx, v) + if err != nil { + return it, err + } } } @@ -16382,7 +16668,7 @@ func (ec *executionContext) unmarshalInputResendOTPRequest(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"email", "state"} + fieldsInOrder := [...]string{"email", "phone_number", "state"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -16393,7 +16679,15 @@ func (ec *executionContext) unmarshalInputResendOTPRequest(ctx context.Context, var err error ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) - it.Email, err = ec.unmarshalNString2string(ctx, v) + it.Email, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "phone_number": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number")) + it.PhoneNumber, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } @@ -16542,7 +16836,7 @@ func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj i asMap[k] = v } - fieldsInOrder := [...]string{"email", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "password", "confirm_password", "roles", "scope", "redirect_uri", "is_multi_factor_auth_enabled", "state"} + fieldsInOrder := [...]string{"email", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "password", "confirm_password", "roles", "scope", "redirect_uri", "is_multi_factor_auth_enabled", "state", "app_data"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -16677,6 +16971,14 @@ func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj i if err != nil { return it, err } + case "app_data": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("app_data")) + it.AppData, err = ec.unmarshalOMap2map(ctx, v) + if err != nil { + return it, err + } } } @@ -16690,7 +16992,7 @@ func (ec *executionContext) unmarshalInputTestEndpointRequest(ctx context.Contex asMap[k] = v } - fieldsInOrder := [...]string{"endpoint", "event_name", "headers"} + fieldsInOrder := [...]string{"endpoint", "event_name", "event_description", "headers"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -16713,6 +17015,14 @@ func (ec *executionContext) unmarshalInputTestEndpointRequest(ctx context.Contex if err != nil { return it, err } + case "event_description": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("event_description")) + it.EventDescription, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } case "headers": var err error @@ -17266,7 +17576,7 @@ func (ec *executionContext) unmarshalInputUpdateProfileInput(ctx context.Context asMap[k] = v } - fieldsInOrder := [...]string{"old_password", "new_password", "confirm_new_password", "email", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "is_multi_factor_auth_enabled"} + fieldsInOrder := [...]string{"old_password", "new_password", "confirm_new_password", "email", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "is_multi_factor_auth_enabled", "app_data"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -17377,6 +17687,14 @@ func (ec *executionContext) unmarshalInputUpdateProfileInput(ctx context.Context if err != nil { return it, err } + case "app_data": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("app_data")) + it.AppData, err = ec.unmarshalOMap2map(ctx, v) + if err != nil { + return it, err + } } } @@ -17390,7 +17708,7 @@ func (ec *executionContext) unmarshalInputUpdateUserInput(ctx context.Context, o asMap[k] = v } - fieldsInOrder := [...]string{"id", "email", "email_verified", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "roles", "is_multi_factor_auth_enabled"} + fieldsInOrder := [...]string{"id", "email", "email_verified", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "roles", "is_multi_factor_auth_enabled", "app_data"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -17501,6 +17819,14 @@ func (ec *executionContext) unmarshalInputUpdateUserInput(ctx context.Context, o if err != nil { return it, err } + case "app_data": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("app_data")) + it.AppData, err = ec.unmarshalOMap2map(ctx, v) + if err != nil { + return it, err + } } } @@ -17619,6 +17945,42 @@ func (ec *executionContext) unmarshalInputValidateJWTTokenInput(ctx context.Cont return it, nil } +func (ec *executionContext) unmarshalInputValidateSessionInput(ctx context.Context, obj interface{}) (model.ValidateSessionInput, error) { + var it model.ValidateSessionInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"cookie", "roles"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "cookie": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("cookie")) + it.Cookie, err = ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + case "roles": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roles")) + it.Roles, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputVerifyEmailInput(ctx context.Context, obj interface{}) (model.VerifyEmailInput, error) { var it model.VerifyEmailInput asMap := map[string]interface{}{} @@ -17655,42 +18017,6 @@ func (ec *executionContext) unmarshalInputVerifyEmailInput(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputVerifyMobileRequest(ctx context.Context, obj interface{}) (model.VerifyMobileRequest, error) { - var it model.VerifyMobileRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"phone_number", "code"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "phone_number": - var err error - - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number")) - it.PhoneNumber, err = ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - case "code": - var err error - - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("code")) - it.Code, err = ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - } - } - - return it, nil -} - func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context, obj interface{}) (model.VerifyOTPRequest, error) { var it model.VerifyOTPRequest asMap := map[string]interface{}{} @@ -17698,7 +18024,7 @@ func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"email", "otp", "state"} + fieldsInOrder := [...]string{"email", "phone_number", "otp", "state"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -17709,7 +18035,15 @@ func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context, var err error ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) - it.Email, err = ec.unmarshalNString2string(ctx, v) + it.Email, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "phone_number": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number")) + it.PhoneNumber, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } @@ -17788,9 +18122,13 @@ func (ec *executionContext) _AuthResponse(ctx context.Context, sel ast.Selection if out.Values[i] == graphql.Null { invalids++ } - case "should_show_otp_screen": + case "should_show_email_otp_screen": - out.Values[i] = ec._AuthResponse_should_show_otp_screen(ctx, field, obj) + out.Values[i] = ec._AuthResponse_should_show_email_otp_screen(ctx, field, obj) + + case "should_show_mobile_otp_screen": + + out.Values[i] = ec._AuthResponse_should_show_mobile_otp_screen(ctx, field, obj) case "access_token": @@ -18604,15 +18942,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) return ec._Mutation_resend_otp(ctx, field) }) - if out.Values[i] == graphql.Null { - invalids++ - } - case "verify_mobile": - - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_verify_mobile(ctx, field) - }) - if out.Values[i] == graphql.Null { invalids++ } @@ -18937,6 +19266,29 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) } + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) + }) + case "validate_session": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_validate_session(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + out.Concurrently(i, func() graphql.Marshaler { return rrm(innerCtx) }) @@ -19388,6 +19740,10 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj out.Values[i] = ec._User_is_multi_factor_auth_enabled(ctx, field, obj) + case "app_data": + + out.Values[i] = ec._User_app_data(ctx, field, obj) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -19466,6 +19822,41 @@ func (ec *executionContext) _ValidateJWTTokenResponse(ctx context.Context, sel a return out } +var validateSessionResponseImplementors = []string{"ValidateSessionResponse"} + +func (ec *executionContext) _ValidateSessionResponse(ctx context.Context, sel ast.SelectionSet, obj *model.ValidateSessionResponse) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, validateSessionResponseImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ValidateSessionResponse") + case "is_valid": + + out.Values[i] = ec._ValidateSessionResponse_is_valid(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "user": + + out.Values[i] = ec._ValidateSessionResponse_user(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var verificationRequestImplementors = []string{"VerificationRequest"} func (ec *executionContext) _VerificationRequest(ctx context.Context, sel ast.SelectionSet, obj *model.VerificationRequest) graphql.Marshaler { @@ -20541,6 +20932,20 @@ func (ec *executionContext) marshalNValidateJWTTokenResponse2ᚖgithubᚗcomᚋa return ec._ValidateJWTTokenResponse(ctx, sel, v) } +func (ec *executionContext) marshalNValidateSessionResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateSessionResponse(ctx context.Context, sel ast.SelectionSet, v model.ValidateSessionResponse) graphql.Marshaler { + return ec._ValidateSessionResponse(ctx, sel, &v) +} + +func (ec *executionContext) marshalNValidateSessionResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateSessionResponse(ctx context.Context, sel ast.SelectionSet, v *model.ValidateSessionResponse) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._ValidateSessionResponse(ctx, sel, v) +} + func (ec *executionContext) marshalNVerificationRequest2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerificationRequestᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.VerificationRequest) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup @@ -20614,11 +21019,6 @@ func (ec *executionContext) unmarshalNVerifyEmailInput2githubᚗcomᚋauthorizer return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNVerifyMobileRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerifyMobileRequest(ctx context.Context, v interface{}) (model.VerifyMobileRequest, error) { - res, err := ec.unmarshalInputVerifyMobileRequest(ctx, v) - return res, graphql.ErrorOnPath(ctx, err) -} - func (ec *executionContext) unmarshalNVerifyOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerifyOTPRequest(ctx context.Context, v interface{}) (model.VerifyOTPRequest, error) { res, err := ec.unmarshalInputVerifyOTPRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -21229,6 +21629,14 @@ func (ec *executionContext) marshalOUser2ᚖgithubᚗcomᚋauthorizerdevᚋautho return ec._User(ctx, sel, v) } +func (ec *executionContext) unmarshalOValidateSessionInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateSessionInput(ctx context.Context, v interface{}) (*model.ValidateSessionInput, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputValidateSessionInput(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/server/graph/model/models_gen.go b/server/graph/model/models_gen.go index 47fbb1e..a76b0e3 100644 --- a/server/graph/model/models_gen.go +++ b/server/graph/model/models_gen.go @@ -26,13 +26,14 @@ type AdminSignupInput struct { } type AuthResponse struct { - Message string `json:"message"` - ShouldShowOtpScreen *bool `json:"should_show_otp_screen"` - AccessToken *string `json:"access_token"` - IDToken *string `json:"id_token"` - RefreshToken *string `json:"refresh_token"` - ExpiresIn *int64 `json:"expires_in"` - User *User `json:"user"` + Message string `json:"message"` + ShouldShowEmailOtpScreen *bool `json:"should_show_email_otp_screen"` + ShouldShowMobileOtpScreen *bool `json:"should_show_mobile_otp_screen"` + AccessToken *string `json:"access_token"` + IDToken *string `json:"id_token"` + RefreshToken *string `json:"refresh_token"` + ExpiresIn *int64 `json:"expires_in"` + User *User `json:"user"` } type DeleteEmailTemplateRequest struct { @@ -120,7 +121,6 @@ type Env struct { AdminCookieSecure bool `json:"ADMIN_COOKIE_SECURE"` DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE"` DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE"` - DisablePlayground bool `json:"DISABLE_PLAYGROUND"` } type Error struct { @@ -207,22 +207,23 @@ type MobileLoginInput struct { } type MobileSignUpInput struct { - Email *string `json:"email"` - GivenName *string `json:"given_name"` - FamilyName *string `json:"family_name"` - MiddleName *string `json:"middle_name"` - Nickname *string `json:"nickname"` - Gender *string `json:"gender"` - Birthdate *string `json:"birthdate"` - PhoneNumber string `json:"phone_number"` - Picture *string `json:"picture"` - Password string `json:"password"` - ConfirmPassword string `json:"confirm_password"` - Roles []string `json:"roles"` - Scope []string `json:"scope"` - RedirectURI *string `json:"redirect_uri"` - IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"` - State *string `json:"state"` + Email *string `json:"email"` + GivenName *string `json:"given_name"` + FamilyName *string `json:"family_name"` + MiddleName *string `json:"middle_name"` + Nickname *string `json:"nickname"` + Gender *string `json:"gender"` + Birthdate *string `json:"birthdate"` + PhoneNumber string `json:"phone_number"` + Picture *string `json:"picture"` + Password string `json:"password"` + ConfirmPassword string `json:"confirm_password"` + Roles []string `json:"roles"` + Scope []string `json:"scope"` + RedirectURI *string `json:"redirect_uri"` + IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"` + State *string `json:"state"` + AppData map[string]interface{} `json:"app_data"` } type OAuthRevokeInput struct { @@ -246,8 +247,9 @@ type PaginationInput struct { } type ResendOTPRequest struct { - Email string `json:"email"` - State *string `json:"state"` + Email *string `json:"email"` + PhoneNumber *string `json:"phone_number"` + State *string `json:"state"` } type ResendVerifyEmailInput struct { @@ -281,28 +283,30 @@ type SessionQueryInput struct { } type SignUpInput struct { - Email string `json:"email"` - GivenName *string `json:"given_name"` - FamilyName *string `json:"family_name"` - MiddleName *string `json:"middle_name"` - Nickname *string `json:"nickname"` - Gender *string `json:"gender"` - Birthdate *string `json:"birthdate"` - PhoneNumber *string `json:"phone_number"` - Picture *string `json:"picture"` - Password string `json:"password"` - ConfirmPassword string `json:"confirm_password"` - Roles []string `json:"roles"` - Scope []string `json:"scope"` - RedirectURI *string `json:"redirect_uri"` - IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"` - State *string `json:"state"` + Email string `json:"email"` + GivenName *string `json:"given_name"` + FamilyName *string `json:"family_name"` + MiddleName *string `json:"middle_name"` + Nickname *string `json:"nickname"` + Gender *string `json:"gender"` + Birthdate *string `json:"birthdate"` + PhoneNumber *string `json:"phone_number"` + Picture *string `json:"picture"` + Password string `json:"password"` + ConfirmPassword string `json:"confirm_password"` + Roles []string `json:"roles"` + Scope []string `json:"scope"` + RedirectURI *string `json:"redirect_uri"` + IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"` + State *string `json:"state"` + AppData map[string]interface{} `json:"app_data"` } type TestEndpointRequest struct { - Endpoint string `json:"endpoint"` - EventName string `json:"event_name"` - Headers map[string]interface{} `json:"headers"` + Endpoint string `json:"endpoint"` + EventName string `json:"event_name"` + EventDescription *string `json:"event_description"` + Headers map[string]interface{} `json:"headers"` } type TestEndpointResponse struct { @@ -375,39 +379,40 @@ type UpdateEnvInput struct { OrganizationLogo *string `json:"ORGANIZATION_LOGO"` DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE"` DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE"` - DisablePlayground *bool `json:"DISABLE_PLAYGROUND"` } type UpdateProfileInput struct { - OldPassword *string `json:"old_password"` - NewPassword *string `json:"new_password"` - ConfirmNewPassword *string `json:"confirm_new_password"` - Email *string `json:"email"` - GivenName *string `json:"given_name"` - FamilyName *string `json:"family_name"` - MiddleName *string `json:"middle_name"` - Nickname *string `json:"nickname"` - Gender *string `json:"gender"` - Birthdate *string `json:"birthdate"` - PhoneNumber *string `json:"phone_number"` - Picture *string `json:"picture"` - IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"` + OldPassword *string `json:"old_password"` + NewPassword *string `json:"new_password"` + ConfirmNewPassword *string `json:"confirm_new_password"` + Email *string `json:"email"` + GivenName *string `json:"given_name"` + FamilyName *string `json:"family_name"` + MiddleName *string `json:"middle_name"` + Nickname *string `json:"nickname"` + Gender *string `json:"gender"` + Birthdate *string `json:"birthdate"` + PhoneNumber *string `json:"phone_number"` + Picture *string `json:"picture"` + IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"` + AppData map[string]interface{} `json:"app_data"` } type UpdateUserInput struct { - ID string `json:"id"` - Email *string `json:"email"` - EmailVerified *bool `json:"email_verified"` - GivenName *string `json:"given_name"` - FamilyName *string `json:"family_name"` - MiddleName *string `json:"middle_name"` - Nickname *string `json:"nickname"` - Gender *string `json:"gender"` - Birthdate *string `json:"birthdate"` - PhoneNumber *string `json:"phone_number"` - Picture *string `json:"picture"` - Roles []*string `json:"roles"` - IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"` + ID string `json:"id"` + Email *string `json:"email"` + EmailVerified *bool `json:"email_verified"` + GivenName *string `json:"given_name"` + FamilyName *string `json:"family_name"` + MiddleName *string `json:"middle_name"` + Nickname *string `json:"nickname"` + Gender *string `json:"gender"` + Birthdate *string `json:"birthdate"` + PhoneNumber *string `json:"phone_number"` + Picture *string `json:"picture"` + Roles []*string `json:"roles"` + IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"` + AppData map[string]interface{} `json:"app_data"` } type UpdateWebhookRequest struct { @@ -420,25 +425,26 @@ type UpdateWebhookRequest struct { } type User struct { - ID string `json:"id"` - Email string `json:"email"` - EmailVerified bool `json:"email_verified"` - SignupMethods string `json:"signup_methods"` - GivenName *string `json:"given_name"` - FamilyName *string `json:"family_name"` - MiddleName *string `json:"middle_name"` - Nickname *string `json:"nickname"` - PreferredUsername *string `json:"preferred_username"` - Gender *string `json:"gender"` - Birthdate *string `json:"birthdate"` - PhoneNumber *string `json:"phone_number"` - PhoneNumberVerified *bool `json:"phone_number_verified"` - Picture *string `json:"picture"` - Roles []string `json:"roles"` - CreatedAt *int64 `json:"created_at"` - UpdatedAt *int64 `json:"updated_at"` - RevokedTimestamp *int64 `json:"revoked_timestamp"` - IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"` + ID string `json:"id"` + Email string `json:"email"` + EmailVerified bool `json:"email_verified"` + SignupMethods string `json:"signup_methods"` + GivenName *string `json:"given_name"` + FamilyName *string `json:"family_name"` + MiddleName *string `json:"middle_name"` + Nickname *string `json:"nickname"` + PreferredUsername *string `json:"preferred_username"` + Gender *string `json:"gender"` + Birthdate *string `json:"birthdate"` + PhoneNumber *string `json:"phone_number"` + PhoneNumberVerified *bool `json:"phone_number_verified"` + Picture *string `json:"picture"` + Roles []string `json:"roles"` + CreatedAt *int64 `json:"created_at"` + UpdatedAt *int64 `json:"updated_at"` + RevokedTimestamp *int64 `json:"revoked_timestamp"` + IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"` + AppData map[string]interface{} `json:"app_data"` } type Users struct { @@ -457,6 +463,16 @@ type ValidateJWTTokenResponse struct { Claims map[string]interface{} `json:"claims"` } +type ValidateSessionInput struct { + Cookie string `json:"cookie"` + Roles []string `json:"roles"` +} + +type ValidateSessionResponse struct { + IsValid bool `json:"is_valid"` + User *User `json:"user"` +} + type VerificationRequest struct { ID string `json:"id"` Identifier *string `json:"identifier"` @@ -479,15 +495,11 @@ type VerifyEmailInput struct { State *string `json:"state"` } -type VerifyMobileRequest struct { - PhoneNumber string `json:"phone_number"` - Code string `json:"code"` -} - type VerifyOTPRequest struct { - Email string `json:"email"` - Otp string `json:"otp"` - State *string `json:"state"` + Email *string `json:"email"` + PhoneNumber *string `json:"phone_number"` + Otp string `json:"otp"` + State *string `json:"state"` } type Webhook struct { diff --git a/server/graph/schema.graphqls b/server/graph/schema.graphqls index 0ca3d2e..1c7de22 100644 --- a/server/graph/schema.graphqls +++ b/server/graph/schema.graphqls @@ -51,6 +51,7 @@ type User { updated_at: Int64 revoked_timestamp: Int64 is_multi_factor_auth_enabled: Boolean + app_data: Map } type Users { @@ -84,11 +85,6 @@ type SMSVerificationRequests { updated_at: Int64 } -input VerifyMobileRequest { - phone_number: String! - code: String! -} - type Error { message: String! reason: String! @@ -96,7 +92,8 @@ type Error { type AuthResponse { message: String! - should_show_otp_screen: Boolean + should_show_email_otp_screen: Boolean + should_show_mobile_otp_screen: Boolean access_token: String id_token: String refresh_token: String @@ -183,6 +180,11 @@ type ValidateJWTTokenResponse { claims: Map } +type ValidateSessionResponse { + is_valid: Boolean! + user: User! +} + type GenerateJWTKeysResponse { secret: String public_key: String @@ -324,6 +326,7 @@ input MobileSignUpInput { # 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 state: String + app_data: Map } input SignUpInput { @@ -346,6 +349,7 @@ input SignUpInput { # 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 state: String + app_data: Map } input LoginInput { @@ -401,6 +405,7 @@ input UpdateProfileInput { phone_number: String picture: String is_multi_factor_auth_enabled: Boolean + app_data: Map } input UpdateUserInput { @@ -417,6 +422,7 @@ input UpdateUserInput { picture: String roles: [String] is_multi_factor_auth_enabled: Boolean + app_data: Map } input ForgotPasswordInput { @@ -476,6 +482,11 @@ input ValidateJWTTokenInput { roles: [String!] } +input ValidateSessionInput { + cookie: String! + roles: [String!] +} + input GenerateJWTKeysInput { type: String! } @@ -509,6 +520,7 @@ input WebhookRequest { input TestEndpointRequest { endpoint: String! event_name: String! + event_description: String headers: Map } @@ -536,7 +548,9 @@ input DeleteEmailTemplateRequest { } input VerifyOTPRequest { - email: String! + # either email or phone_number is required + email: String + phone_number: String otp: String! # state is used for authorization code grant flow # it is used to get code for an on-going auth process during login @@ -545,7 +559,8 @@ input VerifyOTPRequest { } input ResendOTPRequest { - email: String! + email: String + phone_number: String # state is used for authorization code grant flow # 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 @@ -572,7 +587,6 @@ type Mutation { revoke(params: OAuthRevokeInput!): Response! verify_otp(params: VerifyOTPRequest!): AuthResponse! resend_otp(params: ResendOTPRequest!): Response! - verify_mobile(params: VerifyMobileRequest!): AuthResponse! # admin only apis _delete_user(params: DeleteUserInput!): Response! _update_user(params: UpdateUserInput!): User! @@ -598,6 +612,7 @@ type Query { session(params: SessionQueryInput): AuthResponse! profile: User! validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse! + validate_session(params: ValidateSessionInput): ValidateSessionResponse! # admin only apis _users(params: PaginatedInput): Users! _user(params: GetUserRequest!): User! diff --git a/server/graph/schema.resolvers.go b/server/graph/schema.resolvers.go index 75dad85..eecb6b2 100644 --- a/server/graph/schema.resolvers.go +++ b/server/graph/schema.resolvers.go @@ -81,11 +81,6 @@ func (r *mutationResolver) ResendOtp(ctx context.Context, params model.ResendOTP return resolvers.ResendOTPResolver(ctx, params) } -// VerifyMobile is the resolver for the verify_mobile field. -func (r *mutationResolver) VerifyMobile(ctx context.Context, params model.VerifyMobileRequest) (*model.AuthResponse, error) { - return resolvers.VerifyMobileResolver(ctx, params) -} - // DeleteUser is the resolver for the _delete_user field. func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) { return resolvers.DeleteUserResolver(ctx, params) @@ -191,6 +186,11 @@ func (r *queryResolver) ValidateJwtToken(ctx context.Context, params model.Valid return resolvers.ValidateJwtTokenResolver(ctx, params) } +// ValidateSession is the resolver for the validate_session field. +func (r *queryResolver) ValidateSession(ctx context.Context, params *model.ValidateSessionInput) (*model.ValidateSessionResponse, error) { + return resolvers.ValidateSessionResolver(ctx, params) +} + // Users is the resolver for the _users field. func (r *queryResolver) Users(ctx context.Context, params *model.PaginatedInput) (*model.Users, error) { return resolvers.UsersResolver(ctx, params) diff --git a/server/handlers/oauth_callback.go b/server/handlers/oauth_callback.go index 1c547e2..782da41 100644 --- a/server/handlers/oauth_callback.go +++ b/server/handlers/oauth_callback.go @@ -32,11 +32,11 @@ func OAuthCallbackHandler() gin.HandlerFunc { return func(ctx *gin.Context) { provider := ctx.Param("oauth_provider") state := ctx.Request.FormValue("state") - sessionState, err := memorystore.Provider.GetState(state) if sessionState == "" || err != nil { log.Debug("Invalid oauth state: ", state) ctx.JSON(400, gin.H{"error": "invalid oauth state"}) + return } // contains random token, redirect url, role sessionSplit := strings.Split(state, "___") @@ -46,32 +46,34 @@ func OAuthCallbackHandler() gin.HandlerFunc { ctx.JSON(400, gin.H{"error": "invalid redirect url"}) return } - // remove state from store go memorystore.Provider.RemoveState(state) - stateValue := sessionSplit[0] redirectURL := sessionSplit[1] inputRoles := strings.Split(sessionSplit[2], ",") scopes := strings.Split(sessionSplit[3], ",") - - user := models.User{} + var user *models.User oauthCode := ctx.Request.FormValue("code") + if oauthCode == "" { + log.Debug("Invalid oauth code: ", oauthCode) + ctx.JSON(400, gin.H{"error": "invalid oauth code"}) + return + } switch provider { case constants.AuthRecipeMethodGoogle: - user, err = processGoogleUserInfo(oauthCode) + user, err = processGoogleUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodGithub: - user, err = processGithubUserInfo(oauthCode) + user, err = processGithubUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodFacebook: - user, err = processFacebookUserInfo(oauthCode) + user, err = processFacebookUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodLinkedIn: - user, err = processLinkedInUserInfo(oauthCode) + user, err = processLinkedInUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodApple: - user, err = processAppleUserInfo(oauthCode) + user, err = processAppleUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodTwitter: - user, err = processTwitterUserInfo(oauthCode, sessionState) + user, err = processTwitterUserInfo(ctx, oauthCode, sessionState) case constants.AuthRecipeMethodMicrosoft: - user, err = processMicrosoftUserInfo(oauthCode) + user, err = processMicrosoftUserInfo(ctx, oauthCode) default: log.Info("Invalid oauth provider") err = fmt.Errorf(`invalid oauth provider`) @@ -260,10 +262,12 @@ func OAuthCallbackHandler() gin.HandlerFunc { go func() { if isSignUp { utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, provider, user) + // User is also logged in with signup + utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, provider, user) } else { utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, provider, user) } - db.Provider.AddSession(ctx, models.Session{ + db.Provider.AddSession(ctx, &models.Session{ UserID: user.ID, UserAgent: utils.GetUserAgent(ctx.Request), IP: utils.GetIP(ctx.Request), @@ -279,15 +283,13 @@ func OAuthCallbackHandler() gin.HandlerFunc { } } -func processGoogleUserInfo(code string) (models.User, error) { - user := models.User{} - ctx := context.Background() +func processGoogleUserInfo(ctx context.Context, code string) (*models.User, error) { + var user *models.User oauth2Token, err := oauth.OAuthProviders.GoogleConfig.Exchange(ctx, code) if err != nil { log.Debug("Failed to exchange code for token: ", err) return user, fmt.Errorf("invalid google exchange code: %s", err.Error()) } - verifier := oauth.OIDCProviders.GoogleOIDC.Verifier(&oidc.Config{ClientID: oauth.OAuthProviders.GoogleConfig.ClientID}) // Extract the ID Token from OAuth2 token. @@ -312,9 +314,9 @@ func processGoogleUserInfo(code string) (models.User, error) { return user, nil } -func processGithubUserInfo(code string) (models.User, error) { - user := models.User{} - oauth2Token, err := oauth.OAuthProviders.GithubConfig.Exchange(context.TODO(), code) +func processGithubUserInfo(ctx context.Context, code string) (*models.User, error) { + var user *models.User + oauth2Token, err := oauth.OAuthProviders.GithubConfig.Exchange(ctx, code) if err != nil { log.Debug("Failed to exchange code for token: ", err) return user, fmt.Errorf("invalid github exchange code: %s", err.Error()) @@ -409,7 +411,7 @@ func processGithubUserInfo(code string) (models.User, error) { } } - user = models.User{ + user = &models.User{ GivenName: &firstName, FamilyName: &lastName, Picture: &picture, @@ -419,9 +421,9 @@ func processGithubUserInfo(code string) (models.User, error) { return user, nil } -func processFacebookUserInfo(code string) (models.User, error) { - user := models.User{} - oauth2Token, err := oauth.OAuthProviders.FacebookConfig.Exchange(context.TODO(), code) +func processFacebookUserInfo(ctx context.Context, code string) (*models.User, error) { + var user *models.User + oauth2Token, err := oauth.OAuthProviders.FacebookConfig.Exchange(ctx, code) if err != nil { log.Debug("Invalid facebook exchange code: ", err) return user, fmt.Errorf("invalid facebook exchange code: %s", err.Error()) @@ -460,7 +462,7 @@ func processFacebookUserInfo(code string) (models.User, error) { lastName := fmt.Sprintf("%v", userRawData["last_name"]) picture := fmt.Sprintf("%v", picDataObject["url"]) - user = models.User{ + user = &models.User{ GivenName: &firstName, FamilyName: &lastName, Picture: &picture, @@ -470,9 +472,9 @@ func processFacebookUserInfo(code string) (models.User, error) { return user, nil } -func processLinkedInUserInfo(code string) (models.User, error) { - user := models.User{} - oauth2Token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(context.TODO(), code) +func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, error) { + var user *models.User + oauth2Token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(ctx, code) if err != nil { log.Debug("Failed to exchange code for token: ", err) return user, fmt.Errorf("invalid linkedin exchange code: %s", err.Error()) @@ -542,7 +544,7 @@ func processLinkedInUserInfo(code string) (models.User, error) { profilePicture := userRawData["profilePicture"].(map[string]interface{})["displayImage~"].(map[string]interface{})["elements"].([]interface{})[0].(map[string]interface{})["identifiers"].([]interface{})[0].(map[string]interface{})["identifier"].(string) emailAddress := emailRawData["elements"].([]interface{})[0].(map[string]interface{})["handle~"].(map[string]interface{})["emailAddress"].(string) - user = models.User{ + user = &models.User{ GivenName: &firstName, FamilyName: &lastName, Picture: &profilePicture, @@ -552,9 +554,9 @@ func processLinkedInUserInfo(code string) (models.User, error) { return user, nil } -func processAppleUserInfo(code string) (models.User, error) { - user := models.User{} - oauth2Token, err := oauth.OAuthProviders.AppleConfig.Exchange(context.TODO(), code) +func processAppleUserInfo(ctx context.Context, code string) (*models.User, error) { + var user *models.User + oauth2Token, err := oauth.OAuthProviders.AppleConfig.Exchange(ctx, code) if err != nil { log.Debug("Failed to exchange code for token: ", err) return user, fmt.Errorf("invalid apple exchange code: %s", err.Error()) @@ -605,9 +607,9 @@ func processAppleUserInfo(code string) (models.User, error) { return user, err } -func processTwitterUserInfo(code, verifier string) (models.User, error) { - user := models.User{} - oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(context.TODO(), code, oauth2.SetAuthURLParam("code_verifier", verifier)) +func processTwitterUserInfo(ctx context.Context, code, verifier string) (*models.User, error) { + var user *models.User + oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(ctx, code, oauth2.SetAuthURLParam("code_verifier", verifier)) if err != nil { log.Debug("Failed to exchange code for token: ", err) return user, fmt.Errorf("invalid twitter exchange code: %s", err.Error()) @@ -662,7 +664,7 @@ func processTwitterUserInfo(code, verifier string) (models.User, error) { nickname := userRawData["username"].(string) profilePicture := userRawData["profile_image_url"].(string) - user = models.User{ + user = &models.User{ GivenName: &firstName, FamilyName: &lastName, Picture: &profilePicture, @@ -673,24 +675,24 @@ func processTwitterUserInfo(code, verifier string) (models.User, error) { } // process microsoft user information -func processMicrosoftUserInfo(code string) (models.User, error) { - user := models.User{} - ctx := context.Background() +func processMicrosoftUserInfo(ctx context.Context, code string) (*models.User, error) { + var user *models.User oauth2Token, err := oauth.OAuthProviders.MicrosoftConfig.Exchange(ctx, code) if err != nil { log.Debug("Failed to exchange code for token: ", err) - return user, fmt.Errorf("invalid google exchange code: %s", err.Error()) + return user, fmt.Errorf("invalid microsoft exchange code: %s", err.Error()) } - - verifier := oauth.OIDCProviders.MicrosoftOIDC.Verifier(&oidc.Config{ClientID: oauth.OAuthProviders.MicrosoftConfig.ClientID}) - + // we need to skip issuer check because for common tenant it will return internal issuer which does not match + verifier := oauth.OIDCProviders.MicrosoftOIDC.Verifier(&oidc.Config{ + ClientID: oauth.OAuthProviders.MicrosoftConfig.ClientID, + SkipIssuerCheck: true, + }) // Extract the ID Token from OAuth2 token. rawIDToken, ok := oauth2Token.Extra("id_token").(string) if !ok { log.Debug("Failed to extract ID Token from OAuth2 token") return user, fmt.Errorf("unable to extract id_token") } - // Parse and verify ID Token payload. idToken, err := verifier.Verify(ctx, rawIDToken) if err != nil { diff --git a/server/handlers/verify_email.go b/server/handlers/verify_email.go index 452820f..47f61d3 100644 --- a/server/handlers/verify_email.go +++ b/server/handlers/verify_email.go @@ -175,11 +175,12 @@ func VerifyEmailHandler() gin.HandlerFunc { go func() { if isSignUp { utils.RegisterEvent(c, constants.UserSignUpWebhookEvent, loginMethod, user) + // User is also logged in with signup + utils.RegisterEvent(c, constants.UserLoginWebhookEvent, loginMethod, user) } else { utils.RegisterEvent(c, constants.UserLoginWebhookEvent, loginMethod, user) } - - db.Provider.AddSession(c, models.Session{ + db.Provider.AddSession(c, &models.Session{ UserID: user.ID, UserAgent: utils.GetUserAgent(c.Request), IP: utils.GetIP(c.Request), diff --git a/server/memorystore/memory_store.go b/server/memorystore/memory_store.go index c8f4773..4004d68 100644 --- a/server/memorystore/memory_store.go +++ b/server/memorystore/memory_store.go @@ -33,6 +33,7 @@ func InitMemStore() error { constants.EnvKeyDisableSignUp: false, constants.EnvKeyDisableStrongPassword: false, constants.EnvKeyIsEmailServiceEnabled: false, + constants.EnvKeyIsSMSServiceEnabled: false, constants.EnvKeyEnforceMultiFactorAuthentication: false, constants.EnvKeyDisableMultiFactorAuthentication: false, constants.EnvKeyAppCookieSecure: true, diff --git a/server/memorystore/providers/inmemory/provider.go b/server/memorystore/providers/inmemory/provider.go index 952092d..e726502 100644 --- a/server/memorystore/providers/inmemory/provider.go +++ b/server/memorystore/providers/inmemory/provider.go @@ -7,18 +7,20 @@ import ( ) type provider struct { - mutex sync.Mutex - sessionStore *stores.SessionStore - stateStore *stores.StateStore - envStore *stores.EnvStore + mutex sync.Mutex + sessionStore *stores.SessionStore + mfasessionStore *stores.SessionStore + stateStore *stores.StateStore + envStore *stores.EnvStore } // NewInMemoryStore returns a new in-memory store. func NewInMemoryProvider() (*provider, error) { return &provider{ - mutex: sync.Mutex{}, - envStore: stores.NewEnvStore(), - sessionStore: stores.NewSessionStore(), - stateStore: stores.NewStateStore(), + mutex: sync.Mutex{}, + envStore: stores.NewEnvStore(), + sessionStore: stores.NewSessionStore(), + mfasessionStore: stores.NewSessionStore(), + stateStore: stores.NewStateStore(), }, nil } diff --git a/server/memorystore/providers/inmemory/store.go b/server/memorystore/providers/inmemory/store.go index 4a8e8ce..b20fb62 100644 --- a/server/memorystore/providers/inmemory/store.go +++ b/server/memorystore/providers/inmemory/store.go @@ -42,6 +42,27 @@ func (c *provider) DeleteSessionForNamespace(namespace string) error { return nil } +// SetMfaSession sets the mfa session with key and value of userId +func (c *provider) SetMfaSession(userId, key string, expiration int64) error { + c.mfasessionStore.Set(userId, key, userId, expiration) + return nil +} + +// GetMfaSession returns value of given mfa session +func (c *provider) GetMfaSession(userId, key string) (string, error) { + val := c.mfasessionStore.Get(userId, key) + if val == "" { + return "", fmt.Errorf("Not found") + } + return val, nil +} + +// DeleteMfaSession deletes given mfa session from in-memory store. +func (c *provider) DeleteMfaSession(userId, key string) error { + c.mfasessionStore.Remove(userId, key) + return nil +} + // SetState sets the state in the in-memory store. func (c *provider) SetState(key, state string) error { if os.Getenv("ENV") != constants.TestEnv { diff --git a/server/memorystore/providers/provider_tests.go b/server/memorystore/providers/provider_tests.go index e569fe8..47f4dba 100644 --- a/server/memorystore/providers/provider_tests.go +++ b/server/memorystore/providers/provider_tests.go @@ -112,4 +112,15 @@ func ProviderTests(t *testing.T, p Provider) { key, err = p.GetUserSession("auth_provider1:124", "access_token_key") assert.Empty(t, key) assert.Error(t, err) + + err = p.SetMfaSession("auth_provider:123", "session123", time.Now().Add(60*time.Second).Unix()) + assert.NoError(t, err) + key, err = p.GetMfaSession("auth_provider:123", "session123") + assert.NoError(t, err) + assert.Equal(t, "auth_provider:123", key) + err = p.DeleteMfaSession("auth_provider:123", "session123") + assert.NoError(t, err) + key, err = p.GetMfaSession("auth_provider:123", "session123") + assert.Error(t, err) + assert.Empty(t, key) } diff --git a/server/memorystore/providers/providers.go b/server/memorystore/providers/providers.go index db58aa7..331e34a 100644 --- a/server/memorystore/providers/providers.go +++ b/server/memorystore/providers/providers.go @@ -12,6 +12,12 @@ type Provider interface { DeleteAllUserSessions(userId string) error // DeleteSessionForNamespace deletes the session for a given namespace DeleteSessionForNamespace(namespace string) error + // SetMfaSession sets the mfa session with key and value of userId + SetMfaSession(userId, key string, expiration int64) error + // GetMfaSession returns value of given mfa session + GetMfaSession(userId, key string) (string, error) + // DeleteMfaSession deletes given mfa session from in-memory store. + DeleteMfaSession(userId, key string) error // SetState sets the login state (key, value form) in the session store SetState(key, state string) error diff --git a/server/memorystore/providers/redis/provider.go b/server/memorystore/providers/redis/provider.go index 894a75e..17fb475 100644 --- a/server/memorystore/providers/redis/provider.go +++ b/server/memorystore/providers/redis/provider.go @@ -9,6 +9,10 @@ import ( log "github.com/sirupsen/logrus" ) +const ( + dialTimeout = 60 * time.Second +) + // RedisClient is the interface for redis client & redis cluster client type RedisClient interface { HMSet(ctx context.Context, key string, values ...interface{}) *redis.BoolCmd @@ -41,8 +45,7 @@ func NewRedisProvider(redisURL string) (*provider, error) { urls := []string{opt.Addr} urlList := redisURLHostPortsList[1:] urls = append(urls, urlList...) - clusterOpt := &redis.ClusterOptions{Addrs: urls} - + clusterOpt := &redis.ClusterOptions{Addrs: urls, DialTimeout: dialTimeout} rdb := redis.NewClusterClient(clusterOpt) ctx := context.Background() _, err = rdb.Ping(ctx).Result() @@ -62,7 +65,7 @@ func NewRedisProvider(redisURL string) (*provider, error) { log.Debug("error parsing redis url: ", err) return nil, err } - + opt.DialTimeout = dialTimeout rdb := redis.NewClient(opt) ctx := context.Background() _, err = rdb.Ping(ctx).Result() diff --git a/server/memorystore/providers/redis/store.go b/server/memorystore/providers/redis/store.go index 7f395db..d761ce1 100644 --- a/server/memorystore/providers/redis/store.go +++ b/server/memorystore/providers/redis/store.go @@ -16,6 +16,8 @@ var ( envStorePrefix = "authorizer_env" ) +const mfaSessionPrefix = "mfa_sess_" + // SetUserSession sets the user session for given user identifier in form recipe:user_id func (c *provider) SetUserSession(userId, key, token string, expiration int64) error { currentTime := time.Now() @@ -91,6 +93,37 @@ func (c *provider) DeleteSessionForNamespace(namespace string) error { return nil } +// SetMfaSession sets the mfa session with key and value of userId +func (c *provider) SetMfaSession(userId, key string, expiration int64) error { + currentTime := time.Now() + expireTime := time.Unix(expiration, 0) + duration := expireTime.Sub(currentTime) + err := c.store.Set(c.ctx, fmt.Sprintf("%s%s:%s", mfaSessionPrefix, userId, key), userId, duration).Err() + if err != nil { + log.Debug("Error saving user session to redis: ", err) + return err + } + return nil +} + +// GetMfaSession returns value of given mfa session +func (c *provider) GetMfaSession(userId, key string) (string, error) { + data, err := c.store.Get(c.ctx, fmt.Sprintf("%s%s:%s", mfaSessionPrefix, userId, key)).Result() + if err != nil { + return "", err + } + return data, nil +} + +// DeleteMfaSession deletes given mfa session from in-memory store. +func (c *provider) DeleteMfaSession(userId, key string) error { + if err := c.store.Del(c.ctx, fmt.Sprintf("%s%s:%s", mfaSessionPrefix, userId, key)).Err(); err != nil { + log.Debug("Error deleting user session from redis: ", err) + // continue + } + return nil +} + // SetState sets the state in redis store. func (c *provider) SetState(key, value string) error { err := c.store.Set(c.ctx, stateStorePrefix+key, value, 0).Err() @@ -143,7 +176,7 @@ func (c *provider) GetEnvStore() (map[string]interface{}, error) { return nil, err } 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.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 { boolValue, err := strconv.ParseBool(value) if err != nil { return res, err diff --git a/server/oauth/oauth.go b/server/oauth/oauth.go index 7841909..3f02916 100644 --- a/server/oauth/oauth.go +++ b/server/oauth/oauth.go @@ -10,11 +10,16 @@ import ( githubOAuth2 "golang.org/x/oauth2/github" linkedInOAuth2 "golang.org/x/oauth2/linkedin" microsoftOAuth2 "golang.org/x/oauth2/microsoft" + "google.golang.org/appengine/log" "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/memorystore" ) +const ( + microsoftCommonTenant = "common" +) + // OAuthProviders is a struct that contains reference all the OAuth providers type OAuthProvider struct { GoogleConfig *oauth2.Config @@ -171,12 +176,16 @@ func InitOAuth() error { microsoftClientSecret = "" } microsoftActiveDirTenantID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyMicrosoftActiveDirectoryTenantID) - if err != nil { - microsoftActiveDirTenantID = "" + if err != nil || microsoftActiveDirTenantID == "" { + microsoftActiveDirTenantID = microsoftCommonTenant } - if microsoftClientID != "" && microsoftClientSecret != "" && microsoftActiveDirTenantID != "" { + if microsoftClientID != "" && microsoftClientSecret != "" { + if microsoftActiveDirTenantID == microsoftCommonTenant { + ctx = oidc.InsecureIssuerURLContext(ctx, fmt.Sprintf("https://login.microsoftonline.com/%s/v2.0", microsoftActiveDirTenantID)) + } p, err := oidc.NewProvider(ctx, fmt.Sprintf("https://login.microsoftonline.com/%s/v2.0", microsoftActiveDirTenantID)) if err != nil { + log.Debugf(ctx, "Error while creating OIDC provider for Microsoft: %v", err) return err } OIDCProviders.MicrosoftOIDC = p diff --git a/server/resolvers/add_email_template.go b/server/resolvers/add_email_template.go index 311b18a..487edc2 100644 --- a/server/resolvers/add_email_template.go +++ b/server/resolvers/add_email_template.go @@ -47,7 +47,7 @@ func AddEmailTemplateResolver(ctx context.Context, params model.AddEmailTemplate design = "" } - _, err = db.Provider.AddEmailTemplate(ctx, models.EmailTemplate{ + _, err = db.Provider.AddEmailTemplate(ctx, &models.EmailTemplate{ EventName: params.EventName, Template: params.Template, Subject: params.Subject, diff --git a/server/resolvers/add_webhook.go b/server/resolvers/add_webhook.go index 596b1e0..3380779 100644 --- a/server/resolvers/add_webhook.go +++ b/server/resolvers/add_webhook.go @@ -43,7 +43,7 @@ func AddWebhookResolver(ctx context.Context, params model.AddWebhookRequest) (*m if params.EventDescription == nil { params.EventDescription = refs.NewStringRef(strings.Join(strings.Split(params.EventName, "."), " ")) } - _, err = db.Provider.AddWebhook(ctx, models.Webhook{ + _, err = db.Provider.AddWebhook(ctx, &models.Webhook{ EventDescription: refs.StringValue(params.EventDescription), EventName: params.EventName, EndPoint: params.Endpoint, diff --git a/server/resolvers/email_templates.go b/server/resolvers/email_templates.go index 7230400..0e1ee66 100644 --- a/server/resolvers/email_templates.go +++ b/server/resolvers/email_templates.go @@ -25,7 +25,6 @@ func EmailTemplatesResolver(ctx context.Context, params *model.PaginatedInput) ( } pagination := utils.GetPagination(params) - emailTemplates, err := db.Provider.ListEmailTemplate(ctx, pagination) if err != nil { log.Debug("failed to get email templates: ", err) diff --git a/server/resolvers/forgot_password.go b/server/resolvers/forgot_password.go index f497b31..028ff11 100644 --- a/server/resolvers/forgot_password.go +++ b/server/resolvers/forgot_password.go @@ -81,7 +81,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu log.Debug("Failed to create verification token", err) return res, err } - _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{ + _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ Token: verificationToken, Identifier: constants.VerificationTypeForgotPassword, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), diff --git a/server/resolvers/invite_members.go b/server/resolvers/invite_members.go index c15ca7e..ee5e0a1 100644 --- a/server/resolvers/invite_members.go +++ b/server/resolvers/invite_members.go @@ -105,7 +105,7 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput) defaultRoles = strings.Split(defaultRolesString, ",") } - user := models.User{ + user := &models.User{ Email: email, Roles: strings.Join(defaultRoles, ","), } @@ -128,7 +128,7 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput) log.Debug("Failed to create verification token: ", err) } - verificationRequest := models.VerificationRequest{ + verificationRequest := &models.VerificationRequest{ Token: verificationToken, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), Email: email, diff --git a/server/resolvers/login.go b/server/resolvers/login.go index 28a2289..9dcec5a 100644 --- a/server/resolvers/login.go +++ b/server/resolvers/login.go @@ -106,23 +106,32 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes } isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication) - if err != nil || !isEmailServiceEnabled { + if err != nil || !isMFADisabled { log.Debug("MFA service not enabled: ", err) } // If email service is not enabled continue the process in any way if refs.BoolValue(user.IsMultiFactorAuthEnabled) && isEmailServiceEnabled && !isMFADisabled { otp := utils.GenerateOTP() + expires := time.Now().Add(1 * time.Minute).Unix() otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{ Email: user.Email, Otp: otp, - ExpiresAt: time.Now().Add(1 * time.Minute).Unix(), + ExpiresAt: expires, }) if err != nil { log.Debug("Failed to add otp: ", err) return nil, err } + mfaSession := uuid.NewString() + err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expires) + if err != nil { + log.Debug("Failed to add mfasession: ", err) + return nil, err + } + cookie.SetMfaSession(gc, mfaSession) + go func() { // exec it as go routine so that we can reduce the api latency go email.SendEmail([]string{params.Email}, constants.VerificationTypeOTP, map[string]interface{}{ @@ -136,8 +145,8 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes }() return &model.AuthResponse{ - Message: "Please check the OTP in your inbox", - ShouldShowOtpScreen: refs.NewBoolRef(true), + Message: "Please check the OTP in your inbox", + ShouldShowEmailOtpScreen: refs.NewBoolRef(true), }, nil } @@ -162,7 +171,6 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes if nonce == "" { nonce = uuid.New().String() } - authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth, nonce, code) if err != nil { log.Debug("Failed to create auth token", err) @@ -203,7 +211,7 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes go func() { utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) - db.Provider.AddSession(ctx, models.Session{ + db.Provider.AddSession(ctx, &models.Session{ UserID: user.ID, UserAgent: utils.GetUserAgent(gc.Request), IP: utils.GetIP(gc.Request), diff --git a/server/resolvers/magic_link_login.go b/server/resolvers/magic_link_login.go index 5ce90c8..a500c27 100644 --- a/server/resolvers/magic_link_login.go +++ b/server/resolvers/magic_link_login.go @@ -55,7 +55,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu inputRoles := []string{} - user := models.User{ + user := &models.User{ Email: params.Email, } @@ -207,7 +207,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu if err != nil { log.Debug("Failed to create verification token: ", err) } - _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{ + _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ Token: verificationToken, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), diff --git a/server/resolvers/meta.go b/server/resolvers/meta.go index 5322517..9290a41 100644 --- a/server/resolvers/meta.go +++ b/server/resolvers/meta.go @@ -101,12 +101,6 @@ func MetaResolver(ctx context.Context) (*model.Meta, error) { microsoftClientSecret = "" } - microsoftActiveDirTenantID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyMicrosoftActiveDirectoryTenantID) - if err != nil { - log.Debug("Failed to get Microsoft Active Directory Tenant ID from environment variable", err) - microsoftActiveDirTenantID = "" - } - isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) if err != nil { log.Debug("Failed to get Disable Basic Authentication from environment variable", err) @@ -152,7 +146,7 @@ func MetaResolver(ctx context.Context) (*model.Meta, error) { IsLinkedinLoginEnabled: linkedClientID != "" && linkedInClientSecret != "", IsAppleLoginEnabled: appleClientID != "" && appleClientSecret != "", IsTwitterLoginEnabled: twitterClientID != "" && twitterClientSecret != "", - IsMicrosoftLoginEnabled: microsoftClientID != "" && microsoftClientSecret != "" && microsoftActiveDirTenantID != "", + IsMicrosoftLoginEnabled: microsoftClientID != "" && microsoftClientSecret != "", IsBasicAuthenticationEnabled: !isBasicAuthDisabled, IsEmailVerificationEnabled: !isEmailVerificationDisabled, IsMagicLinkLoginEnabled: !isMagicLinkLoginDisabled, diff --git a/server/resolvers/mobile_login.go b/server/resolvers/mobile_login.go index 9da0a53..381f9a4 100644 --- a/server/resolvers/mobile_login.go +++ b/server/resolvers/mobile_login.go @@ -17,6 +17,7 @@ import ( "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/refs" + "github.com/authorizerdev/authorizer/server/smsproviders" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/validators" @@ -94,55 +95,67 @@ func MobileLoginResolver(ctx context.Context, params model.MobileLoginInput) (*m roles = params.Roles } + disablePhoneVerification, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) + if err != nil { + log.Debug("Error getting disable phone verification: ", err) + } + if disablePhoneVerification { + now := time.Now().Unix() + user.PhoneNumberVerifiedAt = &now + } + isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled) + if err != nil || !isSMSServiceEnabled { + log.Debug("SMS service not enabled: ", err) + } + if disablePhoneVerification { + now := time.Now().Unix() + user.PhoneNumberVerifiedAt = &now + } + isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication) + if err != nil || !isMFADisabled { + log.Debug("MFA service not enabled: ", err) + } + if !disablePhoneVerification && isSMSServiceEnabled && !isMFADisabled { + duration, _ := time.ParseDuration("10m") + smsCode := utils.GenerateOTP() + + smsBody := strings.Builder{} + smsBody.WriteString("Your verification code is: ") + smsBody.WriteString(smsCode) + expires := time.Now().Add(duration).Unix() + _, err := db.Provider.UpsertOTP(ctx, &models.OTP{ + PhoneNumber: params.PhoneNumber, + Otp: smsCode, + ExpiresAt: expires, + }) + if err != nil { + log.Debug("error while upserting OTP: ", err.Error()) + return nil, err + } + + mfaSession := uuid.NewString() + err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expires) + if err != nil { + log.Debug("Failed to add mfasession: ", err) + return nil, err + } + cookie.SetMfaSession(gc, mfaSession) + + go func() { + utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + smsproviders.SendSMS(params.PhoneNumber, smsBody.String()) + }() + return &model.AuthResponse{ + Message: "Please check the OTP", + ShouldShowMobileOtpScreen: refs.NewBoolRef(true), + }, nil + } + scope := []string{"openid", "email", "profile"} if params.Scope != nil && len(scope) > 0 { scope = params.Scope } - /* - // TODO use sms authentication for MFA - isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled) - if err != nil || !isEmailServiceEnabled { - log.Debug("Email service not enabled: ", err) - } - - isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication) - if err != nil || !isEmailServiceEnabled { - log.Debug("MFA service not enabled: ", err) - } - - // If email service is not enabled continue the process in any way - if refs.BoolValue(user.IsMultiFactorAuthEnabled) && isEmailServiceEnabled && !isMFADisabled { - otp := utils.GenerateOTP() - otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{ - Email: user.Email, - Otp: otp, - ExpiresAt: time.Now().Add(1 * time.Minute).Unix(), - }) - if err != nil { - log.Debug("Failed to add otp: ", err) - return nil, err - } - - go func() { - // exec it as go routine so that we can reduce the api latency - go email.SendEmail([]string{params.PhoneNumber}, constants.VerificationTypeOTP, map[string]interface{}{ - "user": user.ToMap(), - "organization": utils.GetOrganization(), - "otp": otpData.Otp, - }) - if err != nil { - log.Debug("Failed to send otp email: ", err) - } - }() - - return &model.AuthResponse{ - Message: "Please check the OTP in your inbox", - ShouldShowOtpScreen: refs.NewBoolRef(true), - }, nil - } - */ - code := "" codeChallenge := "" nonce := "" @@ -165,7 +178,7 @@ func MobileLoginResolver(ctx context.Context, params model.MobileLoginInput) (*m nonce = uuid.New().String() } - authToken, err := token.CreateAuthToken(gc, *user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code) + authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code) if err != nil { log.Debug("Failed to create auth token", err) return res, err @@ -204,8 +217,8 @@ func MobileLoginResolver(ctx context.Context, params model.MobileLoginInput) (*m } go func() { - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, *user) - db.Provider.AddSession(ctx, models.Session{ + utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + db.Provider.AddSession(ctx, &models.Session{ UserID: user.ID, UserAgent: utils.GetUserAgent(gc.Request), IP: utils.GetIP(gc.Request), diff --git a/server/resolvers/mobile_signup.go b/server/resolvers/mobile_signup.go index 9aee0a6..60b3a88 100644 --- a/server/resolvers/mobile_signup.go +++ b/server/resolvers/mobile_signup.go @@ -8,7 +8,7 @@ import ( "github.com/google/uuid" log "github.com/sirupsen/logrus" - + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/crypto" @@ -17,9 +17,9 @@ import ( "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/refs" + "github.com/authorizerdev/authorizer/server/smsproviders" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/smsproviders" "github.com/authorizerdev/authorizer/server/validators" ) @@ -92,7 +92,6 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) if err != nil { log.Debug("Failed to get user by email: ", err) } - if existingUser != nil { if existingUser.PhoneNumberVerifiedAt != nil { // email is verified @@ -105,7 +104,6 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) } inputRoles := []string{} - if len(params.Roles) > 0 { // check if roles exists rolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRoles) @@ -132,9 +130,9 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) } } - user := models.User{ - Email: emailInput, - PhoneNumber: &mobile, + user := &models.User{ + Email: emailInput, + PhoneNumber: &mobile, } user.Roles = strings.Join(inputRoles, ",") @@ -179,7 +177,7 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) log.Debug("MFA service not enabled: ", err) isMFAEnforced = false } - + if isMFAEnforced { user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) } @@ -189,6 +187,10 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) now := time.Now().Unix() user.PhoneNumberVerifiedAt = &now } + isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled) + if err != nil || !isSMSServiceEnabled { + log.Debug("SMS service not enabled: ", err) + } user.SignupMethods = constants.AuthRecipeMethodMobileBasicAuth user, err = db.Provider.AddUser(ctx, user) @@ -197,11 +199,10 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) log.Debug("Failed to add user: ", err) return res, err } - - if !disablePhoneVerification { + if !disablePhoneVerification && isSMSServiceEnabled { duration, _ := time.ParseDuration("10m") smsCode := utils.GenerateOTP() - + smsBody := strings.Builder{} smsBody.WriteString("Your verification code is: ") smsBody.WriteString(smsCode) @@ -211,15 +212,23 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) log.Debug("error while upserting user: ", err.Error()) return nil, err } - + _, err = db.Provider.UpsertOTP(ctx, &models.OTP{ + PhoneNumber: mobile, + Otp: smsCode, + ExpiresAt: time.Now().Add(duration).Unix(), + }) + if err != nil { + log.Debug("error while upserting OTP: ", err.Error()) + return nil, err + } go func() { - db.Provider.UpsertSMSRequest(ctx, &models.SMSVerificationRequest{ - PhoneNumber: mobile, - Code: smsCode, - CodeExpiresAt: time.Now().Add(duration).Unix(), - }) smsproviders.SendSMS(mobile, smsBody.String()) + utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) }() + return &model.AuthResponse{ + Message: "Please check the OTP in your inbox", + ShouldShowMobileOtpScreen: refs.NewBoolRef(true), + }, nil } roles := strings.Split(user.Roles, ",") @@ -290,7 +299,9 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) go func() { utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - db.Provider.AddSession(ctx, models.Session{ + // User is also logged in with signup + utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + db.Provider.AddSession(ctx, &models.Session{ UserID: user.ID, UserAgent: utils.GetUserAgent(gc.Request), IP: utils.GetIP(gc.Request), diff --git a/server/resolvers/resend_otp.go b/server/resolvers/resend_otp.go index 65d9cf1..74da143 100644 --- a/server/resolvers/resend_otp.go +++ b/server/resolvers/resend_otp.go @@ -12,23 +12,46 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/email" + emailHelper "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/refs" + "github.com/authorizerdev/authorizer/server/smsproviders" "github.com/authorizerdev/authorizer/server/utils" ) // ResendOTPResolver is a resolver for resend otp mutation func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error) { + email := strings.ToLower(strings.Trim(refs.StringValue(params.Email), " ")) + phoneNumber := strings.Trim(refs.StringValue(params.PhoneNumber), " ") log := log.WithFields(log.Fields{ - "email": params.Email, + "email": email, + "phone_number": phoneNumber, }) - params.Email = strings.ToLower(params.Email) - user, err := db.Provider.GetUserByEmail(ctx, params.Email) + if email == "" && phoneNumber == "" { + log.Debug("Email or phone number is required") + return nil, errors.New("email or phone number is required") + } + var user *models.User + var err error + if email != "" { + isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled) + if err != nil || !isEmailServiceEnabled { + log.Debug("Email service not enabled: ", err) + return nil, errors.New("email service not enabled") + } + user, err = db.Provider.GetUserByEmail(ctx, email) + } else { + isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled) + if err != nil || !isSMSServiceEnabled { + log.Debug("Email service not enabled: ", err) + return nil, errors.New("email service not enabled") + } + user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber) + } if err != nil { log.Debug("Failed to get user by email: ", err) - return nil, fmt.Errorf(`user with this email not found`) + return nil, fmt.Errorf(`user with this email/phone not found`) } if user.RevokedTimestamp != nil { @@ -36,35 +59,38 @@ func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*mod return nil, fmt.Errorf(`user access has been revoked`) } - if user.EmailVerifiedAt == nil { + if email != "" && user.EmailVerifiedAt == nil { log.Debug("User email is not verified") return nil, fmt.Errorf(`email not verified`) } + if phoneNumber != "" && user.PhoneNumberVerifiedAt == nil { + log.Debug("User phone number is not verified") + return nil, fmt.Errorf(`phone number not verified`) + } + if !refs.BoolValue(user.IsMultiFactorAuthEnabled) { log.Debug("User multi factor authentication is not enabled") return nil, fmt.Errorf(`multi factor authentication not enabled`) } - isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled) - if err != nil || !isEmailServiceEnabled { - log.Debug("Email service not enabled: ", err) - return nil, errors.New("email service not enabled") - } - isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication) if err != nil || isMFADisabled { log.Debug("MFA service not enabled: ", err) return nil, errors.New("multi factor authentication is disabled for this instance") } - // get otp by email - otpData, err := db.Provider.GetOTPByEmail(ctx, params.Email) + // get otp by email or phone number + var otpData *models.OTP + if email != "" { + otpData, err = db.Provider.GetOTPByEmail(ctx, refs.StringValue(params.Email)) + } else { + otpData, err = db.Provider.GetOTPByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber)) + } if err != nil { log.Debug("Failed to get otp for given email: ", err) return nil, err } - if otpData == nil { log.Debug("No otp found for given email: ", params.Email) return &model.Response{ @@ -73,28 +99,30 @@ func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*mod } otp := utils.GenerateOTP() - otpData, err = db.Provider.UpsertOTP(ctx, &models.OTP{ + if _, err := db.Provider.UpsertOTP(ctx, &models.OTP{ Email: user.Email, Otp: otp, ExpiresAt: time.Now().Add(1 * time.Minute).Unix(), - }) - if err != nil { - log.Debug("Error generating new otp: ", err) + }); err != nil { + log.Debug("Error upserting otp: ", err) return nil, err } - go func() { + if email != "" { // exec it as go routine so that we can reduce the api latency - go email.SendEmail([]string{params.Email}, constants.VerificationTypeOTP, map[string]interface{}{ + go emailHelper.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{ "user": user.ToMap(), "organization": utils.GetOrganization(), "otp": otp, }) - if err != nil { - log.Debug("Error sending otp email: ", otp) - } - }() - + } else { + smsBody := strings.Builder{} + smsBody.WriteString("Your verification code is: ") + smsBody.WriteString(otp) + // exec it as go routine so that we can reduce the api latency + go smsproviders.SendSMS(phoneNumber, smsBody.String()) + } + log.Info("OTP has been resent") return &model.Response{ Message: `OTP has been sent. Please check your inbox`, }, nil diff --git a/server/resolvers/resend_verify_email.go b/server/resolvers/resend_verify_email.go index 6c94024..b5a789f 100644 --- a/server/resolvers/resend_verify_email.go +++ b/server/resolvers/resend_verify_email.go @@ -67,7 +67,7 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma if err != nil { log.Debug("Failed to create verification token: ", err) } - _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{ + _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ Token: verificationToken, Identifier: params.Identifier, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), diff --git a/server/resolvers/signup.go b/server/resolvers/signup.go index 757efeb..cefcfb2 100644 --- a/server/resolvers/signup.go +++ b/server/resolvers/signup.go @@ -2,6 +2,8 @@ package resolvers import ( "context" + "encoding/json" + "errors" "fmt" "strings" "time" @@ -81,13 +83,15 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR log.Debug("Failed to get user by email: ", err) } - if existingUser.EmailVerifiedAt != nil { - // email is verified - log.Debug("Email is already verified and signed up.") - return res, fmt.Errorf(`%s has already signed up`, params.Email) - } else if existingUser.ID != "" && existingUser.EmailVerifiedAt == nil { - log.Debug("Email is already signed up. Verification pending...") - return res, fmt.Errorf("%s has already signed up. please complete the email verification process or reset the password", params.Email) + if existingUser != nil { + if existingUser.EmailVerifiedAt != nil { + // email is verified + log.Debug("Email is already verified and signed up.") + return res, fmt.Errorf(`%s has already signed up`, params.Email) + } else if existingUser.ID != "" && existingUser.EmailVerifiedAt == nil { + log.Debug("Email is already signed up. Verification pending...") + return res, fmt.Errorf("%s has already signed up. please complete the email verification process or reset the password", params.Email) + } } inputRoles := []string{} @@ -116,13 +120,10 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR inputRoles = strings.Split(inputRolesString, ",") } } - - user := models.User{ + user := &models.User{ Email: params.Email, } - user.Roles = strings.Join(inputRoles, ",") - password, _ := crypto.EncryptPassword(params.Password) user.Password = &password @@ -172,6 +173,17 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) } + if params.AppData != nil { + appDataString := "" + appDataBytes, err := json.Marshal(params.AppData) + if err != nil { + log.Debug("failed to marshall source app_data: ", err) + return nil, errors.New("malformed app_data") + } + appDataString = string(appDataBytes) + user.AppData = &appDataString + } + user.SignupMethods = constants.AuthRecipeMethodBasicAuth isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) if err != nil { @@ -208,7 +220,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR log.Debug("Failed to create verification token: ", err) return res, err } - _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{ + _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ Token: verificationToken, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), @@ -302,7 +314,9 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR go func() { utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) - db.Provider.AddSession(ctx, models.Session{ + // User is also logged in with signup + utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) + db.Provider.AddSession(ctx, &models.Session{ UserID: user.ID, UserAgent: utils.GetUserAgent(gc.Request), IP: utils.GetIP(gc.Request), diff --git a/server/resolvers/update_email_template.go b/server/resolvers/update_email_template.go index cf4e948..c08a49f 100644 --- a/server/resolvers/update_email_template.go +++ b/server/resolvers/update_email_template.go @@ -34,7 +34,7 @@ func UpdateEmailTemplateResolver(ctx context.Context, params model.UpdateEmailTe return nil, err } - emailTemplateDetails := models.EmailTemplate{ + emailTemplateDetails := &models.EmailTemplate{ ID: emailTemplate.ID, Key: emailTemplate.ID, EventName: emailTemplate.EventName, diff --git a/server/resolvers/update_env.go b/server/resolvers/update_env.go index d9d6881..96388aa 100644 --- a/server/resolvers/update_env.go +++ b/server/resolvers/update_env.go @@ -33,7 +33,7 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) { isCurrentGithubLoginEnabled := currentData[constants.EnvKeyGithubClientID] != nil && currentData[constants.EnvKeyGithubClientSecret] != nil && currentData[constants.EnvKeyGithubClientID].(string) != "" && currentData[constants.EnvKeyGithubClientSecret].(string) != "" isCurrentLinkedInLoginEnabled := currentData[constants.EnvKeyLinkedInClientID] != nil && currentData[constants.EnvKeyLinkedInClientSecret] != nil && currentData[constants.EnvKeyLinkedInClientID].(string) != "" && currentData[constants.EnvKeyLinkedInClientSecret].(string) != "" isCurrentTwitterLoginEnabled := currentData[constants.EnvKeyTwitterClientID] != nil && currentData[constants.EnvKeyTwitterClientSecret] != nil && currentData[constants.EnvKeyTwitterClientID].(string) != "" && currentData[constants.EnvKeyTwitterClientSecret].(string) != "" - isCurrentMicrosoftLoginEnabled := currentData[constants.EnvKeyMicrosoftClientID] != nil && currentData[constants.EnvKeyMicrosoftClientSecret] != nil && currentData[constants.EnvKeyMicrosoftActiveDirectoryTenantID] != nil && currentData[constants.EnvKeyMicrosoftClientID].(string) != "" && currentData[constants.EnvKeyMicrosoftClientSecret].(string) != "" && currentData[constants.EnvKeyMicrosoftActiveDirectoryTenantID].(string) != "" + isCurrentMicrosoftLoginEnabled := currentData[constants.EnvKeyMicrosoftClientID] != nil && currentData[constants.EnvKeyMicrosoftClientSecret] != nil && currentData[constants.EnvKeyMicrosoftClientID].(string) != "" && currentData[constants.EnvKeyMicrosoftClientSecret].(string) != "" isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool) isUpdatedMobileBasicAuthEnabled := !updatedData[constants.EnvKeyDisableMobileBasicAuthentication].(bool) @@ -44,7 +44,7 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) { isUpdatedGithubLoginEnabled := updatedData[constants.EnvKeyGithubClientID] != nil && updatedData[constants.EnvKeyGithubClientSecret] != nil && updatedData[constants.EnvKeyGithubClientID].(string) != "" && updatedData[constants.EnvKeyGithubClientSecret].(string) != "" isUpdatedLinkedInLoginEnabled := updatedData[constants.EnvKeyLinkedInClientID] != nil && updatedData[constants.EnvKeyLinkedInClientSecret] != nil && updatedData[constants.EnvKeyLinkedInClientID].(string) != "" && updatedData[constants.EnvKeyLinkedInClientSecret].(string) != "" isUpdatedTwitterLoginEnabled := updatedData[constants.EnvKeyTwitterClientID] != nil && updatedData[constants.EnvKeyTwitterClientSecret] != nil && updatedData[constants.EnvKeyTwitterClientID].(string) != "" && updatedData[constants.EnvKeyTwitterClientSecret].(string) != "" - isUpdatedMicrosoftLoginEnabled := updatedData[constants.EnvKeyMicrosoftClientID] != nil && updatedData[constants.EnvKeyMicrosoftClientSecret] != nil && updatedData[constants.EnvKeyMicrosoftActiveDirectoryTenantID] != nil && updatedData[constants.EnvKeyMicrosoftClientID].(string) != "" && updatedData[constants.EnvKeyMicrosoftClientSecret].(string) != "" && updatedData[constants.EnvKeyMicrosoftActiveDirectoryTenantID].(string) != "" + isUpdatedMicrosoftLoginEnabled := updatedData[constants.EnvKeyMicrosoftClientID] != nil && updatedData[constants.EnvKeyMicrosoftClientSecret] != nil && updatedData[constants.EnvKeyMicrosoftClientID].(string) != "" && updatedData[constants.EnvKeyMicrosoftClientSecret].(string) != "" if isCurrentBasicAuthEnabled && !isUpdatedBasicAuthEnabled { memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth) @@ -267,6 +267,13 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model updatedData[constants.EnvKeyIsEmailServiceEnabled] = true } + if updatedData[constants.EnvKeyTwilioAPIKey] == "" || updatedData[constants.EnvKeyTwilioAPISecret] == "" || updatedData[constants.EnvKeyTwilioAccountSID] == "" || updatedData[constants.EnvKeyTwilioSender] == "" { + updatedData[constants.EnvKeyIsSMSServiceEnabled] = false + if !updatedData[constants.EnvKeyIsSMSServiceEnabled].(bool) { + updatedData[constants.EnvKeyDisablePhoneVerification] = true + } + } + if !currentData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && updatedData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && !updatedData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) { go db.Provider.UpdateUsers(ctx, map[string]interface{}{ "is_multi_factor_auth_enabled": true, diff --git a/server/resolvers/update_profile.go b/server/resolvers/update_profile.go index da74258..c478182 100644 --- a/server/resolvers/update_profile.go +++ b/server/resolvers/update_profile.go @@ -2,6 +2,7 @@ package resolvers import ( "context" + "encoding/json" "errors" "fmt" "strings" @@ -47,7 +48,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) } // validate if all params are not empty - if params.GivenName == nil && params.FamilyName == nil && params.Picture == nil && params.MiddleName == nil && params.Nickname == nil && params.OldPassword == nil && params.Email == nil && params.Birthdate == nil && params.Gender == nil && params.PhoneNumber == nil && params.NewPassword == nil && params.ConfirmNewPassword == nil && params.IsMultiFactorAuthEnabled == nil { + if params.GivenName == nil && params.FamilyName == nil && params.Picture == nil && params.MiddleName == nil && params.Nickname == nil && params.OldPassword == nil && params.Email == nil && params.Birthdate == nil && params.Gender == nil && params.PhoneNumber == nil && params.NewPassword == nil && params.ConfirmNewPassword == nil && params.IsMultiFactorAuthEnabled == nil && params.AppData == nil { log.Debug("All params are empty") return res, fmt.Errorf("please enter at least one param to update") } @@ -56,7 +57,6 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) log := log.WithFields(log.Fields{ "user_id": userID, }) - user, err := db.Provider.GetUserByID(ctx, userID) if err != nil { log.Debug("Failed to get user by id: ", err) @@ -99,7 +99,16 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) if params.Picture != nil && refs.StringValue(user.Picture) != refs.StringValue(params.Picture) { user.Picture = params.Picture } - + if params.AppData != nil { + appDataString := "" + appDataBytes, err := json.Marshal(params.AppData) + if err != nil { + log.Debug("failed to marshall source app_data: ", err) + return nil, errors.New("malformed app_data") + } + appDataString = string(appDataBytes) + user.AppData = &appDataString + } if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) { if refs.BoolValue(params.IsMultiFactorAuthEnabled) { isEnvServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled) @@ -242,7 +251,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) log.Debug("Failed to create verification token: ", err) return res, err } - _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{ + _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ Token: verificationToken, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), diff --git a/server/resolvers/update_user.go b/server/resolvers/update_user.go index bd61428..ee751ab 100644 --- a/server/resolvers/update_user.go +++ b/server/resolvers/update_user.go @@ -2,6 +2,7 @@ package resolvers import ( "context" + "encoding/json" "errors" "fmt" "strings" @@ -95,6 +96,17 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod user.Picture = params.Picture } + if params.AppData != nil { + appDataString := "" + appDataBytes, err := json.Marshal(params.AppData) + if err != nil { + log.Debug("failed to marshall source app_data: ", err) + return nil, errors.New("malformed app_data") + } + appDataString = string(appDataBytes) + user.AppData = &appDataString + } + if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) { user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled if refs.BoolValue(params.IsMultiFactorAuthEnabled) { @@ -147,7 +159,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod if err != nil { log.Debug("Failed to create verification token: ", err) } - _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{ + _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ Token: verificationToken, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), diff --git a/server/resolvers/update_webhook.go b/server/resolvers/update_webhook.go index 5783984..3d09568 100644 --- a/server/resolvers/update_webhook.go +++ b/server/resolvers/update_webhook.go @@ -41,7 +41,7 @@ func UpdateWebhookResolver(ctx context.Context, params model.UpdateWebhookReques } headersString = string(headerBytes) } - webhookDetails := models.Webhook{ + webhookDetails := &models.Webhook{ ID: webhook.ID, Key: webhook.ID, EventName: refs.StringValue(webhook.EventName), diff --git a/server/resolvers/validate_session.go b/server/resolvers/validate_session.go new file mode 100644 index 0000000..39adb1f --- /dev/null +++ b/server/resolvers/validate_session.go @@ -0,0 +1,61 @@ +package resolvers + +import ( + "context" + "errors" + "fmt" + + "github.com/authorizerdev/authorizer/server/cookie" + "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/server/token" + "github.com/authorizerdev/authorizer/server/utils" + log "github.com/sirupsen/logrus" +) + +// ValidateSessionResolver is used to validate a cookie session without its rotation +func ValidateSessionResolver(ctx context.Context, params *model.ValidateSessionInput) (*model.ValidateSessionResponse, error) { + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug("Failed to get GinContext: ", err) + return nil, err + } + sessionToken := params.Cookie + if sessionToken == "" { + sessionToken, err = cookie.GetSession(gc) + if err != nil { + log.Debug("Failed to get session token: ", err) + return nil, errors.New("unauthorized") + } + } + claims, err := token.ValidateBrowserSession(gc, sessionToken) + if err != nil { + log.Debug("Failed to validate session token", err) + return nil, errors.New("unauthorized") + } + userID := claims.Subject + log := log.WithFields(log.Fields{ + "user_id": userID, + }) + user, err := db.Provider.GetUserByID(ctx, userID) + if err != nil { + log.Debug("Failed to get user: ", err) + return nil, err + } + // refresh token has "roles" as claim + claimRoleInterface := claims.Roles + claimRoles := []string{} + claimRoles = append(claimRoles, claimRoleInterface...) + if params != nil && params.Roles != nil && len(params.Roles) > 0 { + for _, v := range params.Roles { + if !utils.StringSliceContains(claimRoles, v) { + log.Debug("User does not have required role: ", claimRoles, v) + return nil, fmt.Errorf(`unauthorized`) + } + } + } + return &model.ValidateSessionResponse{ + IsValid: true, + User: user.AsAPIUser(), + }, nil +} diff --git a/server/resolvers/verification_requests.go b/server/resolvers/verification_requests.go index 4a629de..9a55be7 100644 --- a/server/resolvers/verification_requests.go +++ b/server/resolvers/verification_requests.go @@ -27,7 +27,6 @@ func VerificationRequestsResolver(ctx context.Context, params *model.PaginatedIn } pagination := utils.GetPagination(params) - res, err := db.Provider.ListVerificationRequests(ctx, pagination) if err != nil { log.Debug("Failed to get verification requests: ", err) diff --git a/server/resolvers/verify_email.go b/server/resolvers/verify_email.go index d1fd81d..d263629 100644 --- a/server/resolvers/verify_email.go +++ b/server/resolvers/verify_email.go @@ -125,11 +125,13 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m go func() { if isSignUp { utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user) + // User is also logged in with signup + utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) } else { utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) } - db.Provider.AddSession(ctx, models.Session{ + db.Provider.AddSession(ctx, &models.Session{ UserID: user.ID, UserAgent: utils.GetUserAgent(gc.Request), IP: utils.GetIP(gc.Request), diff --git a/server/resolvers/verify_mobile.go b/server/resolvers/verify_mobile.go deleted file mode 100644 index 4e077d7..0000000 --- a/server/resolvers/verify_mobile.go +++ /dev/null @@ -1,62 +0,0 @@ -package resolvers - -import ( - "fmt" - "context" - "time" - - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/db" - log "github.com/sirupsen/logrus" -) - -func VerifyMobileResolver(ctx context.Context, params model.VerifyMobileRequest) (*model.AuthResponse, error) { - var res *model.AuthResponse - - _, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - smsVerificationRequest, err := db.Provider.GetCodeByPhone(ctx, params.PhoneNumber) - if err != nil { - log.Debug("Failed to get sms request by phone: ", err) - return res, err - } - - if smsVerificationRequest.Code != params.Code { - log.Debug("Failed to verify request: bad credentials") - return res, fmt.Errorf(`bad credentials`) - } - - expiresIn := smsVerificationRequest.CodeExpiresAt - time.Now().Unix() - if expiresIn < 0 { - log.Debug("Failed to verify sms request: Timeout") - return res, fmt.Errorf("time expired") - } - - res = &model.AuthResponse{ - Message: "successful", - } - - user, err := db.Provider.GetUserByPhoneNumber(ctx, params.PhoneNumber) - if user.PhoneNumberVerifiedAt == nil { - now := time.Now().Unix() - user.PhoneNumberVerifiedAt = &now - } - - _, err = db.Provider.UpdateUser(ctx, *user) - if err != nil { - log.Debug("Failed to update user: ", err) - return res, err - } - - err = db.Provider.DeleteSMSRequest(ctx, smsVerificationRequest) - if err != nil { - log.Debug("Failed to delete sms request: ", err.Error()) - } - - return res, err -} diff --git a/server/resolvers/verify_otp.go b/server/resolvers/verify_otp.go index 80080d9..bab3323 100644 --- a/server/resolvers/verify_otp.go +++ b/server/resolvers/verify_otp.go @@ -28,35 +28,62 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod return res, err } - otp, err := db.Provider.GetOTPByEmail(ctx, params.Email) + mfaSession, err := cookie.GetMfaSession(gc) if err != nil { log.Debug("Failed to get otp request by email: ", err) - return res, fmt.Errorf(`invalid email: %s`, err.Error()) + return res, fmt.Errorf(`invalid session: %s`, err.Error()) } + if refs.StringValue(params.Email) == "" && refs.StringValue(params.PhoneNumber) == "" { + log.Debug("Email or phone number is required") + return res, fmt.Errorf(`email or phone_number is required`) + } + + currentField := models.FieldNameEmail + if refs.StringValue(params.Email) == "" { + currentField = models.FieldNamePhoneNumber + } + var otp *models.OTP + if currentField == models.FieldNameEmail { + otp, err = db.Provider.GetOTPByEmail(ctx, refs.StringValue(params.Email)) + } else { + otp, err = db.Provider.GetOTPByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber)) + } + if otp == nil && err != nil { + log.Debugf("Failed to get otp request for %s: %s", currentField, err.Error()) + return res, fmt.Errorf(`invalid %s: %s`, currentField, err.Error()) + } if params.Otp != otp.Otp { log.Debug("Failed to verify otp request: Incorrect value") return res, fmt.Errorf(`invalid otp`) } - expiresIn := otp.ExpiresAt - time.Now().Unix() - if expiresIn < 0 { log.Debug("Failed to verify otp request: Timeout") return res, fmt.Errorf("otp expired") } - - user, err := db.Provider.GetUserByEmail(ctx, params.Email) - if err != nil { - log.Debug("Failed to get user by email: ", err) + 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 } - isSignUp := user.EmailVerifiedAt == nil + if _, err := memorystore.Provider.GetMfaSession(user.ID, mfaSession); err != nil { + log.Debug("Failed to get mfa session: ", err) + return res, fmt.Errorf(`invalid session: %s`, err.Error()) + } + isSignUp := user.EmailVerifiedAt == nil && user.PhoneNumberVerifiedAt == nil // TODO - Add Login method in DB when we introduce OTP for social media login loginMethod := constants.AuthRecipeMethodBasicAuth - + if currentField == models.FieldNamePhoneNumber { + loginMethod = constants.AuthRecipeMethodMobileOTP + } roles := strings.Split(user.Roles, ",") scope := []string{"openid", "email", "profile"} code := "" @@ -97,11 +124,13 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod db.Provider.DeleteOTP(gc, otp) if isSignUp { utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user) + // User is also logged in with signup + utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) } else { utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) } - db.Provider.AddSession(ctx, models.Session{ + db.Provider.AddSession(ctx, &models.Session{ UserID: user.ID, UserAgent: utils.GetUserAgent(gc.Request), IP: utils.GetIP(gc.Request), diff --git a/server/resolvers/webhook_logs.go b/server/resolvers/webhook_logs.go index 7c9cc7b..cd7b62d 100644 --- a/server/resolvers/webhook_logs.go +++ b/server/resolvers/webhook_logs.go @@ -25,7 +25,7 @@ func WebhookLogsResolver(ctx context.Context, params *model.ListWebhookLogReques return nil, fmt.Errorf("unauthorized") } - var pagination model.Pagination + var pagination *model.Pagination var webhookID string if params != nil { @@ -37,7 +37,7 @@ func WebhookLogsResolver(ctx context.Context, params *model.ListWebhookLogReques pagination = utils.GetPagination(nil) webhookID = "" } - + // TODO fix webhookLogs, err := db.Provider.ListWebhookLogs(ctx, pagination, webhookID) if err != nil { log.Debug("failed to get webhook logs: ", err) diff --git a/server/resolvers/webhooks.go b/server/resolvers/webhooks.go index 5a6ccbb..733df82 100644 --- a/server/resolvers/webhooks.go +++ b/server/resolvers/webhooks.go @@ -25,7 +25,6 @@ func WebhooksResolver(ctx context.Context, params *model.PaginatedInput) (*model } pagination := utils.GetPagination(params) - webhooks, err := db.Provider.ListWebhook(ctx, pagination) if err != nil { log.Debug("failed to get webhooks: ", err) diff --git a/server/smsproviders/twilio.go b/server/smsproviders/twilio.go index 093e924..f4f1acb 100644 --- a/server/smsproviders/twilio.go +++ b/server/smsproviders/twilio.go @@ -1,43 +1,38 @@ package smsproviders import ( - twilio "github.com/twilio/twilio-go" - api "github.com/twilio/twilio-go/rest/api/v2010" "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/memorystore" log "github.com/sirupsen/logrus" + twilio "github.com/twilio/twilio-go" + api "github.com/twilio/twilio-go/rest/api/v2010" ) +// SendSMS util to send sms // TODO: Should be restructured to interface when another provider is added func SendSMS(sendTo, messageBody string) error { - twilioAPISecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwilioAPISecret) - if err != nil || twilioAPISecret == ""{ - log.Errorf("Failed to get api secret: ", err) + if err != nil || twilioAPISecret == "" { + log.Debug("Failed to get api secret: ", err) return err } - twilioAPIKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwilioAPIKey) - if err != nil || twilioAPIKey == ""{ - log.Errorf("Failed to get api key: ", err) + if err != nil || twilioAPIKey == "" { + log.Debug("Failed to get api key: ", err) return err } - - twilioSenderFrom, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwilioSenderFrom) + twilioSenderFrom, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwilioSender) if err != nil || twilioSenderFrom == "" { - log.Errorf("Failed to get sender: ", err) + log.Debug("Failed to get sender: ", err) return err } - // accountSID is not a must to send sms on twilio twilioAccountSID, _ := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwilioAccountSID) - client := twilio.NewRestClientWithParams(twilio.ClientParams{ Username: twilioAPIKey, Password: twilioAPISecret, AccountSid: twilioAccountSID, }) - message := &api.CreateMessageParams{} message.SetBody(messageBody) message.SetFrom(twilioSenderFrom) diff --git a/server/test/admin_signup_test.go b/server/test/admin_signup_test.go index 9596f4d..9e42553 100644 --- a/server/test/admin_signup_test.go +++ b/server/test/admin_signup_test.go @@ -17,11 +17,10 @@ func adminSignupTests(t *testing.T, s TestSetup) { _, err := resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{ AdminSecret: "admin", }) - assert.NotNil(t, err) // reset env for test to pass - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyAdminSecret, "") - + err = memorystore.Provider.UpdateEnvVariable(constants.EnvKeyAdminSecret, "") + assert.Nil(t, err) _, err = resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{ AdminSecret: "admin123", }) diff --git a/server/test/delete_email_template_test.go b/server/test/delete_email_template_test.go index ef79db9..c32b6d5 100644 --- a/server/test/delete_email_template_test.go +++ b/server/test/delete_email_template_test.go @@ -24,7 +24,7 @@ func deleteEmailTemplateTest(t *testing.T, s TestSetup) { req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) // get all email templates - emailTemplates, err := db.Provider.ListEmailTemplate(ctx, model.Pagination{ + emailTemplates, err := db.Provider.ListEmailTemplate(ctx, &model.Pagination{ Limit: 10, Page: 1, Offset: 0, @@ -41,7 +41,7 @@ func deleteEmailTemplateTest(t *testing.T, s TestSetup) { assert.NotEmpty(t, res.Message) } - emailTemplates, err = db.Provider.ListEmailTemplate(ctx, model.Pagination{ + emailTemplates, err = db.Provider.ListEmailTemplate(ctx, &model.Pagination{ Limit: 10, Page: 1, Offset: 0, diff --git a/server/test/delete_webhook_test.go b/server/test/delete_webhook_test.go index ab9b9f2..3404a42 100644 --- a/server/test/delete_webhook_test.go +++ b/server/test/delete_webhook_test.go @@ -24,7 +24,7 @@ func deleteWebhookTest(t *testing.T, s TestSetup) { req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) // get all webhooks - webhooks, err := db.Provider.ListWebhook(ctx, model.Pagination{ + webhooks, err := db.Provider.ListWebhook(ctx, &model.Pagination{ Limit: 20, Page: 1, Offset: 0, @@ -41,14 +41,14 @@ func deleteWebhookTest(t *testing.T, s TestSetup) { assert.NotEmpty(t, res.Message) } - webhooks, err = db.Provider.ListWebhook(ctx, model.Pagination{ + webhooks, err = db.Provider.ListWebhook(ctx, &model.Pagination{ Limit: 20, Page: 1, Offset: 0, }) assert.NoError(t, err) assert.Len(t, webhooks.Webhooks, 0) - webhookLogs, err := db.Provider.ListWebhookLogs(ctx, model.Pagination{ + webhookLogs, err := db.Provider.ListWebhookLogs(ctx, &model.Pagination{ Limit: 100, Page: 1, Offset: 0, diff --git a/server/test/resolvers_test.go b/server/test/integration_test.go similarity index 89% rename from server/test/resolvers_test.go rename to server/test/integration_test.go index 4c83bf3..3d4bb3d 100644 --- a/server/test/resolvers_test.go +++ b/server/test/integration_test.go @@ -9,6 +9,7 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/env" "github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/utils" @@ -46,7 +47,6 @@ func TestResolvers(t *testing.T) { for dbType, dbURL := range databases { ctx := context.Background() - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseURL, dbURL) memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseType, dbType) memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseName, testDb) @@ -57,6 +57,11 @@ func TestResolvers(t *testing.T) { if dbType == constants.DbTypeDynamoDB { memorystore.Provider.UpdateEnvVariable(constants.EnvAwsRegion, "ap-south-1") os.Setenv(constants.EnvAwsRegion, "ap-south-1") + os.Unsetenv(constants.EnvAwsAccessKeyID) + os.Unsetenv(constants.EnvAwsSecretAccessKey) + // Remove aws credentials from env, so that local dynamodb can be used + memorystore.Provider.UpdateEnvVariable(constants.EnvAwsAccessKeyID, "") + memorystore.Provider.UpdateEnvVariable(constants.EnvAwsSecretAccessKey, "") } if dbType == constants.DbTypeCouchbaseDB { memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseUsername, "Administrator") @@ -74,8 +79,10 @@ func TestResolvers(t *testing.T) { // clean the persisted config for test to use fresh config envData, err := db.Provider.GetEnv(ctx) - if err == nil && envData.ID != "" { - envData.EnvData = "" + if err == nil && envData == nil { + envData = &models.Env{ + EnvData: "", + } _, err = db.Provider.UpdateEnv(ctx, envData) if err != nil { t.Logf("Error updating env: %s", err.Error()) @@ -135,7 +142,7 @@ func TestResolvers(t *testing.T) { validateJwtTokenTest(t, s) verifyOTPTest(t, s) resendOTPTest(t, s) - verifyMobileTest(t, s) + validateSessionTests(t, s) updateAllUsersTest(t, s) webhookLogsTest(t, s) // get logs after above resolver tests are done diff --git a/server/test/mobile_login_test.go b/server/test/mobile_login_test.go index 48b7690..6f0823c 100644 --- a/server/test/mobile_login_test.go +++ b/server/test/mobile_login_test.go @@ -1,14 +1,18 @@ package test import ( + "fmt" "strings" "testing" + "time" "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" "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/google/uuid" "github.com/stretchr/testify/assert" ) @@ -26,11 +30,6 @@ func mobileLoginTests(t *testing.T, s TestSetup) { }) assert.NoError(t, err) assert.NotNil(t, signUpRes) - assert.Equal(t, email, signUpRes.User.Email) - assert.Equal(t, phoneNumber, refs.StringValue(signUpRes.User.PhoneNumber)) - assert.True(t, strings.Contains(signUpRes.User.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth)) - assert.Len(t, strings.Split(signUpRes.User.SignupMethods, ","), 1) - res, err := resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{ PhoneNumber: phoneNumber, Password: "random_test", @@ -45,7 +44,6 @@ func mobileLoginTests(t *testing.T, s TestSetup) { }) assert.Error(t, err) assert.Nil(t, res) - // should fail because phone is not verified res, err = resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{ PhoneNumber: phoneNumber, @@ -53,26 +51,28 @@ func mobileLoginTests(t *testing.T, s TestSetup) { }) assert.NotNil(t, err, "should fail because phone is not verified") assert.Nil(t, res) - - smsRequest, err := db.Provider.GetCodeByPhone(ctx, phoneNumber) + smsRequest, err := db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber) assert.NoError(t, err) - assert.NotEmpty(t, smsRequest.Code) - - verifySMSRequest, err := resolvers.VerifyMobileResolver(ctx, model.VerifyMobileRequest{ - PhoneNumber: phoneNumber, - Code: smsRequest.Code, + assert.NotEmpty(t, smsRequest.Otp) + // Get user by phone number + user, err := db.Provider.GetUserByPhoneNumber(ctx, phoneNumber) + assert.NoError(t, err) + assert.NotNil(t, user) + // Set mfa cookie session + mfaSession := uuid.NewString() + memorystore.Provider.SetMfaSession(user.ID, mfaSession, time.Now().Add(1*time.Minute).Unix()) + cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession) + cookie = strings.TrimSuffix(cookie, ";") + req, ctx := createContext(s) + req.Header.Set("Cookie", cookie) + verifySMSRequest, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ + PhoneNumber: &phoneNumber, + Otp: smsRequest.Otp, }) assert.Nil(t, err) assert.NotEqual(t, verifySMSRequest.Message, "", "message should not be empty") - - res, err = resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{ - PhoneNumber: phoneNumber, - Password: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotEmpty(t, res.AccessToken) - assert.NotEmpty(t, res.IDToken) - + assert.NotEmpty(t, verifySMSRequest.AccessToken) + assert.NotEmpty(t, verifySMSRequest.IDToken) cleanData(email) }) } diff --git a/server/test/mobile_signup_test.go b/server/test/mobile_signup_test.go index 11deccc..e0982e1 100644 --- a/server/test/mobile_signup_test.go +++ b/server/test/mobile_signup_test.go @@ -1,13 +1,18 @@ package test import ( + "fmt" + "strings" "testing" + "time" "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/google/uuid" "github.com/stretchr/testify/assert" ) @@ -65,16 +70,36 @@ func mobileSingupTest(t *testing.T, s TestSetup) { }) assert.Error(t, err) assert.Nil(t, res) - + phoneNumber := "1234567890" res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{ - PhoneNumber: "1234567890", + PhoneNumber: phoneNumber, Password: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password, }) assert.NoError(t, err) - assert.NotEmpty(t, res.AccessToken) - assert.Equal(t, "1234567890@authorizer.dev", res.User.Email) - + assert.NotNil(t, res) + assert.True(t, *res.ShouldShowMobileOtpScreen) + // Verify with otp + otp, err := db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber) + assert.Nil(t, err) + assert.NotEmpty(t, otp.Otp) + // Get user by phone number + user, err := db.Provider.GetUserByPhoneNumber(ctx, phoneNumber) + assert.NoError(t, err) + assert.NotNil(t, user) + // Set mfa cookie session + mfaSession := uuid.NewString() + memorystore.Provider.SetMfaSession(user.ID, mfaSession, time.Now().Add(1*time.Minute).Unix()) + cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession) + cookie = strings.TrimSuffix(cookie, ";") + req, ctx := createContext(s) + req.Header.Set("Cookie", cookie) + otpRes, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ + PhoneNumber: &phoneNumber, + Otp: otp.Otp, + }) + assert.Nil(t, err) + assert.NotEmpty(t, otpRes.Message) res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{ PhoneNumber: "1234567890", Password: s.TestInfo.Password, diff --git a/server/test/resend_otp_test.go b/server/test/resend_otp_test.go index 73e715d..3f1e738 100644 --- a/server/test/resend_otp_test.go +++ b/server/test/resend_otp_test.go @@ -2,13 +2,18 @@ package test import ( "context" + "fmt" + "strings" "testing" + "time" "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/google/uuid" "github.com/stretchr/testify/assert" ) @@ -51,7 +56,7 @@ func resendOTPTest(t *testing.T, s TestSetup) { assert.NotNil(t, updateRes) // Resend otp should return error as no initial opt is being sent resendOtpRes, err := resolvers.ResendOTPResolver(ctx, model.ResendOTPRequest{ - Email: email, + Email: refs.NewStringRef(email), }) assert.Error(t, err) assert.Nil(t, resendOtpRes) @@ -72,7 +77,7 @@ func resendOTPTest(t *testing.T, s TestSetup) { // resend otp resendOtpRes, err = resolvers.ResendOTPResolver(ctx, model.ResendOTPRequest{ - Email: email, + Email: refs.NewStringRef(email), }) assert.NoError(t, err) assert.NotEmpty(t, resendOtpRes.Message) @@ -84,13 +89,23 @@ func resendOTPTest(t *testing.T, s TestSetup) { // Should return error for older otp verifyOtpRes, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - Email: email, + Email: &email, Otp: otp.Otp, }) assert.Error(t, err) assert.Nil(t, verifyOtpRes) + // Get user by email + user, err := db.Provider.GetUserByEmail(ctx, email) + assert.NoError(t, err) + assert.NotNil(t, user) + // Set mfa cookie session + mfaSession := uuid.NewString() + memorystore.Provider.SetMfaSession(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) verifyOtpRes, err = resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - Email: email, + Email: &email, Otp: newOtp.Otp, }) assert.NoError(t, err) diff --git a/server/test/test.go b/server/test/test.go index b2727ea..217ad39 100644 --- a/server/test/test.go +++ b/server/test/test.go @@ -126,6 +126,10 @@ func testSetup() TestSetup { memorystore.Provider.UpdateEnvVariable(constants.EnvKeySmtpPassword, "test") memorystore.Provider.UpdateEnvVariable(constants.EnvKeySenderEmail, "info@yopmail.com") memorystore.Provider.UpdateEnvVariable(constants.EnvKeyProtectedRoles, "admin") + memorystore.Provider.UpdateEnvVariable(constants.EnvKeyTwilioAPIKey, "test") + memorystore.Provider.UpdateEnvVariable(constants.EnvKeyTwilioAPISecret, "test") + memorystore.Provider.UpdateEnvVariable(constants.EnvKeyTwilioAccountSID, "test") + memorystore.Provider.UpdateEnvVariable(constants.EnvKeyTwilioSender, "1234567890") err = db.InitDB() if err != nil { diff --git a/server/test/update_all_users_tests.go b/server/test/update_all_users_tests.go index 375158f..b2e507f 100644 --- a/server/test/update_all_users_tests.go +++ b/server/test/update_all_users_tests.go @@ -18,7 +18,7 @@ func updateAllUsersTest(t *testing.T, s TestSetup) { t.Run("Should update all users", func(t *testing.T) { _, ctx := createContext(s) for i := 0; i < 10; i++ { - user := models.User{ + user := &models.User{ Email: fmt.Sprintf("update_all_user_%d_%s", i, s.TestInfo.Email), SignupMethods: constants.AuthRecipeMethodBasicAuth, Roles: "user", @@ -33,7 +33,7 @@ func updateAllUsersTest(t *testing.T, s TestSetup) { }, nil) assert.NoError(t, err) - listUsers, err := db.Provider.ListUsers(ctx, model.Pagination{ + listUsers, err := db.Provider.ListUsers(ctx, &model.Pagination{ Limit: 20, Offset: 0, }) @@ -49,7 +49,7 @@ func updateAllUsersTest(t *testing.T, s TestSetup) { }, updateIds) assert.NoError(t, err) - listUsers, err = db.Provider.ListUsers(ctx, model.Pagination{ + listUsers, err = db.Provider.ListUsers(ctx, &model.Pagination{ Limit: 20, Offset: 0, }) diff --git a/server/test/update_webhook_test.go b/server/test/update_webhook_test.go index 14ccb94..6e2d023 100644 --- a/server/test/update_webhook_test.go +++ b/server/test/update_webhook_test.go @@ -27,7 +27,7 @@ func updateWebhookTest(t *testing.T, s TestSetup) { webhooks, err := db.Provider.GetWebhookByEventName(ctx, constants.UserDeletedWebhookEvent) assert.NoError(t, err) assert.NotNil(t, webhooks) - assert.Equal(t, 2, len(webhooks)) + assert.GreaterOrEqual(t, len(webhooks), 2) for _, webhook := range webhooks { // it should completely replace headers webhook.Headers = map[string]interface{}{ @@ -58,7 +58,7 @@ func updateWebhookTest(t *testing.T, s TestSetup) { // Check if webhooks with new name is as per expected len accessWebhooks, err := db.Provider.GetWebhookByEventName(ctx, constants.UserAccessEnabledWebhookEvent) assert.NoError(t, err) - assert.Equal(t, 3, len(accessWebhooks)) + assert.GreaterOrEqual(t, len(accessWebhooks), 3) // Revert name change res, err = resolvers.UpdateWebhookResolver(ctx, model.UpdateWebhookRequest{ ID: w.ID, @@ -69,7 +69,7 @@ func updateWebhookTest(t *testing.T, s TestSetup) { updatedWebhooks, err := db.Provider.GetWebhookByEventName(ctx, constants.UserDeletedWebhookEvent) assert.NoError(t, err) assert.NotNil(t, updatedWebhooks) - assert.Equal(t, 2, len(updatedWebhooks)) + assert.GreaterOrEqual(t, len(updatedWebhooks), 2) for _, updatedWebhook := range updatedWebhooks { assert.Contains(t, refs.StringValue(updatedWebhook.EventName), constants.UserDeletedWebhookEvent) assert.Len(t, updatedWebhook.Headers, 1) diff --git a/server/test/validate_jwt_token_test.go b/server/test/validate_jwt_token_test.go index d2ab257..f9a108a 100644 --- a/server/test/validate_jwt_token_test.go +++ b/server/test/validate_jwt_token_test.go @@ -39,7 +39,7 @@ func validateJwtTokenTest(t *testing.T, s TestSetup) { }) scope := []string{"openid", "email", "profile", "offline_access"} - user := models.User{ + user := &models.User{ ID: uuid.New().String(), Email: "jwt_test_" + s.TestInfo.Email, Roles: "user", diff --git a/server/test/validate_session_test.go b/server/test/validate_session_test.go new file mode 100644 index 0000000..b9573cb --- /dev/null +++ b/server/test/validate_session_test.go @@ -0,0 +1,62 @@ +package test + +import ( + "fmt" + "strings" + "testing" + + "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/resolvers" + "github.com/authorizerdev/authorizer/server/token" + "github.com/stretchr/testify/assert" +) + +// ValidateSessionTests tests all the validate session resolvers +func validateSessionTests(t *testing.T, s TestSetup) { + t.Helper() + t.Run(`should validate session`, func(t *testing.T) { + req, ctx := createContext(s) + email := "validate_session." + s.TestInfo.Email + + resolvers.SignupResolver(ctx, model.SignUpInput{ + Email: email, + Password: s.TestInfo.Password, + ConfirmPassword: s.TestInfo.Password, + }) + _, err := resolvers.ValidateSessionResolver(ctx, &model.ValidateSessionInput{}) + assert.NotNil(t, err, "unauthorized") + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) + assert.NoError(t, err) + assert.NotNil(t, verificationRequest) + verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ + Token: verificationRequest.Token, + }) + assert.NoError(t, err) + assert.NotNil(t, verifyRes) + accessToken := *verifyRes.AccessToken + assert.NotEmpty(t, accessToken) + claims, err := token.ParseJWTToken(accessToken) + assert.NoError(t, err) + assert.NotEmpty(t, claims) + sessionKey := constants.AuthRecipeMethodBasicAuth + ":" + 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, ";") + res, err := resolvers.ValidateSessionResolver(ctx, &model.ValidateSessionInput{ + Cookie: sessionToken, + }) + assert.Nil(t, err) + assert.True(t, res.IsValid) + req.Header.Set("Cookie", cookie) + res, err = resolvers.ValidateSessionResolver(ctx, &model.ValidateSessionInput{}) + assert.Nil(t, err) + assert.True(t, res.IsValid) + assert.Equal(t, res.User.ID, verifyRes.User.ID) + cleanData(email) + }) +} diff --git a/server/test/verification_requests_test.go b/server/test/verification_requests_test.go index 0d0ce65..e5d5d73 100644 --- a/server/test/verification_requests_test.go +++ b/server/test/verification_requests_test.go @@ -44,9 +44,7 @@ func verificationRequestsTest(t *testing.T, s TestSetup) { assert.Nil(t, err) req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) requests, err = resolvers.VerificationRequestsResolver(ctx, pagination) - assert.Nil(t, err) - rLen := len(requests.VerificationRequests) assert.GreaterOrEqual(t, rLen, 1) diff --git a/server/test/verify_mobile_test.go b/server/test/verify_mobile_test.go deleted file mode 100644 index b4daa5e..0000000 --- a/server/test/verify_mobile_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package test - -import ( - "strings" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func verifyMobileTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should verify mobile`, func(t *testing.T) { - _, ctx := createContext(s) - email := "mobile_verification." + s.TestInfo.Email - phoneNumber := "2234567890" - signUpRes, err := resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{ - Email: refs.NewStringRef(email), - PhoneNumber: phoneNumber, - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, signUpRes) - assert.Equal(t, email, signUpRes.User.Email) - assert.Equal(t, phoneNumber, refs.StringValue(signUpRes.User.PhoneNumber)) - assert.True(t, strings.Contains(signUpRes.User.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth)) - assert.Len(t, strings.Split(signUpRes.User.SignupMethods, ","), 1) - - res, err := resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{ - PhoneNumber: phoneNumber, - Password: "random_test", - }) - assert.Error(t, err) - assert.Nil(t, res) - - // should fail because phone is not verified - res, err = resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{ - PhoneNumber: phoneNumber, - Password: s.TestInfo.Password, - }) - assert.NotNil(t, err, "should fail because phone is not verified") - assert.Nil(t, res) - - // get code from db - smsRequest, err := db.Provider.GetCodeByPhone(ctx, phoneNumber) - assert.NoError(t, err) - assert.NotEmpty(t, smsRequest.Code) - - // throw an error if the code is not correct - verifySMSRequest, err := resolvers.VerifyMobileResolver(ctx, model.VerifyMobileRequest{ - PhoneNumber: phoneNumber, - Code: "rand_12@1", - }) - assert.NotNil(t, err, "should fail because of bad credentials") - assert.Nil(t, verifySMSRequest) - - verifySMSRequest, err = resolvers.VerifyMobileResolver(ctx, model.VerifyMobileRequest{ - PhoneNumber: phoneNumber, - Code: smsRequest.Code, - }) - assert.Nil(t, err) - assert.NotEqual(t, verifySMSRequest.Message, "", "message should not be empty") - - res, err = resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{ - PhoneNumber: phoneNumber, - Password: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotEmpty(t, res.AccessToken) - assert.NotEmpty(t, res.IDToken) - - cleanData(email) - }) -} diff --git a/server/test/verify_otp_test.go b/server/test/verify_otp_test.go index 9e074cd..455ac12 100644 --- a/server/test/verify_otp_test.go +++ b/server/test/verify_otp_test.go @@ -2,13 +2,18 @@ package test import ( "context" + "fmt" + "strings" "testing" + "time" "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/google/uuid" "github.com/stretchr/testify/assert" ) @@ -63,9 +68,18 @@ func verifyOTPTest(t *testing.T, s TestSetup) { otp, err := db.Provider.GetOTPByEmail(ctx, email) assert.NoError(t, err) assert.NotEmpty(t, otp.Otp) - + // Get user by email + user, err := db.Provider.GetUserByEmail(ctx, email) + assert.NoError(t, err) + assert.NotNil(t, user) + // Set mfa cookie session + mfaSession := uuid.NewString() + memorystore.Provider.SetMfaSession(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) verifyOtpRes, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - Email: email, + Email: &email, Otp: otp.Otp, }) assert.Nil(t, err) diff --git a/server/test/webhook_test.go b/server/test/webhook_test.go index 0fb789f..a556f9d 100644 --- a/server/test/webhook_test.go +++ b/server/test/webhook_test.go @@ -28,7 +28,7 @@ func webhookTest(t *testing.T, s TestSetup) { webhooks, err := db.Provider.GetWebhookByEventName(ctx, constants.UserCreatedWebhookEvent) assert.NoError(t, err) assert.NotNil(t, webhooks) - assert.Equal(t, 2, len(webhooks)) + assert.GreaterOrEqual(t, len(webhooks), 2) for _, webhook := range webhooks { res, err := resolvers.WebhookResolver(ctx, model.WebhookRequest{ ID: webhook.ID, diff --git a/server/test/webhooks_test.go b/server/test/webhooks_test.go index 6ed1bb2..74cad74 100644 --- a/server/test/webhooks_test.go +++ b/server/test/webhooks_test.go @@ -30,6 +30,6 @@ func webhooksTest(t *testing.T, s TestSetup) { }) assert.NoError(t, err) assert.NotEmpty(t, webhooks) - assert.Len(t, webhooks.Webhooks, len(s.TestInfo.TestWebhookEventTypes)*2) + assert.GreaterOrEqual(t, len(webhooks.Webhooks), len(s.TestInfo.TestWebhookEventTypes)*2) }) } diff --git a/server/token/auth_token.go b/server/token/auth_token.go index 6d2c942..f482db8 100644 --- a/server/token/auth_token.go +++ b/server/token/auth_token.go @@ -51,7 +51,7 @@ type SessionData struct { } // CreateAuthToken creates a new auth token when userlogs in -func CreateAuthToken(gc *gin.Context, user models.User, roles, scope []string, loginMethod, nonce string, code string) (*Token, error) { +func CreateAuthToken(gc *gin.Context, user *models.User, roles, scope []string, loginMethod, nonce string, code string) (*Token, error) { hostname := parsers.GetHost(gc) _, fingerPrintHash, sessionTokenExpiresAt, err := CreateSessionToken(user, nonce, roles, scope, loginMethod) if err != nil { @@ -104,7 +104,7 @@ func CreateAuthToken(gc *gin.Context, user models.User, roles, scope []string, l } // CreateSessionToken creates a new session token -func CreateSessionToken(user models.User, nonce string, roles, scope []string, loginMethod string) (*SessionData, string, int64, error) { +func CreateSessionToken(user *models.User, nonce string, roles, scope []string, loginMethod string) (*SessionData, string, int64, error) { expiresAt := time.Now().AddDate(1, 0, 0).Unix() fingerPrintMap := &SessionData{ Nonce: nonce, @@ -125,7 +125,7 @@ func CreateSessionToken(user models.User, nonce string, roles, scope []string, l } // CreateRefreshToken util to create JWT token -func CreateRefreshToken(user models.User, roles, scopes []string, hostname, nonce, loginMethod string) (string, int64, error) { +func CreateRefreshToken(user *models.User, roles, scopes []string, hostname, nonce, loginMethod string) (string, int64, error) { // expires in 1 year expiryBound := time.Hour * 8760 expiresAt := time.Now().Add(expiryBound).Unix() @@ -157,7 +157,7 @@ func CreateRefreshToken(user models.User, roles, scopes []string, hostname, nonc // CreateAccessToken util to create JWT token, based on // user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT -func CreateAccessToken(user models.User, roles, scopes []string, hostName, nonce, loginMethod string) (string, int64, error) { +func CreateAccessToken(user *models.User, roles, scopes []string, hostName, nonce, loginMethod string) (string, int64, error) { expireTime, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAccessTokenExpiryTime) if err != nil { return "", 0, err @@ -372,7 +372,7 @@ func ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionD // user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT // For response_type (code) / authorization_code grant nonce should be empty // for implicit flow it should be present to verify with actual state -func CreateIDToken(user models.User, roles []string, hostname, nonce, atHash, cHash, loginMethod string) (string, int64, error) { +func CreateIDToken(user *models.User, roles []string, hostname, nonce, atHash, cHash, loginMethod string) (string, int64, error) { expireTime, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAccessTokenExpiryTime) if err != nil { return "", 0, err diff --git a/server/utils/pagination.go b/server/utils/pagination.go index e27eb53..384eebd 100644 --- a/server/utils/pagination.go +++ b/server/utils/pagination.go @@ -7,10 +7,9 @@ import ( // GetPagination helps getting pagination data from paginated input // also returns default limit and offset if pagination data is not present -func GetPagination(paginatedInput *model.PaginatedInput) model.Pagination { +func GetPagination(paginatedInput *model.PaginatedInput) *model.Pagination { limit := int64(constants.DefaultLimit) page := int64(1) - if paginatedInput != nil && paginatedInput.Pagination != nil { if paginatedInput.Pagination.Limit != nil { limit = *paginatedInput.Pagination.Limit @@ -21,7 +20,7 @@ func GetPagination(paginatedInput *model.PaginatedInput) model.Pagination { } } - return model.Pagination{ + return &model.Pagination{ Limit: limit, Offset: (page - 1) * limit, Page: page, diff --git a/server/utils/webhook.go b/server/utils/webhook.go index 705c571..2571cf5 100644 --- a/server/utils/webhook.go +++ b/server/utils/webhook.go @@ -16,10 +16,12 @@ import ( log "github.com/sirupsen/logrus" ) -func RegisterEvent(ctx context.Context, eventName string, authRecipe string, user models.User) error { +// RegisterEvent util to register event +// TODO change user to user ref +func RegisterEvent(ctx context.Context, eventName string, authRecipe string, user *models.User) error { webhooks, err := db.Provider.GetWebhookByEventName(ctx, eventName) if err != nil { - log.Debug("Error getting webhook: %v", err) + log.Debug("error getting webhook: %v", err) return err } for _, webhook := range webhooks { @@ -61,7 +63,7 @@ func RegisterEvent(ctx context.Context, eventName string, authRecipe string, use continue } if envKey == constants.TestEnv { - _, err := db.Provider.AddWebhookLog(ctx, models.WebhookLog{ + _, err := db.Provider.AddWebhookLog(ctx, &models.WebhookLog{ HttpStatus: 200, Request: string(requestBody), Response: string(`{"message": "test"}`), @@ -102,7 +104,7 @@ func RegisterEvent(ctx context.Context, eventName string, authRecipe string, use } statusCode := int64(resp.StatusCode) - _, err = db.Provider.AddWebhookLog(ctx, models.WebhookLog{ + _, err = db.Provider.AddWebhookLog(ctx, &models.WebhookLog{ HttpStatus: statusCode, Request: string(requestBody), Response: string(responseBytes),