Compare commits
128 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
891c885f20 | ||
![]() |
89606615dc | ||
![]() |
ecab47b2ea | ||
![]() |
882756ef3a | ||
![]() |
a208c87c29 | ||
![]() |
70ea463f60 | ||
![]() |
79c94fcaf0 | ||
![]() |
3b925bb072 | ||
![]() |
df17ea8f40 | ||
![]() |
94066d4408 | ||
![]() |
41468b5b60 | ||
![]() |
1c61fcc17a | ||
![]() |
a102924fd7 | ||
![]() |
390846c85f | ||
![]() |
a48b809a89 | ||
![]() |
cd46da60a0 | ||
![]() |
50f52a99b4 | ||
![]() |
150b1e5712 | ||
![]() |
1f7eee43e2 | ||
![]() |
7c441fff14 | ||
![]() |
647cc1d9bf | ||
![]() |
97b1d8d66f | ||
![]() |
2cce1c4e93 | ||
![]() |
8b1511a07b | ||
![]() |
a69dd95992 | ||
![]() |
d3260f4f32 | ||
![]() |
301bde4da2 | ||
![]() |
913c5c94fb | ||
![]() |
610896b6f5 | ||
![]() |
33f79872be | ||
![]() |
8fc52d76dc | ||
![]() |
aa12757155 | ||
![]() |
847c364ad1 | ||
![]() |
eabc943452 | ||
![]() |
41a0f15e16 | ||
![]() |
e2294c24d0 | ||
![]() |
a3c0a0422c | ||
![]() |
d837b1590a | ||
![]() |
283e570ebb | ||
![]() |
14c74f6566 | ||
![]() |
8e655daa71 | ||
![]() |
fed092bb65 | ||
![]() |
6d28290605 | ||
![]() |
2de0ea57d0 | ||
![]() |
f2886e6da8 | ||
![]() |
6b57bce6d9 | ||
![]() |
bfbeb6add2 | ||
![]() |
1fe0d65874 | ||
![]() |
bfaa0f9d89 | ||
![]() |
4f5a6c77f8 | ||
![]() |
018a13ab3c | ||
![]() |
334041d0e4 | ||
![]() |
6a8309a231 | ||
![]() |
6347b60753 | ||
![]() |
bbb064b939 | ||
![]() |
e91a819067 | ||
![]() |
09c3eafe6b | ||
![]() |
bb51775d34 | ||
![]() |
6d586b16e4 | ||
![]() |
e8eb62769e | ||
![]() |
0ffb3f67f1 | ||
![]() |
ec62686fbc | ||
![]() |
a8064e79a1 | ||
![]() |
265331801f | ||
![]() |
6a74a50493 | ||
![]() |
8c27f20534 | ||
![]() |
29c6003ea3 | ||
![]() |
ae34fc7c2b | ||
![]() |
2a5d5d43b0 | ||
![]() |
e6a4670ba9 | ||
![]() |
64d64b4099 | ||
![]() |
88f9a10f21 | ||
![]() |
4e08d4f8fd | ||
![]() |
1c4dda9299 | ||
![]() |
ab18fa5832 | ||
![]() |
484d0c0882 | ||
![]() |
be59c3615f | ||
![]() |
db351f7771 | ||
![]() |
91c29c4092 | ||
![]() |
415b97535e | ||
![]() |
7d1272d815 | ||
![]() |
c9ba0b13f8 | ||
![]() |
fadd9f6168 | ||
![]() |
395e2e2a85 | ||
![]() |
6335084835 | ||
![]() |
eab336cd3d | ||
![]() |
f4691fca1f | ||
![]() |
341d4fbae5 | ||
![]() |
e467b45ab1 | ||
![]() |
7edfad3486 | ||
![]() |
80578b88ac | ||
![]() |
5646e7a0e7 | ||
![]() |
53a592ef63 | ||
![]() |
3337dbd0a4 | ||
![]() |
82a2a42f84 | ||
![]() |
ac49b5bb70 | ||
![]() |
926ab07c07 | ||
![]() |
7a2dbea019 | ||
![]() |
dff50097e8 | ||
![]() |
aff9d3af20 | ||
![]() |
02eb1d6677 | ||
![]() |
78a673e4ad | ||
![]() |
e0d8644264 | ||
![]() |
d8c662eaad | ||
![]() |
6d1d259f71 | ||
![]() |
2841853d37 | ||
![]() |
360dd3c3bd | ||
![]() |
c6add0cca6 | ||
![]() |
7ac6252aac | ||
![]() |
5d2d1c342b | ||
![]() |
6da0a85936 | ||
![]() |
116972d725 | ||
![]() |
d1e1e287db | ||
![]() |
a7f04f8754 | ||
![]() |
69b56c9912 | ||
![]() |
98015708a2 | ||
![]() |
1b5a7b8fb0 | ||
![]() |
8b9bcdfdbe | ||
![]() |
ba429da05f | ||
![]() |
7c7bb42003 | ||
![]() |
eeff88c853 | ||
![]() |
cf8762b7a0 | ||
![]() |
c61c3024ec | ||
![]() |
7e3bd6a721 | ||
![]() |
1146468a03 | ||
![]() |
268b22ffb2 | ||
![]() |
43359f1dba | ||
![]() |
1941cf4299 |
@@ -1,3 +1,4 @@
|
||||
ENV=production
|
||||
DATABASE_URL=data.db
|
||||
DATABASE_TYPE=sqlite
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT="function(user,tokenPayload){var data = tokenPayload;data.extra = {'x-extra-id': user.id};return data;}"
|
9
.env.test
Normal file
9
.env.test
Normal file
@@ -0,0 +1,9 @@
|
||||
ENV=test
|
||||
DATABASE_URL=test.db
|
||||
DATABASE_TYPE=sqlite
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT="function(user,tokenPayload){var data = tokenPayload;data.extra = {'x-extra-id': user.id};return data;}"
|
||||
SMTP_HOST=smtp.mailtrap.io
|
||||
SMTP_PORT=2525
|
||||
SMTP_USERNAME=test
|
||||
SMTP_PASSWORD=test
|
||||
SENDER_EMAIL="info@authorizer.dev"
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,6 +8,7 @@ dashboard/build
|
||||
build
|
||||
.env
|
||||
data.db
|
||||
test.db
|
||||
.DS_Store
|
||||
.env.local
|
||||
*.tar.gz
|
||||
|
11
Makefile
11
Makefile
@@ -10,7 +10,16 @@ build-dashboard:
|
||||
clean:
|
||||
rm -rf build
|
||||
test:
|
||||
cd server && go clean --testcache && go test -v ./test
|
||||
rm -rf server/test/test.db && rm -rf test.db && cd server && go clean --testcache && TEST_DBS="sqlite" go test -p 1 -v ./test
|
||||
test-all-db:
|
||||
rm -rf server/test/test.db && rm -rf test.db
|
||||
docker run -d --name authorizer_scylla_db -p 9042:9042 scylladb/scylla
|
||||
docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15
|
||||
docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.8.4
|
||||
cd server && go clean --testcache && TEST_DBS="sqlite,mongodb,arangodb,scylladb" go test -p 1 -v ./test
|
||||
docker rm -vf authorizer_mongodb_db
|
||||
docker rm -vf authorizer_scylla_db
|
||||
docker rm -vf authorizer_arangodb
|
||||
generate:
|
||||
cd server && go get github.com/99designs/gqlgen/cmd@v0.14.0 && go run github.com/99designs/gqlgen generate
|
||||
|
42
app/package-lock.json
generated
42
app/package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-react": "^0.17.0",
|
||||
"@authorizerdev/authorizer-react": "^0.25.0",
|
||||
"@types/react": "^17.0.15",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"esbuild": "^0.12.17",
|
||||
@@ -26,9 +26,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@authorizerdev/authorizer-js": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.10.0.tgz",
|
||||
"integrity": "sha512-REM8FLD/Ej9gzA2zDGDAke6QFss33ubePlTDmLDmIYUuQmpHFlO5mCCS6nVsKkN7F/Bcwkmp+eUNQjkdGCaKLg==",
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.14.0.tgz",
|
||||
"integrity": "sha512-cpeeFrmG623QPLn+nf+ACHayZYqW8xokIidGikeboBDJtuAAQB50a54/7HwLHriG2FB7WvPuHQ/9LFFX//N1lg==",
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.6.1"
|
||||
},
|
||||
@@ -37,11 +37,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@authorizerdev/authorizer-react": {
|
||||
"version": "0.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.17.0.tgz",
|
||||
"integrity": "sha512-7WcNCU7hDFkVfFb8LcJXFwWiLYd8aY78z1AbNPxCa2Cw5G85PaRkzjKybP6h01ITVOHO6M03lLwPj8p6Sr6fEg==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.25.0.tgz",
|
||||
"integrity": "sha512-Dt2rZf+cGCVb8dqcJ/9l8Trx+QeXnTdfhER6r/cq0iOnFC9MqWzQPB3RgrlUoMLHtZvKNDXIk1HvfD5hSX9lhw==",
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-js": "^0.10.0",
|
||||
"@authorizerdev/authorizer-js": "^0.14.0",
|
||||
"final-form": "^4.20.2",
|
||||
"react-final-form": "^6.5.3",
|
||||
"styled-components": "^5.3.0"
|
||||
@@ -816,7 +816,7 @@
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.3.5",
|
||||
@@ -838,12 +838,12 @@
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
@@ -852,19 +852,19 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-js": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.10.0.tgz",
|
||||
"integrity": "sha512-REM8FLD/Ej9gzA2zDGDAke6QFss33ubePlTDmLDmIYUuQmpHFlO5mCCS6nVsKkN7F/Bcwkmp+eUNQjkdGCaKLg==",
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.14.0.tgz",
|
||||
"integrity": "sha512-cpeeFrmG623QPLn+nf+ACHayZYqW8xokIidGikeboBDJtuAAQB50a54/7HwLHriG2FB7WvPuHQ/9LFFX//N1lg==",
|
||||
"requires": {
|
||||
"node-fetch": "^2.6.1"
|
||||
}
|
||||
},
|
||||
"@authorizerdev/authorizer-react": {
|
||||
"version": "0.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.17.0.tgz",
|
||||
"integrity": "sha512-7WcNCU7hDFkVfFb8LcJXFwWiLYd8aY78z1AbNPxCa2Cw5G85PaRkzjKybP6h01ITVOHO6M03lLwPj8p6Sr6fEg==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.25.0.tgz",
|
||||
"integrity": "sha512-Dt2rZf+cGCVb8dqcJ/9l8Trx+QeXnTdfhER6r/cq0iOnFC9MqWzQPB3RgrlUoMLHtZvKNDXIk1HvfD5hSX9lhw==",
|
||||
"requires": {
|
||||
"@authorizerdev/authorizer-js": "^0.10.0",
|
||||
"@authorizerdev/authorizer-js": "^0.14.0",
|
||||
"final-form": "^4.20.2",
|
||||
"react-final-form": "^6.5.3",
|
||||
"styled-components": "^5.3.0"
|
||||
@@ -1482,7 +1482,7 @@
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.3.5",
|
||||
@@ -1497,12 +1497,12 @@
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
|
@@ -11,7 +11,7 @@
|
||||
"author": "Lakhan Samani",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-react": "^0.17.0",
|
||||
"@authorizerdev/authorizer-react": "^0.25.0",
|
||||
"@types/react": "^17.0.15",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"esbuild": "^0.12.17",
|
||||
|
@@ -72,7 +72,9 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
||||
</Footer>
|
||||
</Fragment>
|
||||
)}
|
||||
{config.is_sign_up_enabled && (
|
||||
{config.is_basic_authentication_enabled &&
|
||||
!config.is_magic_link_login_enabled &&
|
||||
config.is_sign_up_enabled && (
|
||||
<FooterContent>
|
||||
Don't have an account? <Link to="/app/signup"> Sign Up</Link>
|
||||
</FooterContent>
|
||||
|
12
dashboard/package-lock.json
generated
12
dashboard/package-lock.json
generated
@@ -2529,7 +2529,8 @@
|
||||
"@chakra-ui/css-reset": {
|
||||
"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==",
|
||||
"requires": {}
|
||||
},
|
||||
"@chakra-ui/descendant": {
|
||||
"version": "2.1.1",
|
||||
@@ -3133,7 +3134,8 @@
|
||||
"@graphql-typed-document-node/core": {
|
||||
"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==",
|
||||
"requires": {}
|
||||
},
|
||||
"@popperjs/core": {
|
||||
"version": "2.11.0",
|
||||
@@ -3843,7 +3845,8 @@
|
||||
"react-icons": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz",
|
||||
"integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ=="
|
||||
"integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
@@ -4029,7 +4032,8 @@
|
||||
"use-callback-ref": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz",
|
||||
"integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg=="
|
||||
"integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==",
|
||||
"requires": {}
|
||||
},
|
||||
"use-sidecar": {
|
||||
"version": "1.0.5",
|
||||
|
106
dashboard/src/components/DeleteWebhookModal.tsx
Normal file
106
dashboard/src/components/DeleteWebhookModal.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Button,
|
||||
Center,
|
||||
Flex,
|
||||
MenuItem,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
useDisclosure,
|
||||
Text,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import { useClient } from 'urql';
|
||||
import { FaRegTrashAlt } from 'react-icons/fa';
|
||||
import { DeleteWebhook } from '../graphql/mutation';
|
||||
import { capitalizeFirstLetter } from '../utils';
|
||||
|
||||
interface deleteWebhookModalInputPropTypes {
|
||||
webhookId: string;
|
||||
eventName: string;
|
||||
fetchWebookData: Function;
|
||||
}
|
||||
|
||||
const DeleteWebhookModal = ({
|
||||
webhookId,
|
||||
eventName,
|
||||
fetchWebookData,
|
||||
}: deleteWebhookModalInputPropTypes) => {
|
||||
const client = useClient();
|
||||
const toast = useToast();
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
|
||||
const deleteHandler = async () => {
|
||||
const res = await client
|
||||
.mutation(DeleteWebhook, { params: { id: webhookId } })
|
||||
.toPromise();
|
||||
if (res.error) {
|
||||
toast({
|
||||
title: capitalizeFirstLetter(res.error.message),
|
||||
isClosable: true,
|
||||
status: 'error',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
|
||||
return;
|
||||
} else if (res.data?._delete_webhook) {
|
||||
toast({
|
||||
title: capitalizeFirstLetter(res.data?._delete_webhook.message),
|
||||
isClosable: true,
|
||||
status: 'success',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
}
|
||||
onClose();
|
||||
fetchWebookData();
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={onOpen}>Delete</MenuItem>
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Delete Webhook</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Text fontSize="md">Are you sure?</Text>
|
||||
<Flex
|
||||
padding="5%"
|
||||
marginTop="5%"
|
||||
marginBottom="2%"
|
||||
border="1px solid #ff7875"
|
||||
borderRadius="5px"
|
||||
flexDirection="column"
|
||||
>
|
||||
<Text fontSize="sm">
|
||||
Webhook for event <b>{eventName}</b> will be deleted
|
||||
permanently!
|
||||
</Text>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button
|
||||
leftIcon={<FaRegTrashAlt />}
|
||||
colorScheme="red"
|
||||
variant="solid"
|
||||
onClick={deleteHandler}
|
||||
isDisabled={false}
|
||||
>
|
||||
<Center h="100%" pt="5%">
|
||||
Delete
|
||||
</Center>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeleteWebhookModal;
|
@@ -1,33 +1,34 @@
|
||||
import React from "react";
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react";
|
||||
import React from 'react';
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from '@chakra-ui/react';
|
||||
|
||||
import InputField from "../../components/InputField";
|
||||
import { TextInputType } from "../../constants";
|
||||
import InputField from '../../components/InputField';
|
||||
import { TextInputType } from '../../constants';
|
||||
|
||||
const DatabaseCredentials = ({ variables, setVariables }: any) => {
|
||||
const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)");
|
||||
const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)');
|
||||
return (
|
||||
<div>
|
||||
{" "}
|
||||
{' '}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold">
|
||||
Database Credentials
|
||||
</Text>
|
||||
<Stack spacing={6} padding="3% 0">
|
||||
<Text fontStyle="italic" fontSize="sm" color="blackAlpha.500" mt={3}>
|
||||
Note: Database related environment variables cannot be updated from
|
||||
dashboard :(
|
||||
dashboard. Please use .env file or OS environment variables to update
|
||||
it.
|
||||
</Text>
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "30%" : "40%"}
|
||||
w={isNotSmallerScreen ? '30%' : '40%'}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">DataBase Name:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
@@ -38,17 +39,17 @@ const DatabaseCredentials = ({ variables, setVariables }: any) => {
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "30%" : "40%"}
|
||||
w={isNotSmallerScreen ? '30%' : '40%'}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">DataBase Type:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
@@ -59,17 +60,17 @@ const DatabaseCredentials = ({ variables, setVariables }: any) => {
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "30%" : "40%"}
|
||||
w={isNotSmallerScreen ? '30%' : '40%'}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">DataBase URL:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
|
@@ -3,7 +3,7 @@ import { Flex, Stack, Text } from '@chakra-ui/react';
|
||||
import InputField from '../InputField';
|
||||
import { SwitchInputType } from '../../constants';
|
||||
|
||||
const UICustomization = ({ variables, setVariables }: any) => {
|
||||
const Features = ({ variables, setVariables }: any) => {
|
||||
return (
|
||||
<div>
|
||||
{' '}
|
||||
@@ -71,9 +71,21 @@ const UICustomization = ({ variables, setVariables }: any) => {
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Disable Strong Password:</Text>
|
||||
</Flex>
|
||||
<Flex justifyContent="start" mb={3}>
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={SwitchInputType.DISABLE_STRONG_PASSWORD}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UICustomization;
|
||||
export default Features;
|
@@ -9,7 +9,13 @@ import {
|
||||
Divider,
|
||||
useMediaQuery,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaGoogle, FaGithub, FaFacebookF } from 'react-icons/fa';
|
||||
import {
|
||||
FaGoogle,
|
||||
FaGithub,
|
||||
FaFacebookF,
|
||||
FaLinkedin,
|
||||
FaApple,
|
||||
} from 'react-icons/fa';
|
||||
import { TextInputType, HiddenInputType } from '../../constants';
|
||||
|
||||
const OAuthConfig = ({
|
||||
@@ -182,6 +188,82 @@ const OAuthConfig = ({
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||
h="35px"
|
||||
marginRight="1.5%"
|
||||
border="1px solid #3b5998"
|
||||
borderRadius="5px"
|
||||
>
|
||||
<FaLinkedin style={{ color: '#3b5998' }} />
|
||||
</Center>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
marginRight="1.5%"
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={envVariables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.LINKEDIN_CLIENT_ID}
|
||||
placeholder="LinkedIn Client ID"
|
||||
/>
|
||||
</Center>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={envVariables}
|
||||
setVariables={setVariables}
|
||||
fieldVisibility={fieldVisibility}
|
||||
setFieldVisibility={setFieldVisibility}
|
||||
inputType={HiddenInputType.LINKEDIN_CLIENT_SECRET}
|
||||
placeholder="LinkedIn Client Secret"
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||
h="35px"
|
||||
marginRight="1.5%"
|
||||
border="1px solid #3b5998"
|
||||
borderRadius="5px"
|
||||
>
|
||||
<FaApple style={{ color: '#3b5998' }} />
|
||||
</Center>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
marginRight="1.5%"
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={envVariables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.APPLE_CLIENT_ID}
|
||||
placeholder="Apple Client ID"
|
||||
/>
|
||||
</Center>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={envVariables}
|
||||
setVariables={setVariables}
|
||||
fieldVisibility={fieldVisibility}
|
||||
setFieldVisibility={setFieldVisibility}
|
||||
inputType={HiddenInputType.APPLE_CLIENT_SECRET}
|
||||
placeholder="Apple CLient Secret"
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Box>
|
||||
</div>
|
||||
|
@@ -1,24 +1,25 @@
|
||||
import React from "react";
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react";
|
||||
import { ArrayInputType } from "../../constants";
|
||||
import InputField from "../InputField";
|
||||
import React from 'react';
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from '@chakra-ui/react';
|
||||
import { ArrayInputType } from '../../constants';
|
||||
import InputField from '../InputField';
|
||||
|
||||
const Roles = ({ variables, setVariables }: any) => {
|
||||
const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)");
|
||||
const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)');
|
||||
|
||||
return (
|
||||
<div>
|
||||
{" "}
|
||||
{' '}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||
Roles
|
||||
</Text>
|
||||
<Stack spacing={6} padding="2% 0%">
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Roles:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "2"}
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '2'}
|
||||
overflow="hidden"
|
||||
>
|
||||
<InputField
|
||||
@@ -29,13 +30,13 @@ const Roles = ({ variables, setVariables }: any) => {
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Default Roles:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "2"}
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '2'}
|
||||
>
|
||||
<InputField
|
||||
variables={variables}
|
||||
@@ -44,13 +45,13 @@ const Roles = ({ variables, setVariables }: any) => {
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Protected Roles:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "2"}
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '2'}
|
||||
>
|
||||
<InputField
|
||||
variables={variables}
|
||||
|
@@ -1,25 +1,31 @@
|
||||
import React from "react";
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react";
|
||||
import InputField from "../InputField";
|
||||
import React from 'react';
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from '@chakra-ui/react';
|
||||
import InputField from '../InputField';
|
||||
|
||||
const SessionStorage = ({ variables, setVariables, RedisURL }: any) => {
|
||||
const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)");
|
||||
const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)');
|
||||
return (
|
||||
<div>
|
||||
{" "}
|
||||
{' '}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||
Session Storage
|
||||
</Text>
|
||||
<Text fontStyle="italic" fontSize="sm" color="blackAlpha.500" mt={3}>
|
||||
Note: Redis related environment variables cannot be updated from
|
||||
dashboard. Please use .env file or OS environment variables to update
|
||||
it.
|
||||
</Text>
|
||||
<Stack spacing={6} padding="2% 0%">
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Redis URL:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
disabled
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
|
@@ -22,7 +22,7 @@ import {
|
||||
InputRightElement,
|
||||
Text,
|
||||
Link,
|
||||
Tooltip
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react';
|
||||
import { useClient } from 'urql';
|
||||
import { FaUserPlus, FaMinusCircle, FaPlus, FaUpload } from 'react-icons/fa';
|
||||
@@ -195,14 +195,14 @@ const InviteMembersModal = ({
|
||||
hasArrow
|
||||
bg="gray.300"
|
||||
color="black"
|
||||
label="Email verification is disabled, refer to 'UI Customization' tab within 'Environment' to enable it."
|
||||
label="Email verification is disabled, refer to 'Features' tab within 'Environment' to enable it."
|
||||
>
|
||||
Invite Members
|
||||
</Tooltip>
|
||||
) : (
|
||||
"Invite Members"
|
||||
'Invite Members'
|
||||
)}
|
||||
</Center>{" "}
|
||||
</Center>{' '}
|
||||
</Button>
|
||||
<Modal isOpen={isOpen} onClose={closeModalHandler} size="xl">
|
||||
<ModalOverlay />
|
||||
|
@@ -30,6 +30,7 @@ import {
|
||||
FiMenu,
|
||||
FiUsers,
|
||||
FiChevronDown,
|
||||
FiLink,
|
||||
} from 'react-icons/fi';
|
||||
import { BiCustomize } from 'react-icons/bi';
|
||||
import { AiOutlineKey } from 'react-icons/ai';
|
||||
@@ -98,9 +99,9 @@ const LinkItems: Array<LinkItemProps> = [
|
||||
},
|
||||
{ name: 'Access Token', icon: SiOpenaccess, route: '/access-token' },
|
||||
{
|
||||
name: 'UI Customization',
|
||||
name: 'Features',
|
||||
icon: BiCustomize,
|
||||
route: '/ui-customization',
|
||||
route: '/features',
|
||||
},
|
||||
{ name: 'Database', icon: RiDatabase2Line, route: '/db-cred' },
|
||||
{
|
||||
@@ -111,6 +112,7 @@ const LinkItems: Array<LinkItemProps> = [
|
||||
],
|
||||
},
|
||||
{ name: 'Users', icon: FiUsers, route: '/users' },
|
||||
{ name: 'Webhooks', icon: FiLink, route: '/webhooks' },
|
||||
];
|
||||
|
||||
interface SidebarProps extends BoxProps {
|
||||
|
599
dashboard/src/components/UpdateWebhookModal.tsx
Normal file
599
dashboard/src/components/UpdateWebhookModal.tsx
Normal file
@@ -0,0 +1,599 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Center,
|
||||
Flex,
|
||||
Input,
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
MenuItem,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Select,
|
||||
Switch,
|
||||
Text,
|
||||
useDisclosure,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaMinusCircle, FaPlus } from 'react-icons/fa';
|
||||
import { useClient } from 'urql';
|
||||
import {
|
||||
webhookEventNames,
|
||||
ArrayInputOperations,
|
||||
WebhookInputDataFields,
|
||||
WebhookInputHeaderFields,
|
||||
UpdateWebhookModalViews,
|
||||
webhookVerifiedStatus,
|
||||
} from '../constants';
|
||||
import { capitalizeFirstLetter, validateURI } from '../utils';
|
||||
import { AddWebhook, EditWebhook, TestEndpoint } from '../graphql/mutation';
|
||||
import { rest } from 'lodash';
|
||||
import { BiCheckCircle, BiError, BiErrorCircle } from 'react-icons/bi';
|
||||
|
||||
interface headersDataType {
|
||||
[WebhookInputHeaderFields.KEY]: string;
|
||||
[WebhookInputHeaderFields.VALUE]: string;
|
||||
}
|
||||
|
||||
interface headersValidatorDataType {
|
||||
[WebhookInputHeaderFields.KEY]: boolean;
|
||||
[WebhookInputHeaderFields.VALUE]: boolean;
|
||||
}
|
||||
|
||||
interface selecetdWebhookDataTypes {
|
||||
[WebhookInputDataFields.ID]: string;
|
||||
[WebhookInputDataFields.EVENT_NAME]: string;
|
||||
[WebhookInputDataFields.ENDPOINT]: string;
|
||||
[WebhookInputDataFields.ENABLED]: boolean;
|
||||
[WebhookInputDataFields.HEADERS]?: Record<string, string>;
|
||||
}
|
||||
|
||||
interface UpdateWebhookModalInputPropTypes {
|
||||
view: UpdateWebhookModalViews;
|
||||
selectedWebhook?: selecetdWebhookDataTypes;
|
||||
fetchWebookData: Function;
|
||||
}
|
||||
|
||||
const initHeadersData: headersDataType = {
|
||||
[WebhookInputHeaderFields.KEY]: '',
|
||||
[WebhookInputHeaderFields.VALUE]: '',
|
||||
};
|
||||
|
||||
const initHeadersValidatorData: headersValidatorDataType = {
|
||||
[WebhookInputHeaderFields.KEY]: true,
|
||||
[WebhookInputHeaderFields.VALUE]: true,
|
||||
};
|
||||
|
||||
interface webhookDataType {
|
||||
[WebhookInputDataFields.EVENT_NAME]: string;
|
||||
[WebhookInputDataFields.ENDPOINT]: string;
|
||||
[WebhookInputDataFields.ENABLED]: boolean;
|
||||
[WebhookInputDataFields.HEADERS]: headersDataType[];
|
||||
}
|
||||
|
||||
interface validatorDataType {
|
||||
[WebhookInputDataFields.ENDPOINT]: boolean;
|
||||
[WebhookInputDataFields.HEADERS]: headersValidatorDataType[];
|
||||
}
|
||||
|
||||
const initWebhookData: webhookDataType = {
|
||||
[WebhookInputDataFields.EVENT_NAME]: webhookEventNames.USER_LOGIN,
|
||||
[WebhookInputDataFields.ENDPOINT]: '',
|
||||
[WebhookInputDataFields.ENABLED]: true,
|
||||
[WebhookInputDataFields.HEADERS]: [{ ...initHeadersData }],
|
||||
};
|
||||
|
||||
const initWebhookValidatorData: validatorDataType = {
|
||||
[WebhookInputDataFields.ENDPOINT]: true,
|
||||
[WebhookInputDataFields.HEADERS]: [{ ...initHeadersValidatorData }],
|
||||
};
|
||||
|
||||
const UpdateWebhookModal = ({
|
||||
view,
|
||||
selectedWebhook,
|
||||
fetchWebookData,
|
||||
}: UpdateWebhookModalInputPropTypes) => {
|
||||
const client = useClient();
|
||||
const toast = useToast();
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [verifyingEndpoint, setVerifyingEndpoint] = useState<boolean>(false);
|
||||
const [webhook, setWebhook] = useState<webhookDataType>({
|
||||
...initWebhookData,
|
||||
});
|
||||
const [validator, setValidator] = useState<validatorDataType>({
|
||||
...initWebhookValidatorData,
|
||||
});
|
||||
const [verifiedStatus, setVerifiedStatus] = useState<webhookVerifiedStatus>(
|
||||
webhookVerifiedStatus.PENDING
|
||||
);
|
||||
const inputChangehandler = (
|
||||
inputType: string,
|
||||
value: any,
|
||||
headerInputType: string = WebhookInputHeaderFields.KEY,
|
||||
headerIndex: number = 0
|
||||
) => {
|
||||
if (
|
||||
verifiedStatus !== webhookVerifiedStatus.PENDING &&
|
||||
inputType !== WebhookInputDataFields.ENABLED
|
||||
) {
|
||||
setVerifiedStatus(webhookVerifiedStatus.PENDING);
|
||||
}
|
||||
switch (inputType) {
|
||||
case WebhookInputDataFields.EVENT_NAME:
|
||||
setWebhook({ ...webhook, [inputType]: value });
|
||||
break;
|
||||
case WebhookInputDataFields.ENDPOINT:
|
||||
setWebhook({ ...webhook, [inputType]: value });
|
||||
setValidator({
|
||||
...validator,
|
||||
[WebhookInputDataFields.ENDPOINT]: validateURI(value),
|
||||
});
|
||||
break;
|
||||
case WebhookInputDataFields.ENABLED:
|
||||
setWebhook({ ...webhook, [inputType]: value });
|
||||
break;
|
||||
case WebhookInputDataFields.HEADERS:
|
||||
const updatedHeaders: any = [
|
||||
...webhook[WebhookInputDataFields.HEADERS],
|
||||
];
|
||||
const updatedHeadersValidatorData: any = [
|
||||
...validator[WebhookInputDataFields.HEADERS],
|
||||
];
|
||||
const otherHeaderInputType =
|
||||
headerInputType === WebhookInputHeaderFields.KEY
|
||||
? WebhookInputHeaderFields.VALUE
|
||||
: WebhookInputHeaderFields.KEY;
|
||||
updatedHeaders[headerIndex][headerInputType] = value;
|
||||
updatedHeadersValidatorData[headerIndex][headerInputType] =
|
||||
value.length > 0
|
||||
? updatedHeaders[headerIndex][otherHeaderInputType].length > 0
|
||||
: updatedHeaders[headerIndex][otherHeaderInputType].length === 0;
|
||||
updatedHeadersValidatorData[headerIndex][otherHeaderInputType] =
|
||||
value.length > 0
|
||||
? updatedHeaders[headerIndex][otherHeaderInputType].length > 0
|
||||
: updatedHeaders[headerIndex][otherHeaderInputType].length === 0;
|
||||
setWebhook({ ...webhook, [inputType]: updatedHeaders });
|
||||
setValidator({
|
||||
...validator,
|
||||
[inputType]: updatedHeadersValidatorData,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
const updateHeaders = (operation: string, index: number = 0) => {
|
||||
if (verifiedStatus !== webhookVerifiedStatus.PENDING) {
|
||||
setVerifiedStatus(webhookVerifiedStatus.PENDING);
|
||||
}
|
||||
switch (operation) {
|
||||
case ArrayInputOperations.APPEND:
|
||||
setWebhook({
|
||||
...webhook,
|
||||
[WebhookInputDataFields.HEADERS]: [
|
||||
...(webhook?.[WebhookInputDataFields.HEADERS] || []),
|
||||
{ ...initHeadersData },
|
||||
],
|
||||
});
|
||||
setValidator({
|
||||
...validator,
|
||||
[WebhookInputDataFields.HEADERS]: [
|
||||
...(validator?.[WebhookInputDataFields.HEADERS] || []),
|
||||
{ ...initHeadersValidatorData },
|
||||
],
|
||||
});
|
||||
break;
|
||||
case ArrayInputOperations.REMOVE:
|
||||
if (webhook?.[WebhookInputDataFields.HEADERS]?.length) {
|
||||
const updatedHeaders = [...webhook[WebhookInputDataFields.HEADERS]];
|
||||
updatedHeaders.splice(index, 1);
|
||||
setWebhook({
|
||||
...webhook,
|
||||
[WebhookInputDataFields.HEADERS]: updatedHeaders,
|
||||
});
|
||||
}
|
||||
if (validator?.[WebhookInputDataFields.HEADERS]?.length) {
|
||||
const updatedHeadersData = [
|
||||
...validator[WebhookInputDataFields.HEADERS],
|
||||
];
|
||||
updatedHeadersData.splice(index, 1);
|
||||
setValidator({
|
||||
...validator,
|
||||
[WebhookInputDataFields.HEADERS]: updatedHeadersData,
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
const validateData = () => {
|
||||
return (
|
||||
!loading &&
|
||||
!verifyingEndpoint &&
|
||||
webhook[WebhookInputDataFields.EVENT_NAME].length > 0 &&
|
||||
webhook[WebhookInputDataFields.ENDPOINT].length > 0 &&
|
||||
validator[WebhookInputDataFields.ENDPOINT] &&
|
||||
!validator[WebhookInputDataFields.HEADERS].some(
|
||||
(headerData: headersValidatorDataType) =>
|
||||
!headerData.key || !headerData.value
|
||||
)
|
||||
);
|
||||
};
|
||||
const getParams = () => {
|
||||
let params: any = {
|
||||
[WebhookInputDataFields.EVENT_NAME]:
|
||||
webhook[WebhookInputDataFields.EVENT_NAME],
|
||||
[WebhookInputDataFields.ENDPOINT]:
|
||||
webhook[WebhookInputDataFields.ENDPOINT],
|
||||
[WebhookInputDataFields.ENABLED]: webhook[WebhookInputDataFields.ENABLED],
|
||||
[WebhookInputDataFields.HEADERS]: {},
|
||||
};
|
||||
if (webhook[WebhookInputDataFields.HEADERS].length) {
|
||||
const headers = webhook[WebhookInputDataFields.HEADERS].reduce(
|
||||
(acc, data) => {
|
||||
return data.key ? { ...acc, [data.key]: data.value } : acc;
|
||||
},
|
||||
{}
|
||||
);
|
||||
if (Object.keys(headers).length) {
|
||||
params[WebhookInputDataFields.HEADERS] = headers;
|
||||
}
|
||||
}
|
||||
return params;
|
||||
};
|
||||
const saveData = async () => {
|
||||
if (!validateData()) return;
|
||||
setLoading(true);
|
||||
const params = getParams();
|
||||
let res: any = {};
|
||||
if (
|
||||
view === UpdateWebhookModalViews.Edit &&
|
||||
selectedWebhook?.[WebhookInputDataFields.ID]
|
||||
) {
|
||||
res = await client
|
||||
.mutation(EditWebhook, {
|
||||
params: {
|
||||
...params,
|
||||
id: selectedWebhook[WebhookInputDataFields.ID],
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
} else {
|
||||
res = await client.mutation(AddWebhook, { params }).toPromise();
|
||||
}
|
||||
setLoading(false);
|
||||
if (res.error) {
|
||||
toast({
|
||||
title: capitalizeFirstLetter(res.error.message),
|
||||
isClosable: true,
|
||||
status: 'error',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
} else if (res.data?._add_webhook || res.data?._update_webhook) {
|
||||
toast({
|
||||
title: capitalizeFirstLetter(
|
||||
res.data?._add_webhook?.message || res.data?._update_webhook?.message
|
||||
),
|
||||
isClosable: true,
|
||||
status: 'success',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
setWebhook({
|
||||
...initWebhookData,
|
||||
[WebhookInputDataFields.HEADERS]: [{ ...initHeadersData }],
|
||||
});
|
||||
setValidator({ ...initWebhookValidatorData });
|
||||
fetchWebookData();
|
||||
}
|
||||
view === UpdateWebhookModalViews.ADD && onClose();
|
||||
};
|
||||
useEffect(() => {
|
||||
if (
|
||||
isOpen &&
|
||||
view === UpdateWebhookModalViews.Edit &&
|
||||
selectedWebhook &&
|
||||
Object.keys(selectedWebhook || {}).length
|
||||
) {
|
||||
const { headers, ...rest } = selectedWebhook;
|
||||
const headerItems = Object.entries(headers || {});
|
||||
if (headerItems.length) {
|
||||
let formattedHeadersData = headerItems.map((headerData) => {
|
||||
return {
|
||||
[WebhookInputHeaderFields.KEY]: headerData[0],
|
||||
[WebhookInputHeaderFields.VALUE]: headerData[1],
|
||||
};
|
||||
});
|
||||
setWebhook({
|
||||
...rest,
|
||||
[WebhookInputDataFields.HEADERS]: formattedHeadersData,
|
||||
});
|
||||
setValidator({
|
||||
...validator,
|
||||
[WebhookInputDataFields.HEADERS]: new Array(
|
||||
formattedHeadersData.length
|
||||
)
|
||||
.fill({})
|
||||
.map(() => ({ ...initHeadersValidatorData })),
|
||||
});
|
||||
} else {
|
||||
setWebhook({
|
||||
...rest,
|
||||
[WebhookInputDataFields.HEADERS]: [{ ...initHeadersData }],
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [isOpen]);
|
||||
const verifyEndpoint = async () => {
|
||||
if (!validateData()) return;
|
||||
setVerifyingEndpoint(true);
|
||||
const { [WebhookInputDataFields.ENABLED]: _, ...params } = getParams();
|
||||
const res = await client.mutation(TestEndpoint, { params }).toPromise();
|
||||
if (
|
||||
res.data?._test_endpoint?.http_status >= 200 &&
|
||||
res.data?._test_endpoint?.http_status < 400
|
||||
) {
|
||||
setVerifiedStatus(webhookVerifiedStatus.VERIFIED);
|
||||
} else {
|
||||
setVerifiedStatus(webhookVerifiedStatus.NOT_VERIFIED);
|
||||
}
|
||||
setVerifyingEndpoint(false);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{view === UpdateWebhookModalViews.ADD ? (
|
||||
<Button
|
||||
leftIcon={<FaPlus />}
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
onClick={onOpen}
|
||||
isDisabled={false}
|
||||
size="sm"
|
||||
>
|
||||
<Center h="100%">Add Webhook</Center>{' '}
|
||||
</Button>
|
||||
) : (
|
||||
<MenuItem onClick={onOpen}>Edit</MenuItem>
|
||||
)}
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="3xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
{view === UpdateWebhookModalViews.ADD
|
||||
? 'Add New Webhook'
|
||||
: 'Edit Webhook'}
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
border="1px"
|
||||
borderRadius="md"
|
||||
borderColor="gray.200"
|
||||
p="5"
|
||||
>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
marginBottom="2%"
|
||||
>
|
||||
<Flex flex="1">Event Name</Flex>
|
||||
<Flex flex="3">
|
||||
<Select
|
||||
size="md"
|
||||
value={webhook[WebhookInputDataFields.EVENT_NAME]}
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
WebhookInputDataFields.EVENT_NAME,
|
||||
e.currentTarget.value
|
||||
)
|
||||
}
|
||||
>
|
||||
{Object.entries(webhookEventNames).map(
|
||||
([key, value]: any) => (
|
||||
<option value={value} key={key}>
|
||||
{key}
|
||||
</option>
|
||||
)
|
||||
)}
|
||||
</Select>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
marginBottom="5%"
|
||||
>
|
||||
<Flex flex="1">Endpoint</Flex>
|
||||
<Flex flex="3">
|
||||
<InputGroup size="md">
|
||||
<Input
|
||||
pr="4.5rem"
|
||||
type="text"
|
||||
placeholder="https://domain.com/webhook"
|
||||
value={webhook[WebhookInputDataFields.ENDPOINT]}
|
||||
isInvalid={!validator[WebhookInputDataFields.ENDPOINT]}
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
WebhookInputDataFields.ENDPOINT,
|
||||
e.currentTarget.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
marginBottom="5%"
|
||||
>
|
||||
<Flex flex="1">Enabled</Flex>
|
||||
<Flex w="25%" justifyContent="space-between">
|
||||
<Text h="75%" fontWeight="bold" marginRight="2">
|
||||
Off
|
||||
</Text>
|
||||
<Switch
|
||||
size="md"
|
||||
isChecked={webhook[WebhookInputDataFields.ENABLED]}
|
||||
onChange={() =>
|
||||
inputChangehandler(
|
||||
WebhookInputDataFields.ENABLED,
|
||||
!webhook[WebhookInputDataFields.ENABLED]
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Text h="75%" fontWeight="bold" marginLeft="2">
|
||||
On
|
||||
</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
marginBottom="2%"
|
||||
>
|
||||
<Flex>Headers</Flex>
|
||||
<Flex>
|
||||
<Button
|
||||
leftIcon={<FaPlus />}
|
||||
colorScheme="blue"
|
||||
h="1.75rem"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
paddingRight="0"
|
||||
onClick={() => updateHeaders(ArrayInputOperations.APPEND)}
|
||||
>
|
||||
Add more Headers
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex flexDirection="column" maxH={220} overflowY="scroll">
|
||||
{webhook[WebhookInputDataFields.HEADERS]?.map(
|
||||
(headerData, index) => (
|
||||
<Flex
|
||||
key={`header-data-${index}`}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
>
|
||||
<InputGroup size="md" marginBottom="2.5%">
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="key"
|
||||
value={headerData[WebhookInputHeaderFields.KEY]}
|
||||
isInvalid={
|
||||
!validator[WebhookInputDataFields.HEADERS][index]?.[
|
||||
WebhookInputHeaderFields.KEY
|
||||
]
|
||||
}
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
WebhookInputDataFields.HEADERS,
|
||||
e.target.value,
|
||||
WebhookInputHeaderFields.KEY,
|
||||
index
|
||||
)
|
||||
}
|
||||
width="30%"
|
||||
marginRight="2%"
|
||||
/>
|
||||
<Center marginRight="2%">
|
||||
<Text fontWeight="bold">:</Text>
|
||||
</Center>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="value"
|
||||
value={headerData[WebhookInputHeaderFields.VALUE]}
|
||||
isInvalid={
|
||||
!validator[WebhookInputDataFields.HEADERS][index]?.[
|
||||
WebhookInputHeaderFields.VALUE
|
||||
]
|
||||
}
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
WebhookInputDataFields.HEADERS,
|
||||
e.target.value,
|
||||
WebhookInputHeaderFields.VALUE,
|
||||
index
|
||||
)
|
||||
}
|
||||
width="65%"
|
||||
/>
|
||||
<InputRightElement width="3rem">
|
||||
<Button
|
||||
width="6rem"
|
||||
colorScheme="blackAlpha"
|
||||
variant="ghost"
|
||||
padding="0"
|
||||
onClick={() =>
|
||||
updateHeaders(ArrayInputOperations.REMOVE, index)
|
||||
}
|
||||
>
|
||||
<FaMinusCircle />
|
||||
</Button>
|
||||
</InputRightElement>
|
||||
</InputGroup>
|
||||
</Flex>
|
||||
)
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
colorScheme={
|
||||
verifiedStatus === webhookVerifiedStatus.VERIFIED
|
||||
? 'green'
|
||||
: verifiedStatus === webhookVerifiedStatus.PENDING
|
||||
? 'yellow'
|
||||
: 'red'
|
||||
}
|
||||
variant="outline"
|
||||
onClick={verifyEndpoint}
|
||||
isLoading={verifyingEndpoint}
|
||||
isDisabled={!validateData()}
|
||||
marginRight="5"
|
||||
leftIcon={
|
||||
verifiedStatus === webhookVerifiedStatus.VERIFIED ? (
|
||||
<BiCheckCircle />
|
||||
) : verifiedStatus === webhookVerifiedStatus.PENDING ? (
|
||||
<BiErrorCircle />
|
||||
) : (
|
||||
<BiError />
|
||||
)
|
||||
}
|
||||
>
|
||||
{verifiedStatus === webhookVerifiedStatus.VERIFIED
|
||||
? 'Endpoint Verified'
|
||||
: verifiedStatus === webhookVerifiedStatus.PENDING
|
||||
? 'Test Endpoint'
|
||||
: 'Endpoint Not Verified'}
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
onClick={saveData}
|
||||
isDisabled={!validateData()}
|
||||
>
|
||||
<Center h="100%" pt="5%">
|
||||
Save
|
||||
</Center>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateWebhookModal;
|
426
dashboard/src/components/ViewWebhookLogsModal.tsx
Normal file
426
dashboard/src/components/ViewWebhookLogsModal.tsx
Normal file
@@ -0,0 +1,426 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
Button,
|
||||
Center,
|
||||
Flex,
|
||||
MenuItem,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
useDisclosure,
|
||||
Text,
|
||||
Spinner,
|
||||
Table,
|
||||
Th,
|
||||
Thead,
|
||||
Tr,
|
||||
Tbody,
|
||||
IconButton,
|
||||
NumberDecrementStepper,
|
||||
NumberIncrementStepper,
|
||||
NumberInput,
|
||||
NumberInputField,
|
||||
NumberInputStepper,
|
||||
Select,
|
||||
TableCaption,
|
||||
Tooltip,
|
||||
Td,
|
||||
Tag,
|
||||
} from '@chakra-ui/react';
|
||||
import { useClient } from 'urql';
|
||||
import {
|
||||
FaAngleDoubleLeft,
|
||||
FaAngleDoubleRight,
|
||||
FaAngleLeft,
|
||||
FaAngleRight,
|
||||
FaExclamationCircle,
|
||||
FaRegClone,
|
||||
} from 'react-icons/fa';
|
||||
import { copyTextToClipboard } from '../utils';
|
||||
import { WebhookLogsQuery } from '../graphql/queries';
|
||||
import { pageLimits } from '../constants';
|
||||
|
||||
interface paginationPropTypes {
|
||||
limit: number;
|
||||
page: number;
|
||||
offset: number;
|
||||
total: number;
|
||||
maxPages: number;
|
||||
}
|
||||
|
||||
interface deleteWebhookModalInputPropTypes {
|
||||
webhookId: string;
|
||||
eventName: string;
|
||||
}
|
||||
|
||||
interface webhookLogsDataTypes {
|
||||
id: string;
|
||||
http_status: number;
|
||||
request: string;
|
||||
response: string;
|
||||
created_at: number;
|
||||
}
|
||||
|
||||
const ViewWebhookLogsModal = ({
|
||||
webhookId,
|
||||
eventName,
|
||||
}: deleteWebhookModalInputPropTypes) => {
|
||||
const client = useClient();
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [webhookLogs, setWebhookLogs] = useState<webhookLogsDataTypes[]>([]);
|
||||
const [paginationProps, setPaginationProps] = useState<paginationPropTypes>({
|
||||
limit: 5,
|
||||
page: 1,
|
||||
offset: 0,
|
||||
total: 0,
|
||||
maxPages: 1,
|
||||
});
|
||||
const getMaxPages = (pagination: paginationPropTypes) => {
|
||||
const { limit, total } = pagination;
|
||||
if (total > 1) {
|
||||
return total % limit === 0
|
||||
? total / limit
|
||||
: parseInt(`${total / limit}`) + 1;
|
||||
} else return 1;
|
||||
};
|
||||
const fetchWebhookLogsData = async () => {
|
||||
setLoading(true);
|
||||
const res = await client
|
||||
.query(WebhookLogsQuery, {
|
||||
params: {
|
||||
webhook_id: webhookId,
|
||||
pagination: {
|
||||
limit: paginationProps.limit,
|
||||
page: paginationProps.page,
|
||||
},
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
if (res.data?._webhook_logs) {
|
||||
const { pagination, webhook_logs } = res.data?._webhook_logs;
|
||||
const maxPages = getMaxPages(pagination);
|
||||
if (webhook_logs?.length) {
|
||||
setWebhookLogs(webhook_logs);
|
||||
setPaginationProps({ ...paginationProps, ...pagination, maxPages });
|
||||
} else {
|
||||
if (paginationProps.page !== 1) {
|
||||
setPaginationProps({
|
||||
...paginationProps,
|
||||
...pagination,
|
||||
maxPages,
|
||||
page: 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
const paginationHandler = (value: Record<string, number>) => {
|
||||
setPaginationProps({ ...paginationProps, ...value });
|
||||
};
|
||||
useEffect(() => {
|
||||
isOpen && fetchWebhookLogsData();
|
||||
}, [isOpen, paginationProps.page, paginationProps.limit]);
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={onOpen}>View Logs</MenuItem>
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="4xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Webhook Logs - {eventName}</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
border="1px"
|
||||
borderRadius="md"
|
||||
borderColor="gray.200"
|
||||
p="5"
|
||||
>
|
||||
{!loading ? (
|
||||
webhookLogs.length ? (
|
||||
<Table variant="simple">
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>ID</Th>
|
||||
<Th>Created At</Th>
|
||||
<Th>Http Status</Th>
|
||||
<Th>Request</Th>
|
||||
<Th>Response</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{webhookLogs.map((logData: webhookLogsDataTypes) => (
|
||||
<Tr key={logData.id} style={{ fontSize: 14 }}>
|
||||
<Td>
|
||||
<Text fontSize="sm">{`${logData.id.substring(
|
||||
0,
|
||||
5
|
||||
)}***${logData.id.substring(
|
||||
logData.id.length - 5,
|
||||
logData.id.length
|
||||
)}`}</Text>
|
||||
</Td>
|
||||
<Td>
|
||||
{dayjs(logData.created_at * 1000).format(
|
||||
'MMM DD, YYYY'
|
||||
)}
|
||||
</Td>
|
||||
<Td>
|
||||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme={
|
||||
logData.http_status >= 400 ? 'red' : 'green'
|
||||
}
|
||||
>
|
||||
{logData.http_status}
|
||||
</Tag>
|
||||
</Td>
|
||||
<Td>
|
||||
<Flex alignItems="center">
|
||||
<Tooltip
|
||||
bg="gray.300"
|
||||
color="black"
|
||||
label={logData.request || 'null'}
|
||||
>
|
||||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme={
|
||||
logData.request ? 'gray' : 'yellow'
|
||||
}
|
||||
>
|
||||
{logData.request ? 'Payload' : 'No Data'}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
{logData.request && (
|
||||
<Button
|
||||
size="xs"
|
||||
variant="outline"
|
||||
marginLeft="5px"
|
||||
h="21px"
|
||||
onClick={() =>
|
||||
copyTextToClipboard(logData.request)
|
||||
}
|
||||
>
|
||||
<FaRegClone color="#bfbfbf" />
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
</Td>
|
||||
<Td>
|
||||
<Flex alignItems="center">
|
||||
<Tooltip
|
||||
bg="gray.300"
|
||||
color="black"
|
||||
label={logData.response || 'null'}
|
||||
>
|
||||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme={
|
||||
logData.response ? 'gray' : 'yellow'
|
||||
}
|
||||
>
|
||||
{logData.response ? 'Preview' : 'No Data'}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
{logData.response && (
|
||||
<Button
|
||||
size="xs"
|
||||
variant="outline"
|
||||
marginLeft="5px"
|
||||
h="21px"
|
||||
onClick={() =>
|
||||
copyTextToClipboard(logData.response)
|
||||
}
|
||||
>
|
||||
<FaRegClone color="#bfbfbf" />
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
{(paginationProps.maxPages > 1 ||
|
||||
paginationProps.total >= 5) && (
|
||||
<TableCaption>
|
||||
<Flex
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
m="2% 0"
|
||||
>
|
||||
<Flex flex="1">
|
||||
<Tooltip label="First Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: 1,
|
||||
})
|
||||
}
|
||||
isDisabled={paginationProps.page <= 1}
|
||||
mr={4}
|
||||
icon={<FaAngleDoubleLeft />}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip label="Previous Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: paginationProps.page - 1,
|
||||
})
|
||||
}
|
||||
isDisabled={paginationProps.page <= 1}
|
||||
icon={<FaAngleLeft />}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
<Flex
|
||||
flex="8"
|
||||
justifyContent="space-evenly"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text mr={8}>
|
||||
Page{' '}
|
||||
<Text fontWeight="bold" as="span">
|
||||
{paginationProps.page}
|
||||
</Text>{' '}
|
||||
of{' '}
|
||||
<Text fontWeight="bold" as="span">
|
||||
{paginationProps.maxPages}
|
||||
</Text>
|
||||
</Text>
|
||||
<Flex alignItems="center">
|
||||
<Text flexShrink="0">Go to page:</Text>{' '}
|
||||
<NumberInput
|
||||
ml={2}
|
||||
mr={8}
|
||||
w={28}
|
||||
min={1}
|
||||
max={paginationProps.maxPages}
|
||||
onChange={(value) =>
|
||||
paginationHandler({
|
||||
page: parseInt(value),
|
||||
})
|
||||
}
|
||||
value={paginationProps.page}
|
||||
>
|
||||
<NumberInputField />
|
||||
<NumberInputStepper>
|
||||
<NumberIncrementStepper />
|
||||
<NumberDecrementStepper />
|
||||
</NumberInputStepper>
|
||||
</NumberInput>
|
||||
</Flex>
|
||||
<Select
|
||||
w={32}
|
||||
value={paginationProps.limit}
|
||||
onChange={(e) =>
|
||||
paginationHandler({
|
||||
page: 1,
|
||||
limit: parseInt(e.target.value),
|
||||
})
|
||||
}
|
||||
>
|
||||
{pageLimits.map((pageSize) => (
|
||||
<option key={pageSize} value={pageSize}>
|
||||
Show {pageSize}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</Flex>
|
||||
<Flex flex="1">
|
||||
<Tooltip label="Next Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: paginationProps.page + 1,
|
||||
})
|
||||
}
|
||||
isDisabled={
|
||||
paginationProps.page >=
|
||||
paginationProps.maxPages
|
||||
}
|
||||
icon={<FaAngleRight />}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip label="Last Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: paginationProps.maxPages,
|
||||
})
|
||||
}
|
||||
isDisabled={
|
||||
paginationProps.page >=
|
||||
paginationProps.maxPages
|
||||
}
|
||||
ml={4}
|
||||
icon={<FaAngleDoubleRight />}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</TableCaption>
|
||||
)}
|
||||
</Table>
|
||||
) : (
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
minH="25vh"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
>
|
||||
<Center w="50px" marginRight="1.5%">
|
||||
<FaExclamationCircle
|
||||
style={{ color: '#f0f0f0', fontSize: 70 }}
|
||||
/>
|
||||
</Center>
|
||||
<Text
|
||||
fontSize="2xl"
|
||||
paddingRight="1%"
|
||||
fontWeight="bold"
|
||||
color="#d9d9d9"
|
||||
>
|
||||
No Data
|
||||
</Text>
|
||||
</Flex>
|
||||
)
|
||||
) : (
|
||||
<Center minH="25vh">
|
||||
<Spinner />
|
||||
</Center>
|
||||
)}
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
onClick={onClose}
|
||||
isDisabled={false}
|
||||
>
|
||||
<Center h="100%" pt="5%">
|
||||
Close
|
||||
</Center>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ViewWebhookLogsModal;
|
@@ -7,6 +7,8 @@ export const TextInputType = {
|
||||
GOOGLE_CLIENT_ID: 'GOOGLE_CLIENT_ID',
|
||||
GITHUB_CLIENT_ID: 'GITHUB_CLIENT_ID',
|
||||
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
|
||||
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
|
||||
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
|
||||
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
||||
REDIS_URL: 'REDIS_URL',
|
||||
SMTP_HOST: 'SMTP_HOST',
|
||||
@@ -31,6 +33,8 @@ export const HiddenInputType = {
|
||||
GOOGLE_CLIENT_SECRET: 'GOOGLE_CLIENT_SECRET',
|
||||
GITHUB_CLIENT_SECRET: 'GITHUB_CLIENT_SECRET',
|
||||
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
|
||||
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
|
||||
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
||||
JWT_SECRET: 'JWT_SECRET',
|
||||
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
||||
ADMIN_SECRET: 'ADMIN_SECRET',
|
||||
@@ -62,6 +66,8 @@ export const SwitchInputType = {
|
||||
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
|
||||
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
|
||||
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
|
||||
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
|
||||
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
|
||||
};
|
||||
|
||||
export const DateInputType = {
|
||||
@@ -98,6 +104,10 @@ export interface envVarTypes {
|
||||
GITHUB_CLIENT_SECRET: string;
|
||||
FACEBOOK_CLIENT_ID: string;
|
||||
FACEBOOK_CLIENT_SECRET: string;
|
||||
LINKEDIN_CLIENT_ID: string;
|
||||
LINKEDIN_CLIENT_SECRET: string;
|
||||
APPLE_CLIENT_ID: string;
|
||||
APPLE_CLIENT_SECRET: string;
|
||||
ROLES: [string] | [];
|
||||
DEFAULT_ROLES: [string] | [];
|
||||
PROTECTED_ROLES: [string] | [];
|
||||
@@ -122,6 +132,7 @@ export interface envVarTypes {
|
||||
DISABLE_EMAIL_VERIFICATION: boolean;
|
||||
DISABLE_BASIC_AUTHENTICATION: boolean;
|
||||
DISABLE_SIGN_UP: boolean;
|
||||
DISABLE_STRONG_PASSWORD: boolean;
|
||||
OLD_ADMIN_SECRET: string;
|
||||
DATABASE_NAME: string;
|
||||
DATABASE_TYPE: string;
|
||||
@@ -138,7 +149,42 @@ export const envSubViews = {
|
||||
WHITELIST_VARIABLES: 'whitelist-variables',
|
||||
ORGANIZATION_INFO: 'organization-info',
|
||||
ACCESS_TOKEN: 'access-token',
|
||||
UI_CUSTOMIZATION: 'ui-customization',
|
||||
FEATURES: 'features',
|
||||
ADMIN_SECRET: 'admin-secret',
|
||||
DB_CRED: 'db-cred',
|
||||
};
|
||||
|
||||
export enum WebhookInputDataFields {
|
||||
ID = 'id',
|
||||
EVENT_NAME = 'event_name',
|
||||
ENDPOINT = 'endpoint',
|
||||
ENABLED = 'enabled',
|
||||
HEADERS = 'headers',
|
||||
}
|
||||
|
||||
export enum WebhookInputHeaderFields {
|
||||
KEY = 'key',
|
||||
VALUE = 'value',
|
||||
}
|
||||
|
||||
export enum UpdateWebhookModalViews {
|
||||
ADD = 'add',
|
||||
Edit = 'edit',
|
||||
}
|
||||
|
||||
export const pageLimits: number[] = [5, 10, 15];
|
||||
|
||||
export const webhookEventNames = {
|
||||
USER_SIGNUP: 'user.signup',
|
||||
USER_CREATED: 'user.created',
|
||||
USER_LOGIN: 'user.login',
|
||||
USER_DELETED: 'user.deleted',
|
||||
USER_ACCESS_ENABLED: 'user.access_enabled',
|
||||
USER_ACCESS_REVOKED: 'user.access_revoked',
|
||||
};
|
||||
|
||||
export enum webhookVerifiedStatus {
|
||||
VERIFIED = 'verified',
|
||||
NOT_VERIFIED = 'not_verified',
|
||||
PENDING = 'verification_pending',
|
||||
}
|
||||
|
@@ -79,3 +79,36 @@ export const GenerateKeys = `
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const AddWebhook = `
|
||||
mutation addWebhook($params: AddWebhookRequest!) {
|
||||
_add_webhook(params: $params) {
|
||||
message
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const EditWebhook = `
|
||||
mutation editWebhook($params: UpdateWebhookRequest!) {
|
||||
_update_webhook(params: $params) {
|
||||
message
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const DeleteWebhook = `
|
||||
mutation deleteWebhook($params: WebhookRequest!) {
|
||||
_delete_webhook(params: $params) {
|
||||
message
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const TestEndpoint = `
|
||||
mutation testEndpoint($params: TestEndpointRequest!) {
|
||||
_test_endpoint(params: $params) {
|
||||
http_status
|
||||
response
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@@ -26,9 +26,13 @@ export const EnvVariablesQuery = `
|
||||
GITHUB_CLIENT_SECRET,
|
||||
FACEBOOK_CLIENT_ID,
|
||||
FACEBOOK_CLIENT_SECRET,
|
||||
ROLES,
|
||||
LINKEDIN_CLIENT_ID,
|
||||
LINKEDIN_CLIENT_SECRET,
|
||||
APPLE_CLIENT_ID,
|
||||
APPLE_CLIENT_SECRET,
|
||||
DEFAULT_ROLES,
|
||||
PROTECTED_ROLES,
|
||||
ROLES,
|
||||
JWT_TYPE,
|
||||
JWT_SECRET,
|
||||
JWT_ROLE_CLAIM,
|
||||
@@ -49,6 +53,8 @@ export const EnvVariablesQuery = `
|
||||
DISABLE_EMAIL_VERIFICATION,
|
||||
DISABLE_BASIC_AUTHENTICATION,
|
||||
DISABLE_SIGN_UP,
|
||||
DISABLE_STRONG_PASSWORD,
|
||||
DISABLE_REDIS_FOR_ENV,
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT,
|
||||
DATABASE_NAME,
|
||||
DATABASE_TYPE,
|
||||
@@ -95,3 +101,43 @@ export const EmailVerificationQuery = `
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const WebhooksDataQuery = `
|
||||
query getWebhooksData($params: PaginatedInput!) {
|
||||
_webhooks(params: $params){
|
||||
webhooks{
|
||||
id
|
||||
event_name
|
||||
endpoint
|
||||
enabled
|
||||
headers
|
||||
}
|
||||
pagination{
|
||||
limit
|
||||
page
|
||||
offset
|
||||
total
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const WebhookLogsQuery = `
|
||||
query getWebhookLogs($params: ListWebhookLogRequest!) {
|
||||
_webhook_logs(params: $params) {
|
||||
webhook_logs {
|
||||
id
|
||||
http_status
|
||||
request
|
||||
response
|
||||
created_at
|
||||
}
|
||||
pagination {
|
||||
limit
|
||||
page
|
||||
offset
|
||||
total
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@@ -25,7 +25,7 @@ import EmailConfigurations from '../components/EnvComponents/EmailConfiguration'
|
||||
import DomainWhiteListing from '../components/EnvComponents/DomainWhitelisting';
|
||||
import OrganizationInfo from '../components/EnvComponents/OrganizationInfo';
|
||||
import AccessToken from '../components/EnvComponents/AccessToken';
|
||||
import UICustomization from '../components/EnvComponents/UICustomization';
|
||||
import Features from '../components/EnvComponents/Features';
|
||||
import SecurityAdminSecret from '../components/EnvComponents/SecurityAdminSecret';
|
||||
import DatabaseCredentials from '../components/EnvComponents/DatabaseCredentials';
|
||||
|
||||
@@ -46,6 +46,10 @@ const Environment = () => {
|
||||
GITHUB_CLIENT_SECRET: '',
|
||||
FACEBOOK_CLIENT_ID: '',
|
||||
FACEBOOK_CLIENT_SECRET: '',
|
||||
LINKEDIN_CLIENT_ID: '',
|
||||
LINKEDIN_CLIENT_SECRET: '',
|
||||
APPLE_CLIENT_ID: '',
|
||||
APPLE_CLIENT_SECRET: '',
|
||||
ROLES: [],
|
||||
DEFAULT_ROLES: [],
|
||||
PROTECTED_ROLES: [],
|
||||
@@ -70,6 +74,7 @@ const Environment = () => {
|
||||
DISABLE_EMAIL_VERIFICATION: false,
|
||||
DISABLE_BASIC_AUTHENTICATION: false,
|
||||
DISABLE_SIGN_UP: false,
|
||||
DISABLE_STRONG_PASSWORD: false,
|
||||
OLD_ADMIN_SECRET: '',
|
||||
DATABASE_NAME: '',
|
||||
DATABASE_TYPE: '',
|
||||
@@ -83,6 +88,8 @@ const Environment = () => {
|
||||
GOOGLE_CLIENT_SECRET: false,
|
||||
GITHUB_CLIENT_SECRET: false,
|
||||
FACEBOOK_CLIENT_SECRET: false,
|
||||
LINKEDIN_CLIENT_SECRET: false,
|
||||
APPLE_CLIENT_SECRET: false,
|
||||
JWT_SECRET: false,
|
||||
SMTP_PASSWORD: false,
|
||||
ADMIN_SECRET: false,
|
||||
@@ -259,12 +266,9 @@ const Environment = () => {
|
||||
setVariables={setEnvVariables}
|
||||
/>
|
||||
);
|
||||
case envSubViews.UI_CUSTOMIZATION:
|
||||
case envSubViews.FEATURES:
|
||||
return (
|
||||
<UICustomization
|
||||
variables={envVariables}
|
||||
setVariables={setEnvVariables}
|
||||
/>
|
||||
<Features variables={envVariables} setVariables={setEnvVariables} />
|
||||
);
|
||||
case envSubViews.ADMIN_SECRET:
|
||||
return (
|
||||
|
370
dashboard/src/pages/Webhooks.tsx
Normal file
370
dashboard/src/pages/Webhooks.tsx
Normal file
@@ -0,0 +1,370 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useClient } from 'urql';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Center,
|
||||
Flex,
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
NumberDecrementStepper,
|
||||
NumberIncrementStepper,
|
||||
NumberInput,
|
||||
NumberInputField,
|
||||
NumberInputStepper,
|
||||
Select,
|
||||
Spinner,
|
||||
Table,
|
||||
TableCaption,
|
||||
Tag,
|
||||
Tbody,
|
||||
Td,
|
||||
Text,
|
||||
Th,
|
||||
Thead,
|
||||
Tooltip,
|
||||
Tr,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaAngleDoubleLeft,
|
||||
FaAngleDoubleRight,
|
||||
FaAngleDown,
|
||||
FaAngleLeft,
|
||||
FaAngleRight,
|
||||
FaExclamationCircle,
|
||||
} from 'react-icons/fa';
|
||||
import UpdateWebhookModal from '../components/UpdateWebhookModal';
|
||||
import {
|
||||
pageLimits,
|
||||
WebhookInputDataFields,
|
||||
UpdateWebhookModalViews,
|
||||
} from '../constants';
|
||||
import { WebhooksDataQuery } from '../graphql/queries';
|
||||
import DeleteWebhookModal from '../components/DeleteWebhookModal';
|
||||
import ViewWebhookLogsModal from '../components/ViewWebhookLogsModal';
|
||||
|
||||
interface paginationPropTypes {
|
||||
limit: number;
|
||||
page: number;
|
||||
offset: number;
|
||||
total: number;
|
||||
maxPages: number;
|
||||
}
|
||||
|
||||
interface webhookDataTypes {
|
||||
[WebhookInputDataFields.ID]: string;
|
||||
[WebhookInputDataFields.EVENT_NAME]: string;
|
||||
[WebhookInputDataFields.ENDPOINT]: string;
|
||||
[WebhookInputDataFields.ENABLED]: boolean;
|
||||
[WebhookInputDataFields.HEADERS]?: Record<string, string>;
|
||||
}
|
||||
|
||||
const Webhooks = () => {
|
||||
const client = useClient();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [webhookData, setWebhookData] = useState<webhookDataTypes[]>([]);
|
||||
const [paginationProps, setPaginationProps] = useState<paginationPropTypes>({
|
||||
limit: 5,
|
||||
page: 1,
|
||||
offset: 0,
|
||||
total: 0,
|
||||
maxPages: 1,
|
||||
});
|
||||
const getMaxPages = (pagination: paginationPropTypes) => {
|
||||
const { limit, total } = pagination;
|
||||
if (total > 1) {
|
||||
return total % limit === 0
|
||||
? total / limit
|
||||
: parseInt(`${total / limit}`) + 1;
|
||||
} else return 1;
|
||||
};
|
||||
const fetchWebookData = async () => {
|
||||
setLoading(true);
|
||||
const res = await client
|
||||
.query(WebhooksDataQuery, {
|
||||
params: {
|
||||
pagination: {
|
||||
limit: paginationProps.limit,
|
||||
page: paginationProps.page,
|
||||
},
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
if (res.data?._webhooks) {
|
||||
const { pagination, webhooks } = res.data?._webhooks;
|
||||
const maxPages = getMaxPages(pagination);
|
||||
if (webhooks?.length) {
|
||||
setWebhookData(webhooks);
|
||||
setPaginationProps({ ...paginationProps, ...pagination, maxPages });
|
||||
} else {
|
||||
if (paginationProps.page !== 1) {
|
||||
setPaginationProps({
|
||||
...paginationProps,
|
||||
...pagination,
|
||||
maxPages,
|
||||
page: 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
const paginationHandler = (value: Record<string, number>) => {
|
||||
setPaginationProps({ ...paginationProps, ...value });
|
||||
};
|
||||
useEffect(() => {
|
||||
fetchWebookData();
|
||||
}, [paginationProps.page, paginationProps.limit]);
|
||||
return (
|
||||
<Box m="5" py="5" px="10" bg="white" rounded="md">
|
||||
<Flex margin="2% 0" justifyContent="space-between" alignItems="center">
|
||||
<Text fontSize="md" fontWeight="bold">
|
||||
Webhooks
|
||||
</Text>
|
||||
<UpdateWebhookModal
|
||||
view={UpdateWebhookModalViews.ADD}
|
||||
fetchWebookData={fetchWebookData}
|
||||
/>
|
||||
</Flex>
|
||||
{!loading ? (
|
||||
webhookData.length ? (
|
||||
<Table variant="simple">
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>Event Name</Th>
|
||||
<Th>Endpoint</Th>
|
||||
<Th>Enabled</Th>
|
||||
<Th>Headers</Th>
|
||||
<Th>Actions</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{webhookData.map((webhook: webhookDataTypes) => (
|
||||
<Tr
|
||||
key={webhook[WebhookInputDataFields.ID]}
|
||||
style={{ fontSize: 14 }}
|
||||
>
|
||||
<Td maxW="300">
|
||||
{webhook[WebhookInputDataFields.EVENT_NAME]}
|
||||
</Td>
|
||||
<Td>{webhook[WebhookInputDataFields.ENDPOINT]}</Td>
|
||||
<Td>
|
||||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme={
|
||||
webhook[WebhookInputDataFields.ENABLED]
|
||||
? 'green'
|
||||
: 'yellow'
|
||||
}
|
||||
>
|
||||
{webhook[WebhookInputDataFields.ENABLED].toString()}
|
||||
</Tag>
|
||||
</Td>
|
||||
<Td>
|
||||
<Tooltip
|
||||
bg="gray.300"
|
||||
color="black"
|
||||
label={JSON.stringify(
|
||||
webhook[WebhookInputDataFields.HEADERS],
|
||||
null,
|
||||
' '
|
||||
)}
|
||||
>
|
||||
<Tag size="sm" variant="outline" colorScheme="gray">
|
||||
{Object.keys(
|
||||
webhook[WebhookInputDataFields.HEADERS] || {}
|
||||
)?.length.toString()}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
</Td>
|
||||
<Td>
|
||||
<Menu>
|
||||
<MenuButton as={Button} variant="unstyled" size="sm">
|
||||
<Flex
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm" fontWeight="light">
|
||||
Menu
|
||||
</Text>
|
||||
<FaAngleDown style={{ marginLeft: 10 }} />
|
||||
</Flex>
|
||||
</MenuButton>
|
||||
<MenuList>
|
||||
<UpdateWebhookModal
|
||||
view={UpdateWebhookModalViews.Edit}
|
||||
selectedWebhook={webhook}
|
||||
fetchWebookData={fetchWebookData}
|
||||
/>
|
||||
<DeleteWebhookModal
|
||||
webhookId={webhook[WebhookInputDataFields.ID]}
|
||||
eventName={webhook[WebhookInputDataFields.EVENT_NAME]}
|
||||
fetchWebookData={fetchWebookData}
|
||||
/>
|
||||
<ViewWebhookLogsModal
|
||||
webhookId={webhook[WebhookInputDataFields.ID]}
|
||||
eventName={webhook[WebhookInputDataFields.EVENT_NAME]}
|
||||
/>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
{(paginationProps.maxPages > 1 || paginationProps.total >= 5) && (
|
||||
<TableCaption>
|
||||
<Flex
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
m="2% 0"
|
||||
>
|
||||
<Flex flex="1">
|
||||
<Tooltip label="First Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: 1,
|
||||
})
|
||||
}
|
||||
isDisabled={paginationProps.page <= 1}
|
||||
mr={4}
|
||||
icon={<FaAngleDoubleLeft />}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip label="Previous Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: paginationProps.page - 1,
|
||||
})
|
||||
}
|
||||
isDisabled={paginationProps.page <= 1}
|
||||
icon={<FaAngleLeft />}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
<Flex
|
||||
flex="8"
|
||||
justifyContent="space-evenly"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text mr={8}>
|
||||
Page{' '}
|
||||
<Text fontWeight="bold" as="span">
|
||||
{paginationProps.page}
|
||||
</Text>{' '}
|
||||
of{' '}
|
||||
<Text fontWeight="bold" as="span">
|
||||
{paginationProps.maxPages}
|
||||
</Text>
|
||||
</Text>
|
||||
<Flex alignItems="center">
|
||||
<Text flexShrink="0">Go to page:</Text>{' '}
|
||||
<NumberInput
|
||||
ml={2}
|
||||
mr={8}
|
||||
w={28}
|
||||
min={1}
|
||||
max={paginationProps.maxPages}
|
||||
onChange={(value) =>
|
||||
paginationHandler({
|
||||
page: parseInt(value),
|
||||
})
|
||||
}
|
||||
value={paginationProps.page}
|
||||
>
|
||||
<NumberInputField />
|
||||
<NumberInputStepper>
|
||||
<NumberIncrementStepper />
|
||||
<NumberDecrementStepper />
|
||||
</NumberInputStepper>
|
||||
</NumberInput>
|
||||
</Flex>
|
||||
<Select
|
||||
w={32}
|
||||
value={paginationProps.limit}
|
||||
onChange={(e) =>
|
||||
paginationHandler({
|
||||
page: 1,
|
||||
limit: parseInt(e.target.value),
|
||||
})
|
||||
}
|
||||
>
|
||||
{pageLimits.map((pageSize) => (
|
||||
<option key={pageSize} value={pageSize}>
|
||||
Show {pageSize}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</Flex>
|
||||
<Flex flex="1">
|
||||
<Tooltip label="Next Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: paginationProps.page + 1,
|
||||
})
|
||||
}
|
||||
isDisabled={
|
||||
paginationProps.page >= paginationProps.maxPages
|
||||
}
|
||||
icon={<FaAngleRight />}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip label="Last Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: paginationProps.maxPages,
|
||||
})
|
||||
}
|
||||
isDisabled={
|
||||
paginationProps.page >= paginationProps.maxPages
|
||||
}
|
||||
ml={4}
|
||||
icon={<FaAngleDoubleRight />}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</TableCaption>
|
||||
)}
|
||||
</Table>
|
||||
) : (
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
minH="25vh"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
>
|
||||
<Center w="50px" marginRight="1.5%">
|
||||
<FaExclamationCircle style={{ color: '#f0f0f0', fontSize: 70 }} />
|
||||
</Center>
|
||||
<Text
|
||||
fontSize="2xl"
|
||||
paddingRight="1%"
|
||||
fontWeight="bold"
|
||||
color="#d9d9d9"
|
||||
>
|
||||
No Data
|
||||
</Text>
|
||||
</Flex>
|
||||
)
|
||||
) : (
|
||||
<Center minH="25vh">
|
||||
<Spinner />
|
||||
</Center>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Webhooks;
|
@@ -8,6 +8,7 @@ const Auth = lazy(() => import('../pages/Auth'));
|
||||
const Environment = lazy(() => import('../pages/Environment'));
|
||||
const Home = lazy(() => import('../pages/Home'));
|
||||
const Users = lazy(() => import('../pages/Users'));
|
||||
const Webhooks = lazy(() => import('../pages/Webhooks'));
|
||||
|
||||
export const AppRoutes = () => {
|
||||
const { isLoggedIn } = useAuthContext();
|
||||
@@ -29,6 +30,7 @@ export const AppRoutes = () => {
|
||||
<Route path="/:sec" element={<Environment />} />
|
||||
</Route>
|
||||
<Route path="users" element={<Users />} />
|
||||
<Route path="webhooks" element={<Webhooks />} />
|
||||
<Route path="*" element={<Home />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
|
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "authorizer",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
14
server/cli/cli.go
Normal file
14
server/cli/cli.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package cli
|
||||
|
||||
var (
|
||||
// ARG_DB_URL is the cli arg variable for the database url
|
||||
ARG_DB_URL *string
|
||||
// ARG_DB_TYPE is the cli arg variable for the database type
|
||||
ARG_DB_TYPE *string
|
||||
// ARG_ENV_FILE is the cli arg variable for the env file
|
||||
ARG_ENV_FILE *string
|
||||
// ARG_LOG_LEVEL is the cli arg variable for the log level
|
||||
ARG_LOG_LEVEL *string
|
||||
// ARG_REDIS_URL is the cli arg variable for the redis url
|
||||
ARG_REDIS_URL *string
|
||||
)
|
18
server/constants/auth_methods.go
Normal file
18
server/constants/auth_methods.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
// AuthRecipeMethodBasicAuth is the basic_auth auth method
|
||||
AuthRecipeMethodBasicAuth = "basic_auth"
|
||||
// AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method
|
||||
AuthRecipeMethodMagicLinkLogin = "magic_link_login"
|
||||
// AuthRecipeMethodGoogle is the google auth method
|
||||
AuthRecipeMethodGoogle = "google"
|
||||
// AuthRecipeMethodGithub is the github auth method
|
||||
AuthRecipeMethodGithub = "github"
|
||||
// AuthRecipeMethodFacebook is the facebook auth method
|
||||
AuthRecipeMethodFacebook = "facebook"
|
||||
// AuthRecipeMethodLinkedin is the linkedin auth method
|
||||
AuthRecipeMethodLinkedIn = "linkedin"
|
||||
// AuthRecipeMethodApple is the apple auth method
|
||||
AuthRecipeMethodApple = "apple"
|
||||
)
|
8
server/constants/cookie.go
Normal file
8
server/constants/cookie.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
// AppCookieName is the name of the cookie that is used to store the application token
|
||||
AppCookieName = "cookie"
|
||||
// AdminCookieName is the name of the cookie that is used to store the admin token
|
||||
AdminCookieName = "authorizer-admin"
|
||||
)
|
@@ -19,4 +19,10 @@ const (
|
||||
DbTypeMariaDB = "mariadb"
|
||||
// DbTypeCassandra is the cassandra database type
|
||||
DbTypeCassandraDB = "cassandradb"
|
||||
// DbTypeScyllaDB is the scylla database type
|
||||
DbTypeScyllaDB = "scylladb"
|
||||
// DbTypeCockroachDB is the cockroach database type
|
||||
DbTypeCockroachDB = "cockroachdb"
|
||||
// DbTypePlanetScaleDB is the planetscale database type
|
||||
DbTypePlanetScaleDB = "planetscale"
|
||||
)
|
||||
|
@@ -3,14 +3,8 @@ package constants
|
||||
var VERSION = "0.0.1"
|
||||
|
||||
const (
|
||||
// Envstore identifier
|
||||
// StringStore string store identifier
|
||||
StringStoreIdentifier = "stringStore"
|
||||
// BoolStore bool store identifier
|
||||
BoolStoreIdentifier = "boolStore"
|
||||
// SliceStore slice store identifier
|
||||
SliceStoreIdentifier = "sliceStore"
|
||||
|
||||
// TestEnv is used for testing
|
||||
TestEnv = "test"
|
||||
// EnvKeyEnv key for env variable ENV
|
||||
EnvKeyEnv = "ENV"
|
||||
// EnvKeyEnvPath key for cli arg variable ENV_PATH
|
||||
@@ -19,7 +13,6 @@ const (
|
||||
EnvKeyAuthorizerURL = "AUTHORIZER_URL"
|
||||
// EnvKeyPort key for env variable PORT
|
||||
EnvKeyPort = "PORT"
|
||||
|
||||
// EnvKeyAccessTokenExpiryTime key for env variable ACCESS_TOKEN_EXPIRY_TIME
|
||||
EnvKeyAccessTokenExpiryTime = "ACCESS_TOKEN_EXPIRY_TIME"
|
||||
// EnvKeyAdminSecret key for env variable ADMIN_SECRET
|
||||
@@ -62,34 +55,12 @@ const (
|
||||
EnvKeyJwtPrivateKey = "JWT_PRIVATE_KEY"
|
||||
// EnvKeyJwtPublicKey key for env variable JWT_PUBLIC_KEY
|
||||
EnvKeyJwtPublicKey = "JWT_PUBLIC_KEY"
|
||||
// EnvKeyAllowedOrigins key for env variable ALLOWED_ORIGINS
|
||||
EnvKeyAllowedOrigins = "ALLOWED_ORIGINS"
|
||||
// EnvKeyAppURL key for env variable APP_URL
|
||||
EnvKeyAppURL = "APP_URL"
|
||||
// EnvKeyRedisURL key for env variable REDIS_URL
|
||||
EnvKeyRedisURL = "REDIS_URL"
|
||||
// EnvKeyCookieName key for env variable COOKIE_NAME
|
||||
EnvKeyCookieName = "COOKIE_NAME"
|
||||
// EnvKeyAdminCookieName key for env variable ADMIN_COOKIE_NAME
|
||||
EnvKeyAdminCookieName = "ADMIN_COOKIE_NAME"
|
||||
// EnvKeyResetPasswordURL key for env variable RESET_PASSWORD_URL
|
||||
EnvKeyResetPasswordURL = "RESET_PASSWORD_URL"
|
||||
// EnvKeyDisableEmailVerification key for env variable DISABLE_EMAIL_VERIFICATION
|
||||
EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION"
|
||||
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
|
||||
EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION"
|
||||
// EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN
|
||||
EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN"
|
||||
// EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE
|
||||
EnvKeyDisableLoginPage = "DISABLE_LOGIN_PAGE"
|
||||
// EnvKeyDisableSignUp key for env variable DISABLE_SIGN_UP
|
||||
EnvKeyDisableSignUp = "DISABLE_SIGN_UP"
|
||||
// EnvKeyRoles key for env variable ROLES
|
||||
EnvKeyRoles = "ROLES"
|
||||
// EnvKeyProtectedRoles key for env variable PROTECTED_ROLES
|
||||
EnvKeyProtectedRoles = "PROTECTED_ROLES"
|
||||
// EnvKeyDefaultRoles key for env variable DEFAULT_ROLES
|
||||
EnvKeyDefaultRoles = "DEFAULT_ROLES"
|
||||
// EnvKeyJwtRoleClaim key for env variable JWT_ROLE_CLAIM
|
||||
EnvKeyJwtRoleClaim = "JWT_ROLE_CLAIM"
|
||||
// EnvKeyGoogleClientID key for env variable GOOGLE_CLIENT_ID
|
||||
@@ -104,6 +75,14 @@ const (
|
||||
EnvKeyFacebookClientID = "FACEBOOK_CLIENT_ID"
|
||||
// EnvKeyFacebookClientSecret key for env variable FACEBOOK_CLIENT_SECRET
|
||||
EnvKeyFacebookClientSecret = "FACEBOOK_CLIENT_SECRET"
|
||||
// EnvKeyLinkedinClientID key for env variable LINKEDIN_CLIENT_ID
|
||||
EnvKeyLinkedInClientID = "LINKEDIN_CLIENT_ID"
|
||||
// EnvKeyLinkedinClientSecret key for env variable LINKEDIN_CLIENT_SECRET
|
||||
EnvKeyLinkedInClientSecret = "LINKEDIN_CLIENT_SECRET"
|
||||
// EnvKeyAppleClientID key for env variable APPLE_CLIENT_ID
|
||||
EnvKeyAppleClientID = "APPLE_CLIENT_ID"
|
||||
// EnvKeyAppleClientSecret key for env variable APPLE_CLIENT_SECRET
|
||||
EnvKeyAppleClientSecret = "APPLE_CLIENT_SECRET"
|
||||
// EnvKeyOrganizationName key for env variable ORGANIZATION_NAME
|
||||
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
||||
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
||||
@@ -120,6 +99,32 @@ const (
|
||||
EnvKeyEncryptionKey = "ENCRYPTION_KEY"
|
||||
// EnvKeyJWK key for env variable JWK
|
||||
EnvKeyJWK = "JWK"
|
||||
|
||||
// Boolean variables
|
||||
// EnvKeyIsProd key for env variable IS_PROD
|
||||
EnvKeyIsProd = "IS_PROD"
|
||||
// EnvKeyDisableEmailVerification key for env variable DISABLE_EMAIL_VERIFICATION
|
||||
EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION"
|
||||
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
|
||||
EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION"
|
||||
// EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN
|
||||
EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN"
|
||||
// EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE
|
||||
EnvKeyDisableLoginPage = "DISABLE_LOGIN_PAGE"
|
||||
// EnvKeyDisableSignUp key for env variable DISABLE_SIGN_UP
|
||||
EnvKeyDisableSignUp = "DISABLE_SIGN_UP"
|
||||
// EnvKeyDisableRedisForEnv key for env variable DISABLE_REDIS_FOR_ENV
|
||||
EnvKeyDisableRedisForEnv = "DISABLE_REDIS_FOR_ENV"
|
||||
// EnvKeyDisableStrongPassword key for env variable DISABLE_STRONG_PASSWORD
|
||||
EnvKeyDisableStrongPassword = "DISABLE_STRONG_PASSWORD"
|
||||
|
||||
// Slice variables
|
||||
// EnvKeyRoles key for env variable ROLES
|
||||
EnvKeyRoles = "ROLES"
|
||||
// EnvKeyProtectedRoles key for env variable PROTECTED_ROLES
|
||||
EnvKeyProtectedRoles = "PROTECTED_ROLES"
|
||||
// EnvKeyDefaultRoles key for env variable DEFAULT_ROLES
|
||||
EnvKeyDefaultRoles = "DEFAULT_ROLES"
|
||||
// EnvKeyAllowedOrigins key for env variable ALLOWED_ORIGINS
|
||||
EnvKeyAllowedOrigins = "ALLOWED_ORIGINS"
|
||||
)
|
||||
|
@@ -8,4 +8,10 @@ const (
|
||||
FacebookUserInfoURL = "https://graph.facebook.com/me?fields=id,first_name,last_name,name,email,picture&access_token="
|
||||
// Ref: https://docs.github.com/en/developers/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#3-your-github-app-accesses-the-api-with-the-users-access-token
|
||||
GithubUserInfoURL = "https://api.github.com/user"
|
||||
// Get github user emails when user info email is empty Ref: https://stackoverflow.com/a/35387123
|
||||
GithubUserEmails = "https://api/github.com/user/emails"
|
||||
|
||||
// Ref: https://docs.microsoft.com/en-us/linkedin/shared/integrations/people/profile-api
|
||||
LinkedInUserInfoURL = "https://api.linkedin.com/v2/me?projection=(id,localizedFirstName,localizedLastName,emailAddress,profilePicture(displayImage~:playableStreams))"
|
||||
LinkedInEmailURL = "https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))"
|
||||
)
|
||||
|
@@ -1,14 +0,0 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
// SignupMethodBasicAuth is the basic_auth signup method
|
||||
SignupMethodBasicAuth = "basic_auth"
|
||||
// SignupMethodMagicLinkLogin is the magic_link_login signup method
|
||||
SignupMethodMagicLinkLogin = "magic_link_login"
|
||||
// SignupMethodGoogle is the google signup method
|
||||
SignupMethodGoogle = "google"
|
||||
// SignupMethodGithub is the github signup method
|
||||
SignupMethodGithub = "github"
|
||||
// SignupMethodFacebook is the facebook signup method
|
||||
SignupMethodFacebook = "facebook"
|
||||
)
|
@@ -7,4 +7,6 @@ const (
|
||||
TokenTypeAccessToken = "access_token"
|
||||
// TokenTypeIdentityToken is the identity_token token type
|
||||
TokenTypeIdentityToken = "id_token"
|
||||
// TokenTypeSessionToken is the session_token type used for browser session
|
||||
TokenTypeSessionToken = "session_token"
|
||||
)
|
||||
|
18
server/constants/webhook_event.go
Normal file
18
server/constants/webhook_event.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
|
||||
// UserLoginWebhookEvent name for login event
|
||||
UserLoginWebhookEvent = `user.login`
|
||||
// UserCreatedWebhookEvent name for user creation event
|
||||
// This is triggered when user entry is created but still not verified
|
||||
UserCreatedWebhookEvent = `user.created`
|
||||
// UserSignUpWebhookEvent name for signup event
|
||||
UserSignUpWebhookEvent = `user.signup`
|
||||
// UserAccessRevokedWebhookEvent name for user access revoke event
|
||||
UserAccessRevokedWebhookEvent = `user.access_revoked`
|
||||
// UserAccessEnabledWebhookEvent name for user access enable event
|
||||
UserAccessEnabledWebhookEvent = `user.access_enabled`
|
||||
// UserDeletedWebhookEvent name for user deleted event
|
||||
UserDeletedWebhookEvent = `user.deleted`
|
||||
)
|
@@ -4,8 +4,7 @@ import (
|
||||
"net/url"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
"github.com/authorizerdev/authorizer/server/parsers"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -13,15 +12,14 @@ import (
|
||||
func SetAdminCookie(gc *gin.Context, token string) {
|
||||
secure := true
|
||||
httpOnly := true
|
||||
hostname := utils.GetHost(gc)
|
||||
host, _ := utils.GetHostParts(hostname)
|
||||
|
||||
gc.SetCookie(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminCookieName), token, 3600, "/", host, secure, httpOnly)
|
||||
hostname := parsers.GetHost(gc)
|
||||
host, _ := parsers.GetHostParts(hostname)
|
||||
gc.SetCookie(constants.AdminCookieName, token, 3600, "/", host, secure, httpOnly)
|
||||
}
|
||||
|
||||
// GetAdminCookie gets the admin cookie from the request
|
||||
func GetAdminCookie(gc *gin.Context) (string, error) {
|
||||
cookie, err := gc.Request.Cookie(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminCookieName))
|
||||
cookie, err := gc.Request.Cookie(constants.AdminCookieName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -39,8 +37,7 @@ func GetAdminCookie(gc *gin.Context) (string, error) {
|
||||
func DeleteAdminCookie(gc *gin.Context) {
|
||||
secure := true
|
||||
httpOnly := true
|
||||
hostname := utils.GetHost(gc)
|
||||
host, _ := utils.GetHostParts(hostname)
|
||||
|
||||
gc.SetCookie(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminCookieName), "", -1, "/", host, secure, httpOnly)
|
||||
hostname := parsers.GetHost(gc)
|
||||
host, _ := parsers.GetHostParts(hostname)
|
||||
gc.SetCookie(constants.AdminCookieName, "", -1, "/", host, secure, httpOnly)
|
||||
}
|
||||
|
@@ -5,8 +5,7 @@ import (
|
||||
"net/url"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
"github.com/authorizerdev/authorizer/server/parsers"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -14,9 +13,9 @@ import (
|
||||
func SetSession(gc *gin.Context, sessionID string) {
|
||||
secure := true
|
||||
httpOnly := true
|
||||
hostname := utils.GetHost(gc)
|
||||
host, _ := utils.GetHostParts(hostname)
|
||||
domain := utils.GetDomainName(hostname)
|
||||
hostname := parsers.GetHost(gc)
|
||||
host, _ := parsers.GetHostParts(hostname)
|
||||
domain := parsers.GetDomainName(hostname)
|
||||
if domain != "localhost" {
|
||||
domain = "." + domain
|
||||
}
|
||||
@@ -25,33 +24,33 @@ func SetSession(gc *gin.Context, sessionID string) {
|
||||
year := 60 * 60 * 24 * 365
|
||||
|
||||
gc.SetSameSite(http.SameSiteNoneMode)
|
||||
gc.SetCookie(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyCookieName)+"_session", sessionID, year, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyCookieName)+"_session_domain", sessionID, year, "/", domain, secure, httpOnly)
|
||||
gc.SetCookie(constants.AppCookieName+"_session", sessionID, year, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(constants.AppCookieName+"_session_domain", sessionID, year, "/", domain, secure, httpOnly)
|
||||
}
|
||||
|
||||
// DeleteSession sets session cookies to expire
|
||||
func DeleteSession(gc *gin.Context) {
|
||||
secure := true
|
||||
httpOnly := true
|
||||
hostname := utils.GetHost(gc)
|
||||
host, _ := utils.GetHostParts(hostname)
|
||||
domain := utils.GetDomainName(hostname)
|
||||
hostname := parsers.GetHost(gc)
|
||||
host, _ := parsers.GetHostParts(hostname)
|
||||
domain := parsers.GetDomainName(hostname)
|
||||
if domain != "localhost" {
|
||||
domain = "." + domain
|
||||
}
|
||||
|
||||
gc.SetSameSite(http.SameSiteNoneMode)
|
||||
gc.SetCookie(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyCookieName)+"_session", "", -1, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyCookieName)+"_session_domain", "", -1, "/", domain, secure, httpOnly)
|
||||
gc.SetCookie(constants.AppCookieName+"_session", "", -1, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(constants.AppCookieName+"_session_domain", "", -1, "/", domain, secure, httpOnly)
|
||||
}
|
||||
|
||||
// GetSession gets the session cookie from context
|
||||
func GetSession(gc *gin.Context) (string, error) {
|
||||
var cookie *http.Cookie
|
||||
var err error
|
||||
cookie, err = gc.Request.Cookie(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyCookieName) + "_session")
|
||||
cookie, err = gc.Request.Cookie(constants.AppCookieName + "_session")
|
||||
if err != nil {
|
||||
cookie, err = gc.Request.Cookie(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyCookieName) + "_session_domain")
|
||||
cookie, err = gc.Request.Cookie(constants.AppCookieName + "_session_domain")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@@ -7,14 +7,18 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
)
|
||||
|
||||
var bytes = []byte{35, 46, 57, 24, 85, 35, 24, 74, 87, 35, 88, 98, 66, 32, 14, 0o5}
|
||||
|
||||
// EncryptAES method is to encrypt or hide any classified text
|
||||
func EncryptAES(text string) (string, error) {
|
||||
key := []byte(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey))
|
||||
k, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
key := []byte(k)
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -28,7 +32,11 @@ func EncryptAES(text string) (string, error) {
|
||||
|
||||
// DecryptAES method is to extract back the encrypted text
|
||||
func DecryptAES(text string) (string, error) {
|
||||
key := []byte(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey))
|
||||
k, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
key := []byte(k)
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -46,9 +54,13 @@ func DecryptAES(text string) (string, error) {
|
||||
// EncryptAESEnv encrypts data using AES algorithm
|
||||
// kept for the backward compatibility of env data encryption
|
||||
func EncryptAESEnv(text []byte) ([]byte, error) {
|
||||
key := []byte(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey))
|
||||
c, err := aes.NewCipher(key)
|
||||
var res []byte
|
||||
k, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
key := []byte(k)
|
||||
c, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@@ -81,9 +93,13 @@ func EncryptAESEnv(text []byte) ([]byte, error) {
|
||||
// DecryptAES decrypts data using AES algorithm
|
||||
// Kept for the backward compatibility of env data decryption
|
||||
func DecryptAESEnv(ciphertext []byte) ([]byte, error) {
|
||||
key := []byte(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey))
|
||||
c, err := aes.NewCipher(key)
|
||||
var res []byte
|
||||
k, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
key := []byte(k)
|
||||
c, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
)
|
||||
@@ -37,20 +37,35 @@ func GetPubJWK(algo, keyID string, publicKey interface{}) (string, error) {
|
||||
// this is called while initializing app / when env is updated
|
||||
func GenerateJWKBasedOnEnv() (string, error) {
|
||||
jwk := ""
|
||||
algo := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType)
|
||||
clientID := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyClientID)
|
||||
algo, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType)
|
||||
if err != nil {
|
||||
return jwk, err
|
||||
}
|
||||
clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID)
|
||||
if err != nil {
|
||||
return jwk, err
|
||||
}
|
||||
|
||||
jwtSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)
|
||||
if err != nil {
|
||||
return jwk, err
|
||||
}
|
||||
|
||||
var err error
|
||||
// check if jwt secret is provided
|
||||
if IsHMACA(algo) {
|
||||
jwk, err = GetPubJWK(algo, clientID, []byte(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)))
|
||||
jwk, err = GetPubJWK(algo, clientID, []byte(jwtSecret))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
jwtPublicKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey)
|
||||
if err != nil {
|
||||
return jwk, err
|
||||
}
|
||||
|
||||
if IsRSA(algo) {
|
||||
publicKeyInstance, err := ParseRsaPublicKeyFromPemStr(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey))
|
||||
publicKeyInstance, err := ParseRsaPublicKeyFromPemStr(jwtPublicKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -62,7 +77,11 @@ func GenerateJWKBasedOnEnv() (string, error) {
|
||||
}
|
||||
|
||||
if IsECDSA(algo) {
|
||||
publicKeyInstance, err := ParseEcdsaPublicKeyFromPemStr(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey))
|
||||
jwtPublicKey, err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey)
|
||||
if err != nil {
|
||||
return jwk, err
|
||||
}
|
||||
publicKeyInstance, err := ParseEcdsaPublicKeyFromPemStr(jwtPublicKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -77,13 +96,16 @@ func GenerateJWKBasedOnEnv() (string, error) {
|
||||
}
|
||||
|
||||
// EncryptEnvData is used to encrypt the env data
|
||||
func EncryptEnvData(data envstore.Store) (string, error) {
|
||||
func EncryptEnvData(data map[string]interface{}) (string, error) {
|
||||
jsonBytes, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
storeData := envstore.EnvStoreObj.GetEnvStoreClone()
|
||||
storeData, err := memorystore.Provider.GetEnvStore()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(jsonBytes, &storeData)
|
||||
if err != nil {
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/authorizerdev/authorizer/server/db/providers/cassandradb"
|
||||
"github.com/authorizerdev/authorizer/server/db/providers/mongodb"
|
||||
"github.com/authorizerdev/authorizer/server/db/providers/sql"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
)
|
||||
|
||||
// Provider returns the current database provider
|
||||
@@ -18,13 +18,15 @@ var Provider providers.Provider
|
||||
func InitDB() error {
|
||||
var err error
|
||||
|
||||
isSQL := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) != constants.DbTypeArangodb && envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) != constants.DbTypeMongodb && envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) != constants.DbTypeCassandraDB
|
||||
isArangoDB := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) == constants.DbTypeArangodb
|
||||
isMongoDB := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) == constants.DbTypeMongodb
|
||||
isCassandra := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) == constants.DbTypeCassandraDB
|
||||
envs := memorystore.RequiredEnvStoreObj.GetRequiredEnv()
|
||||
|
||||
isSQL := envs.DatabaseType != constants.DbTypeArangodb && envs.DatabaseType != constants.DbTypeMongodb && envs.DatabaseType != constants.DbTypeCassandraDB && envs.DatabaseType != constants.DbTypeScyllaDB
|
||||
isArangoDB := envs.DatabaseType == constants.DbTypeArangodb
|
||||
isMongoDB := envs.DatabaseType == constants.DbTypeMongodb
|
||||
isCassandra := envs.DatabaseType == constants.DbTypeCassandraDB || envs.DatabaseType == constants.DbTypeScyllaDB
|
||||
|
||||
if isSQL {
|
||||
log.Info("Initializing SQL Driver for: ", envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType))
|
||||
log.Info("Initializing SQL Driver for: ", envs.DatabaseType)
|
||||
Provider, err = sql.NewProvider()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to initialize SQL driver: ", err)
|
||||
|
33
server/db/models/email_templates.go
Normal file
33
server/db/models/email_templates.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
)
|
||||
|
||||
// EmailTemplate model for database
|
||||
type EmailTemplate struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
|
||||
EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name"`
|
||||
Template string `gorm:"type:text" json:"template" bson:"template" cql:"template"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
|
||||
}
|
||||
|
||||
// AsAPIEmailTemplate to return email template as graphql response object
|
||||
func (e *EmailTemplate) AsAPIEmailTemplate() *model.EmailTemplate {
|
||||
id := e.ID
|
||||
if strings.Contains(id, Collections.EmailTemplate+"/") {
|
||||
id = strings.TrimPrefix(id, Collections.EmailTemplate+"/")
|
||||
}
|
||||
return &model.EmailTemplate{
|
||||
ID: id,
|
||||
EventName: e.EventName,
|
||||
Template: e.Template,
|
||||
CreatedAt: refs.NewInt64Ref(e.CreatedAt),
|
||||
UpdatedAt: refs.NewInt64Ref(e.UpdatedAt),
|
||||
}
|
||||
}
|
@@ -6,6 +6,9 @@ type CollectionList struct {
|
||||
VerificationRequest string
|
||||
Session string
|
||||
Env string
|
||||
Webhook string
|
||||
WebhookLog string
|
||||
EmailTemplate string
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -17,5 +20,8 @@ var (
|
||||
VerificationRequest: Prefix + "verification_requests",
|
||||
Session: Prefix + "sessions",
|
||||
Env: Prefix + "env",
|
||||
Webhook: Prefix + "webhook",
|
||||
WebhookLog: Prefix + "webhook_log",
|
||||
EmailTemplate: Prefix + "email_template",
|
||||
}
|
||||
)
|
||||
|
@@ -6,8 +6,7 @@ package models
|
||||
type Session struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
|
||||
UserID string `gorm:"type:char(36),index:" json:"user_id" bson:"user_id" cql:"user_id"`
|
||||
User User `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" bson:"-" cql:"-"`
|
||||
UserID string `gorm:"type:char(36)" json:"user_id" bson:"user_id" cql:"user_id"`
|
||||
UserAgent string `json:"user_agent" bson:"user_agent" cql:"user_agent"`
|
||||
IP string `json:"ip" bson:"ip" cql:"ip"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
)
|
||||
|
||||
// Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation
|
||||
@@ -35,12 +36,13 @@ type User struct {
|
||||
func (user *User) AsAPIUser() *model.User {
|
||||
isEmailVerified := user.EmailVerifiedAt != nil
|
||||
isPhoneVerified := user.PhoneNumberVerifiedAt != nil
|
||||
email := user.Email
|
||||
createdAt := user.CreatedAt
|
||||
updatedAt := user.UpdatedAt
|
||||
revokedTimestamp := user.RevokedTimestamp
|
||||
|
||||
id := user.ID
|
||||
if strings.Contains(id, Collections.WebhookLog+"/") {
|
||||
id = strings.TrimPrefix(id, Collections.WebhookLog+"/")
|
||||
}
|
||||
return &model.User{
|
||||
ID: user.ID,
|
||||
ID: id,
|
||||
Email: user.Email,
|
||||
EmailVerified: isEmailVerified,
|
||||
SignupMethods: user.SignupMethods,
|
||||
@@ -48,15 +50,15 @@ func (user *User) AsAPIUser() *model.User {
|
||||
FamilyName: user.FamilyName,
|
||||
MiddleName: user.MiddleName,
|
||||
Nickname: user.Nickname,
|
||||
PreferredUsername: &email,
|
||||
PreferredUsername: refs.NewStringRef(user.Email),
|
||||
Gender: user.Gender,
|
||||
Birthdate: user.Birthdate,
|
||||
PhoneNumber: user.PhoneNumber,
|
||||
PhoneNumberVerified: &isPhoneVerified,
|
||||
Picture: user.Picture,
|
||||
Roles: strings.Split(user.Roles, ","),
|
||||
RevokedTimestamp: revokedTimestamp,
|
||||
CreatedAt: &createdAt,
|
||||
UpdatedAt: &updatedAt,
|
||||
RevokedTimestamp: user.RevokedTimestamp,
|
||||
CreatedAt: refs.NewInt64Ref(user.CreatedAt),
|
||||
UpdatedAt: refs.NewInt64Ref(user.UpdatedAt),
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,11 @@
|
||||
package models
|
||||
|
||||
import "github.com/authorizerdev/authorizer/server/graph/model"
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
)
|
||||
|
||||
// Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation
|
||||
|
||||
@@ -19,23 +24,20 @@ type VerificationRequest struct {
|
||||
}
|
||||
|
||||
func (v *VerificationRequest) AsAPIVerificationRequest() *model.VerificationRequest {
|
||||
token := v.Token
|
||||
createdAt := v.CreatedAt
|
||||
updatedAt := v.UpdatedAt
|
||||
email := v.Email
|
||||
nonce := v.Nonce
|
||||
redirectURI := v.RedirectURI
|
||||
expires := v.ExpiresAt
|
||||
identifier := v.Identifier
|
||||
id := v.ID
|
||||
if strings.Contains(id, Collections.WebhookLog+"/") {
|
||||
id = strings.TrimPrefix(id, Collections.WebhookLog+"/")
|
||||
}
|
||||
|
||||
return &model.VerificationRequest{
|
||||
ID: v.ID,
|
||||
Token: &token,
|
||||
Identifier: &identifier,
|
||||
Expires: &expires,
|
||||
Email: &email,
|
||||
Nonce: &nonce,
|
||||
RedirectURI: &redirectURI,
|
||||
CreatedAt: &createdAt,
|
||||
UpdatedAt: &updatedAt,
|
||||
ID: id,
|
||||
Token: refs.NewStringRef(v.Token),
|
||||
Identifier: refs.NewStringRef(v.Identifier),
|
||||
Expires: refs.NewInt64Ref(v.ExpiresAt),
|
||||
Email: refs.NewStringRef(v.Email),
|
||||
Nonce: refs.NewStringRef(v.Nonce),
|
||||
RedirectURI: refs.NewStringRef(v.RedirectURI),
|
||||
CreatedAt: refs.NewInt64Ref(v.CreatedAt),
|
||||
UpdatedAt: refs.NewInt64Ref(v.UpdatedAt),
|
||||
}
|
||||
}
|
||||
|
44
server/db/models/webhook.go
Normal file
44
server/db/models/webhook.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
)
|
||||
|
||||
// Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation
|
||||
|
||||
// Webhook model for db
|
||||
type Webhook struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
|
||||
EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name"`
|
||||
EndPoint string `gorm:"type:text" json:"endpoint" bson:"endpoint" cql:"endpoint"`
|
||||
Headers string `gorm:"type:text" json:"headers" bson:"headers" cql:"headers"`
|
||||
Enabled bool `json:"enabled" bson:"enabled" cql:"enabled"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
|
||||
}
|
||||
|
||||
// AsAPIWebhook to return webhook as graphql response object
|
||||
func (w *Webhook) AsAPIWebhook() *model.Webhook {
|
||||
headersMap := make(map[string]interface{})
|
||||
json.Unmarshal([]byte(w.Headers), &headersMap)
|
||||
|
||||
id := w.ID
|
||||
if strings.Contains(id, Collections.Webhook+"/") {
|
||||
id = strings.TrimPrefix(id, Collections.Webhook+"/")
|
||||
}
|
||||
|
||||
return &model.Webhook{
|
||||
ID: id,
|
||||
EventName: refs.NewStringRef(w.EventName),
|
||||
Endpoint: refs.NewStringRef(w.EndPoint),
|
||||
Headers: headersMap,
|
||||
Enabled: refs.NewBoolRef(w.Enabled),
|
||||
CreatedAt: refs.NewInt64Ref(w.CreatedAt),
|
||||
UpdatedAt: refs.NewInt64Ref(w.UpdatedAt),
|
||||
}
|
||||
}
|
39
server/db/models/webhook_log.go
Normal file
39
server/db/models/webhook_log.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
)
|
||||
|
||||
// Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation
|
||||
|
||||
// WebhookLog model for db
|
||||
type WebhookLog struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
|
||||
HttpStatus int64 `json:"http_status" bson:"http_status" cql:"http_status"`
|
||||
Response string `gorm:"type:text" json:"response" bson:"response" cql:"response"`
|
||||
Request string `gorm:"type:text" json:"request" bson:"request" cql:"request"`
|
||||
WebhookID string `gorm:"type:char(36)" json:"webhook_id" bson:"webhook_id" cql:"webhook_id"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
|
||||
}
|
||||
|
||||
// AsAPIWebhookLog to return webhook log as graphql response object
|
||||
func (w *WebhookLog) AsAPIWebhookLog() *model.WebhookLog {
|
||||
id := w.ID
|
||||
if strings.Contains(id, Collections.WebhookLog+"/") {
|
||||
id = strings.TrimPrefix(id, Collections.WebhookLog+"/")
|
||||
}
|
||||
return &model.WebhookLog{
|
||||
ID: id,
|
||||
HTTPStatus: refs.NewInt64Ref(w.HttpStatus),
|
||||
Response: refs.NewStringRef(w.Response),
|
||||
Request: refs.NewStringRef(w.Request),
|
||||
WebhookID: refs.NewStringRef(w.WebhookID),
|
||||
CreatedAt: refs.NewInt64Ref(w.CreatedAt),
|
||||
UpdatedAt: refs.NewInt64Ref(w.UpdatedAt),
|
||||
}
|
||||
}
|
151
server/db/providers/arangodb/email_template.go
Normal file
151
server/db/providers/arangodb/email_template.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package arangodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
arangoDriver "github.com/arangodb/go-driver"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddEmailTemplate to add EmailTemplate
|
||||
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(ctx, models.Collections.EmailTemplate)
|
||||
_, err := emailTemplateCollection.CreateDocument(ctx, emailTemplate)
|
||||
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) {
|
||||
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) {
|
||||
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 := driver.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
|
||||
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,
|
||||
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
|
||||
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 == "" {
|
||||
return nil, fmt.Errorf("email template not found")
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(ctx, &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) {
|
||||
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 == "" {
|
||||
return nil, fmt.Errorf("email template not found")
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(ctx, &emailTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// DeleteEmailTemplate to delete EmailTemplate
|
||||
func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error {
|
||||
eventTemplateCollection, _ := p.db.Collection(ctx, models.Collections.EmailTemplate)
|
||||
_, err := eventTemplateCollection.RemoveDocument(ctx, emailTemplate.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package arangodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -11,15 +12,15 @@ import (
|
||||
)
|
||||
|
||||
// AddEnv to save environment information in database
|
||||
func (p *provider) AddEnv(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()
|
||||
configCollection, _ := p.db.Collection(nil, models.Collections.Env)
|
||||
meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(nil), env)
|
||||
configCollection, _ := p.db.Collection(ctx, models.Collections.Env)
|
||||
meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), env)
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
@@ -29,10 +30,10 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
|
||||
}
|
||||
|
||||
// UpdateEnv to update environment information in database
|
||||
func (p *provider) UpdateEnv(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(nil, models.Collections.Env)
|
||||
meta, err := collection.UpdateDocument(nil, env.Key, env)
|
||||
collection, _ := p.db.Collection(ctx, models.Collections.Env)
|
||||
meta, err := collection.UpdateDocument(ctx, env.Key, env)
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
@@ -43,11 +44,11 @@ func (p *provider) UpdateEnv(env models.Env) (models.Env, error) {
|
||||
}
|
||||
|
||||
// GetEnv to get environment information from database
|
||||
func (p *provider) GetEnv() (models.Env, error) {
|
||||
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(nil, query, nil)
|
||||
cursor, err := p.db.Query(ctx, query, nil)
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
@@ -60,7 +61,7 @@ func (p *provider) GetEnv() (models.Env, error) {
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(nil, &env)
|
||||
_, err := cursor.ReadDocument(ctx, &env)
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
|
@@ -6,9 +6,8 @@ import (
|
||||
"github.com/arangodb/go-driver"
|
||||
arangoDriver "github.com/arangodb/go-driver"
|
||||
"github.com/arangodb/go-driver/http"
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
)
|
||||
|
||||
type provider struct {
|
||||
@@ -22,8 +21,9 @@ type provider struct {
|
||||
// NewProvider to initialize arangodb connection
|
||||
func NewProvider() (*provider, error) {
|
||||
ctx := context.Background()
|
||||
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
||||
conn, err := http.NewConnection(http.ConnectionConfig{
|
||||
Endpoints: []string{envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)},
|
||||
Endpoints: []string{dbURL},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -37,16 +37,16 @@ func NewProvider() (*provider, error) {
|
||||
}
|
||||
|
||||
var arangodb driver.Database
|
||||
|
||||
arangodb_exists, err := arangoClient.DatabaseExists(nil, envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseName))
|
||||
dbName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName
|
||||
arangodb_exists, err := arangoClient.DatabaseExists(nil, dbName)
|
||||
|
||||
if arangodb_exists {
|
||||
arangodb, err = arangoClient.Database(nil, envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseName))
|
||||
arangodb, err = arangoClient.Database(nil, dbName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
arangodb, err = arangoClient.CreateDatabase(nil, envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseName), nil)
|
||||
arangodb, err = arangoClient.CreateDatabase(nil, dbName, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -107,6 +107,47 @@ func NewProvider() (*provider, error) {
|
||||
}
|
||||
}
|
||||
|
||||
webhookCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Webhook)
|
||||
if !webhookCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.Webhook, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
webhookCollection, _ := arangodb.Collection(nil, models.Collections.Webhook)
|
||||
webhookCollection.EnsureHashIndex(ctx, []string{"event_name"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
webhookLogCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.WebhookLog)
|
||||
if !webhookLogCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.WebhookLog, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
webhookLogCollection, _ := arangodb.Collection(nil, models.Collections.WebhookLog)
|
||||
webhookLogCollection.EnsureHashIndex(ctx, []string{"webhook_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
emailTemplateCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.EmailTemplate)
|
||||
if !emailTemplateCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.EmailTemplate, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
emailTemplateCollection, _ := arangodb.Collection(nil, models.Collections.EmailTemplate)
|
||||
emailTemplateCollection.EnsureHashIndex(ctx, []string{"event_name"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
return &provider{
|
||||
db: arangodb,
|
||||
}, err
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package arangodb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
@@ -9,31 +9,17 @@ import (
|
||||
)
|
||||
|
||||
// AddSession to save session information in database
|
||||
func (p *provider) AddSession(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()
|
||||
sessionCollection, _ := p.db.Collection(nil, models.Collections.Session)
|
||||
_, err := sessionCollection.CreateDocument(nil, session)
|
||||
sessionCollection, _ := p.db.Collection(ctx, models.Collections.Session)
|
||||
_, err := sessionCollection.CreateDocument(ctx, session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteSession to delete session information from database
|
||||
func (p *provider) DeleteSession(userId string) error {
|
||||
query := fmt.Sprintf(`FOR d IN %s FILTER d.user_id == @userId REMOVE { _key: d._key } IN %s`, models.Collections.Session, models.Collections.Session)
|
||||
bindVars := map[string]interface{}{
|
||||
"userId": userId,
|
||||
}
|
||||
cursor, err := p.db.Query(nil, query, bindVars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cursor.Close()
|
||||
return nil
|
||||
}
|
||||
|
@@ -3,32 +3,35 @@ package arangodb
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
arangoDriver "github.com/arangodb/go-driver"
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddUser to save user information in database
|
||||
func (p *provider) AddUser(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 == "" {
|
||||
user.Roles = strings.Join(envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles), ",")
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
userCollection, _ := p.db.Collection(nil, models.Collections.User)
|
||||
meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(nil), user)
|
||||
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||
meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -39,10 +42,10 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
|
||||
}
|
||||
|
||||
// UpdateUser to update user information in database
|
||||
func (p *provider) UpdateUser(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(nil, models.Collections.User)
|
||||
meta, err := collection.UpdateDocument(nil, user.Key, user)
|
||||
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||
meta, err := collection.UpdateDocument(ctx, user.Key, user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -53,24 +56,34 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) {
|
||||
}
|
||||
|
||||
// DeleteUser to delete user information from database
|
||||
func (p *provider) DeleteUser(user models.User) error {
|
||||
collection, _ := p.db.Collection(nil, models.Collections.User)
|
||||
_, err := collection.RemoveDocument(nil, user.Key)
|
||||
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.ID,
|
||||
}
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cursor.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListUsers to get list of users from database
|
||||
func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error) {
|
||||
func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
|
||||
var users []*model.User
|
||||
ctx := driver.WithQueryFullCount(context.Background())
|
||||
sctx := driver.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(ctx, query, nil)
|
||||
cursor, err := p.db.Query(sctx, query, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -81,7 +94,7 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
|
||||
|
||||
for {
|
||||
var user models.User
|
||||
meta, err := cursor.ReadDocument(nil, &user)
|
||||
meta, err := cursor.ReadDocument(ctx, &user)
|
||||
|
||||
if arangoDriver.IsNoMoreDocuments(err) {
|
||||
break
|
||||
@@ -101,7 +114,7 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
|
||||
}
|
||||
|
||||
// GetUserByEmail to get user information from database using email address
|
||||
func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
||||
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)
|
||||
@@ -109,7 +122,7 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
||||
"email": email,
|
||||
}
|
||||
|
||||
cursor, err := p.db.Query(nil, query, bindVars)
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -122,7 +135,7 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(nil, &user)
|
||||
_, err := cursor.ReadDocument(ctx, &user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -132,7 +145,7 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
||||
}
|
||||
|
||||
// GetUserByID to get user information from database using user ID
|
||||
func (p *provider) GetUserByID(id string) (models.User, error) {
|
||||
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)
|
||||
@@ -140,7 +153,7 @@ func (p *provider) GetUserByID(id string) (models.User, error) {
|
||||
"id": id,
|
||||
}
|
||||
|
||||
cursor, err := p.db.Query(nil, query, bindVars)
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -153,7 +166,7 @@ func (p *provider) GetUserByID(id string) (models.User, error) {
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(nil, &user)
|
||||
_, err := cursor.ReadDocument(ctx, &user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
@@ -12,15 +12,15 @@ import (
|
||||
)
|
||||
|
||||
// AddVerification to save verification request in database
|
||||
func (p *provider) AddVerificationRequest(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.CreatedAt = time.Now().Unix()
|
||||
verificationRequest.UpdatedAt = time.Now().Unix()
|
||||
verificationRequestRequestCollection, _ := p.db.Collection(nil, models.Collections.VerificationRequest)
|
||||
meta, err := verificationRequestRequestCollection.CreateDocument(nil, verificationRequest)
|
||||
verificationRequestRequestCollection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
|
||||
meta, err := verificationRequestRequestCollection.CreateDocument(ctx, verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
@@ -31,14 +31,14 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
|
||||
}
|
||||
|
||||
// GetVerificationRequestByToken to get verification request from database using token
|
||||
func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) {
|
||||
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(nil, query, bindVars)
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func (p *provider) GetVerificationRequestByToken(token string) (models.Verificat
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(nil, &verificationRequest)
|
||||
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func (p *provider) GetVerificationRequestByToken(token string) (models.Verificat
|
||||
}
|
||||
|
||||
// GetVerificationRequestByEmail to get verification request by email from database
|
||||
func (p *provider) GetVerificationRequestByEmail(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("FOR d in %s FILTER d.email == @email FILTER d.identifier == @identifier LIMIT 1 RETURN d", models.Collections.VerificationRequest)
|
||||
@@ -70,7 +70,7 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
|
||||
"identifier": identifier,
|
||||
}
|
||||
|
||||
cursor, err := p.db.Query(nil, query, bindVars)
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
@@ -83,7 +83,7 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(nil, &verificationRequest)
|
||||
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
@@ -93,12 +93,12 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
|
||||
}
|
||||
|
||||
// ListVerificationRequests to get list of verification requests from database
|
||||
func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model.VerificationRequests, error) {
|
||||
func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
|
||||
var verificationRequests []*model.VerificationRequest
|
||||
ctx := driver.WithQueryFullCount(context.Background())
|
||||
sctx := driver.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(ctx, query, nil)
|
||||
cursor, err := p.db.Query(sctx, query, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
|
||||
|
||||
for {
|
||||
var verificationRequest models.VerificationRequest
|
||||
meta, err := cursor.ReadDocument(nil, &verificationRequest)
|
||||
meta, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||
|
||||
if driver.IsNoMoreDocuments(err) {
|
||||
break
|
||||
@@ -130,7 +130,7 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
|
||||
}
|
||||
|
||||
// DeleteVerificationRequest to delete verification request from database
|
||||
func (p *provider) DeleteVerificationRequest(verificationRequest models.VerificationRequest) error {
|
||||
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
||||
collection, _ := p.db.Collection(nil, models.Collections.VerificationRequest)
|
||||
_, err := collection.RemoveDocument(nil, verificationRequest.Key)
|
||||
if err != nil {
|
||||
|
161
server/db/providers/arangodb/webhook.go
Normal file
161
server/db/providers/arangodb/webhook.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package arangodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
arangoDriver "github.com/arangodb/go-driver"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddWebhook to add webhook
|
||||
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
|
||||
webhook.CreatedAt = time.Now().Unix()
|
||||
webhook.UpdatedAt = time.Now().Unix()
|
||||
webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook)
|
||||
_, err := webhookCollection.CreateDocument(ctx, webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// UpdateWebhook to update webhook
|
||||
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
||||
webhook.UpdatedAt = time.Now().Unix()
|
||||
webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook)
|
||||
meta, err := webhookCollection.UpdateDocument(ctx, webhook.Key, webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
webhook.Key = meta.Key
|
||||
webhook.ID = meta.ID.String()
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// ListWebhooks to list webhook
|
||||
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 := driver.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 webhook models.Webhook
|
||||
meta, err := cursor.ReadDocument(ctx, &webhook)
|
||||
|
||||
if arangoDriver.IsNoMoreDocuments(err) {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if meta.Key != "" {
|
||||
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||
}
|
||||
}
|
||||
|
||||
return &model.Webhooks{
|
||||
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
|
||||
query := fmt.Sprintf("FOR d in %s FILTER d._key == @webhook_id RETURN d", models.Collections.Webhook)
|
||||
bindVars := map[string]interface{}{
|
||||
"webhook_id": webhookID,
|
||||
}
|
||||
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
|
||||
for {
|
||||
if !cursor.HasMore() {
|
||||
if webhook.Key == "" {
|
||||
return nil, fmt.Errorf("webhook not found")
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(ctx, &webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// GetWebhookByEventName to get webhook by event_name
|
||||
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
|
||||
var webhook models.Webhook
|
||||
query := fmt.Sprintf("FOR d in %s FILTER d.event_name == @event_name RETURN d", models.Collections.Webhook)
|
||||
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 webhook.Key == "" {
|
||||
return nil, fmt.Errorf("webhook not found")
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(ctx, &webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// DeleteWebhook to delete webhook
|
||||
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
||||
webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook)
|
||||
_, err := webhookCollection.RemoveDocument(ctx, webhook.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("FOR d IN %s FILTER d.webhook_id == @webhook_id REMOVE { _key: d._key } IN %s", models.Collections.WebhookLog, models.Collections.WebhookLog)
|
||||
bindVars := map[string]interface{}{
|
||||
"webhook_id": webhook.ID,
|
||||
}
|
||||
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cursor.Close()
|
||||
|
||||
return nil
|
||||
}
|
75
server/db/providers/arangodb/webhook_log.go
Normal file
75
server/db/providers/arangodb/webhook_log.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package arangodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
arangoDriver "github.com/arangodb/go-driver"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddWebhookLog to add webhook log
|
||||
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()
|
||||
webhookLogCollection, _ := p.db.Collection(ctx, models.Collections.WebhookLog)
|
||||
_, err := webhookLogCollection.CreateDocument(ctx, webhookLog)
|
||||
if err != nil {
|
||||
return nil, 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) {
|
||||
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 := driver.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
|
||||
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,
|
||||
WebhookLogs: webhookLogs,
|
||||
}, nil
|
||||
}
|
159
server/db/providers/cassandradb/email_template.go
Normal file
159
server/db/providers/cassandradb/email_template.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package cassandradb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddEmailTemplate to add EmailTemplate
|
||||
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, template, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.EmailTemplate, emailTemplate.ID, emailTemplate.EventName, 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) {
|
||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
||||
|
||||
bytes, err := json.Marshal(emailTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||
decoder.UseNumber()
|
||||
emailTemplateMap := map[string]interface{}{}
|
||||
err = decoder.Decode(&emailTemplateMap)
|
||||
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))
|
||||
} else {
|
||||
updateFields += fmt.Sprintf("%s = %v, ", key, value)
|
||||
}
|
||||
}
|
||||
updateFields = strings.Trim(updateFields, " ")
|
||||
updateFields = strings.TrimSuffix(updateFields, ",")
|
||||
|
||||
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.EmailTemplate, updateFields, emailTemplate.ID)
|
||||
err = p.db.Query(query).Exec()
|
||||
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) {
|
||||
emailTemplates := []*model.EmailTemplate{}
|
||||
paginationClone := pagination
|
||||
|
||||
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.EmailTemplate)
|
||||
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
|
||||
query := fmt.Sprintf("SELECT id, event_name, template, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.EmailTemplate, pagination.Limit+pagination.Offset)
|
||||
|
||||
scanner := p.db.Query(query).Iter().Scanner()
|
||||
counter := int64(0)
|
||||
for scanner.Next() {
|
||||
if counter >= pagination.Offset {
|
||||
var emailTemplate models.EmailTemplate
|
||||
err := scanner.Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate())
|
||||
}
|
||||
counter++
|
||||
}
|
||||
|
||||
return &model.EmailTemplates{
|
||||
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
|
||||
query := fmt.Sprintf(`SELECT id, event_name, template, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1`, KeySpace+"."+models.Collections.EmailTemplate, emailTemplateID)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt)
|
||||
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) {
|
||||
var emailTemplate models.EmailTemplate
|
||||
query := fmt.Sprintf(`SELECT id, event_name, template, created_at, updated_at FROM %s WHERE event_name = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.EmailTemplate, eventName)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// DeleteEmailTemplate to delete EmailTemplate
|
||||
func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error {
|
||||
query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.EmailTemplate, emailTemplate.ID)
|
||||
err := p.db.Query(query).Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package cassandradb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -10,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
// AddEnv to save environment information in database
|
||||
func (p *provider) AddEnv(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()
|
||||
}
|
||||
@@ -27,7 +28,7 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
|
||||
}
|
||||
|
||||
// UpdateEnv to update environment information in database
|
||||
func (p *provider) UpdateEnv(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)
|
||||
@@ -39,7 +40,7 @@ func (p *provider) UpdateEnv(env models.Env) (models.Env, error) {
|
||||
}
|
||||
|
||||
// GetEnv to get environment information from database
|
||||
func (p *provider) GetEnv() (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)
|
||||
|
@@ -5,11 +5,12 @@ import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/crypto"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/gocql/gocql"
|
||||
cansandraDriver "github.com/gocql/gocql"
|
||||
)
|
||||
@@ -23,15 +24,21 @@ var KeySpace string
|
||||
|
||||
// NewProvider to initialize arangodb connection
|
||||
func NewProvider() (*provider, error) {
|
||||
dbURL := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)
|
||||
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
||||
if dbURL == "" {
|
||||
dbURL = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseHost)
|
||||
if envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabasePort) != "" {
|
||||
dbURL = fmt.Sprintf("%s:%s", dbURL, envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabasePort))
|
||||
dbHost := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseHost
|
||||
dbPort := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePort
|
||||
if dbPort != "" && dbHost != "" {
|
||||
dbURL = fmt.Sprintf("%s:%s", dbHost, dbPort)
|
||||
} else if dbHost != "" {
|
||||
dbURL = dbHost
|
||||
}
|
||||
}
|
||||
|
||||
KeySpace = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseName)
|
||||
KeySpace = memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName
|
||||
if KeySpace == "" {
|
||||
KeySpace = constants.EnvKeyDatabaseName
|
||||
}
|
||||
clusterURL := []string{}
|
||||
if strings.Contains(dbURL, ",") {
|
||||
clusterURL = strings.Split(dbURL, ",")
|
||||
@@ -39,25 +46,31 @@ func NewProvider() (*provider, error) {
|
||||
clusterURL = append(clusterURL, dbURL)
|
||||
}
|
||||
cassandraClient := cansandraDriver.NewCluster(clusterURL...)
|
||||
if envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseUsername) != "" && envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabasePassword) != "" {
|
||||
dbUsername := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseUsername
|
||||
dbPassword := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePassword
|
||||
|
||||
if dbUsername != "" && dbPassword != "" {
|
||||
cassandraClient.Authenticator = &cansandraDriver.PasswordAuthenticator{
|
||||
Username: envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseUsername),
|
||||
Password: envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabasePassword),
|
||||
Username: dbUsername,
|
||||
Password: dbPassword,
|
||||
}
|
||||
}
|
||||
|
||||
if envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCert) != "" && envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCACert) != "" && envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCertKey) != "" {
|
||||
certString, err := crypto.DecryptB64(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCert))
|
||||
dbCert := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseCert
|
||||
dbCACert := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseCACert
|
||||
dbCertKey := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseCertKey
|
||||
if dbCert != "" && dbCACert != "" && dbCertKey != "" {
|
||||
certString, err := crypto.DecryptB64(dbCert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyString, err := crypto.DecryptB64(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCertKey))
|
||||
keyString, err := crypto.DecryptB64(dbCertKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
caString, err := crypto.DecryptB64(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCACert))
|
||||
caString, err := crypto.DecryptB64(dbCACert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -84,6 +97,8 @@ func NewProvider() (*provider, error) {
|
||||
NumRetries: 3,
|
||||
}
|
||||
cassandraClient.Consistency = gocql.LocalQuorum
|
||||
cassandraClient.ConnectTimeout = 10 * time.Second
|
||||
cassandraClient.ProtoVersion = 4
|
||||
|
||||
session, err := cassandraClient.CreateSession()
|
||||
if err != nil {
|
||||
@@ -128,6 +143,11 @@ func NewProvider() (*provider, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sessionIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_session_user_id ON %s.%s (user_id)", KeySpace, models.Collections.Session)
|
||||
err = session.Query(sessionIndexQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, email text, email_verified_at bigint, password text, signup_methods text, given_name text, family_name text, middle_name text, nickname text, gender text, birthdate text, phone_number text, phone_number_verified_at bigint, picture text, roles text, updated_at bigint, created_at bigint, revoked_timestamp bigint, PRIMARY KEY (id))", KeySpace, models.Collections.User)
|
||||
err = session.Query(userCollectionQuery).Exec()
|
||||
@@ -162,6 +182,39 @@ func NewProvider() (*provider, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
webhookCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, event_name text, endpoint text, enabled boolean, headers text, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.Webhook)
|
||||
err = session.Query(webhookCollectionQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhookIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_webhook_event_name ON %s.%s (event_name)", KeySpace, models.Collections.Webhook)
|
||||
err = session.Query(webhookIndexQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
webhookLogCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, http_status bigint, response text, request text, webhook_id text,updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.WebhookLog)
|
||||
err = session.Query(webhookLogCollectionQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhookLogIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_webhook_log_webhook_id ON %s.%s (webhook_id)", KeySpace, models.Collections.WebhookLog)
|
||||
err = session.Query(webhookLogIndexQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
emailTemplateCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, event_name text, template text, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.EmailTemplate)
|
||||
err = session.Query(emailTemplateCollectionQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
emailTemplateIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_email_template_event_name ON %s.%s (event_name)", KeySpace, models.Collections.EmailTemplate)
|
||||
err = session.Query(emailTemplateIndexQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &provider{
|
||||
db: session,
|
||||
}, err
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cassandradb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -9,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
// AddSession to save session information in database
|
||||
func (p *provider) AddSession(session models.Session) error {
|
||||
func (p *provider) AddSession(ctx context.Context, session models.Session) error {
|
||||
if session.ID == "" {
|
||||
session.ID = uuid.New().String()
|
||||
}
|
||||
@@ -24,13 +25,3 @@ func (p *provider) AddSession(session models.Session) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteSession to delete session information from database
|
||||
func (p *provider) DeleteSession(userId string) error {
|
||||
deleteSessionQuery := fmt.Sprintf("DELETE FROM %s WHERE user_id = '%s'", KeySpace+"."+models.Collections.Session, userId)
|
||||
err := p.db.Query(deleteSessionQuery).Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cassandradb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
@@ -9,20 +10,24 @@ import (
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddUser to save user information in database
|
||||
func (p *provider) AddUser(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 == "" {
|
||||
user.Roles = strings.Join(envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles), ",")
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
@@ -75,7 +80,7 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
|
||||
}
|
||||
|
||||
// UpdateUser to update user information in database
|
||||
func (p *provider) UpdateUser(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)
|
||||
@@ -93,10 +98,11 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) {
|
||||
|
||||
updateFields := ""
|
||||
for key, value := range userMap {
|
||||
if value != nil && key != "_id" {
|
||||
if key == "_id" {
|
||||
continue
|
||||
}
|
||||
|
||||
if key == "_id" {
|
||||
if key == "_key" {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -126,14 +132,36 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) {
|
||||
}
|
||||
|
||||
// DeleteUser to delete user information from database
|
||||
func (p *provider) DeleteUser(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 := ""
|
||||
for scanner.Next() {
|
||||
var wlID string
|
||||
err = scanner.Scan(&wlID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sessionIDs += fmt.Sprintf("'%s',", wlID)
|
||||
}
|
||||
sessionIDs = strings.TrimSuffix(sessionIDs, ",")
|
||||
deleteSessionQuery := fmt.Sprintf("DELETE FROM %s WHERE id IN (%s)", KeySpace+"."+models.Collections.Session, sessionIDs)
|
||||
err = p.db.Query(deleteSessionQuery).Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListUsers to get list of users from database
|
||||
func (p *provider) ListUsers(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)
|
||||
@@ -167,9 +195,9 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
|
||||
}
|
||||
|
||||
// GetUserByEmail to get user information from database using email address
|
||||
func (p *provider) GetUserByEmail(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, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1", KeySpace+"."+models.Collections.User, email)
|
||||
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, 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.CreatedAt, &user.UpdatedAt)
|
||||
if err != nil {
|
||||
return user, err
|
||||
@@ -178,7 +206,7 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
||||
}
|
||||
|
||||
// GetUserByID to get user information from database using user ID
|
||||
func (p *provider) GetUserByID(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, 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.CreatedAt, &user.UpdatedAt)
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cassandradb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -11,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
// AddVerification to save verification request in database
|
||||
func (p *provider) AddVerificationRequest(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()
|
||||
}
|
||||
@@ -28,7 +29,7 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
|
||||
}
|
||||
|
||||
// GetVerificationRequestByToken to get verification request from database using token
|
||||
func (p *provider) GetVerificationRequestByToken(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)
|
||||
|
||||
@@ -40,7 +41,7 @@ func (p *provider) GetVerificationRequestByToken(token string) (models.Verificat
|
||||
}
|
||||
|
||||
// GetVerificationRequestByEmail to get verification request by email from database
|
||||
func (p *provider) GetVerificationRequestByEmail(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)
|
||||
|
||||
@@ -53,7 +54,7 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
|
||||
}
|
||||
|
||||
// ListVerificationRequests to get list of verification requests from database
|
||||
func (p *provider) ListVerificationRequests(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
|
||||
@@ -89,7 +90,7 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
|
||||
}
|
||||
|
||||
// DeleteVerificationRequest to delete verification request from database
|
||||
func (p *provider) DeleteVerificationRequest(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 {
|
||||
|
172
server/db/providers/cassandradb/webhook.go
Normal file
172
server/db/providers/cassandradb/webhook.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package cassandradb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddWebhook to add webhook
|
||||
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
|
||||
webhook.CreatedAt = time.Now().Unix()
|
||||
webhook.UpdatedAt = time.Now().Unix()
|
||||
|
||||
existingHook, _ := p.GetWebhookByEventName(ctx, webhook.EventName)
|
||||
if existingHook != nil {
|
||||
return nil, fmt.Errorf("Webhook with %s event_name already exists", webhook.EventName)
|
||||
}
|
||||
|
||||
insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_name, endpoint, headers, enabled, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %t, %d, %d)", KeySpace+"."+models.Collections.Webhook, webhook.ID, webhook.EventName, webhook.EndPoint, webhook.Headers, webhook.Enabled, webhook.CreatedAt, webhook.UpdatedAt)
|
||||
err := p.db.Query(insertQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// UpdateWebhook to update webhook
|
||||
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
||||
webhook.UpdatedAt = time.Now().Unix()
|
||||
|
||||
bytes, err := json.Marshal(webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||
decoder.UseNumber()
|
||||
webhookMap := map[string]interface{}{}
|
||||
err = decoder.Decode(&webhookMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updateFields := ""
|
||||
for key, value := range webhookMap {
|
||||
if key == "_id" {
|
||||
continue
|
||||
}
|
||||
|
||||
if key == "_key" {
|
||||
continue
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
updateFields += fmt.Sprintf("%s = null,", key)
|
||||
continue
|
||||
}
|
||||
|
||||
valueType := reflect.TypeOf(value)
|
||||
if valueType.Name() == "string" {
|
||||
updateFields += fmt.Sprintf("%s = '%s', ", key, value.(string))
|
||||
} else {
|
||||
updateFields += fmt.Sprintf("%s = %v, ", key, value)
|
||||
}
|
||||
}
|
||||
updateFields = strings.Trim(updateFields, " ")
|
||||
updateFields = strings.TrimSuffix(updateFields, ",")
|
||||
|
||||
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Webhook, updateFields, webhook.ID)
|
||||
err = p.db.Query(query).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// ListWebhooks to list webhook
|
||||
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)
|
||||
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
|
||||
query := fmt.Sprintf("SELECT id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.Webhook, pagination.Limit+pagination.Offset)
|
||||
|
||||
scanner := p.db.Query(query).Iter().Scanner()
|
||||
counter := int64(0)
|
||||
for scanner.Next() {
|
||||
if counter >= pagination.Offset {
|
||||
var webhook models.Webhook
|
||||
err := scanner.Scan(&webhook.ID, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||
}
|
||||
counter++
|
||||
}
|
||||
|
||||
return &model.Webhooks{
|
||||
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
|
||||
query := fmt.Sprintf(`SELECT id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1`, KeySpace+"."+models.Collections.Webhook, webhookID)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&webhook.ID, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// GetWebhookByEventName to get webhook by event_name
|
||||
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
|
||||
var webhook models.Webhook
|
||||
query := fmt.Sprintf(`SELECT id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s WHERE event_name = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.Webhook, eventName)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&webhook.ID, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// DeleteWebhook to delete webhook
|
||||
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
||||
query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.Webhook, webhook.ID)
|
||||
err := p.db.Query(query).Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
getWebhookLogQuery := fmt.Sprintf("SELECT id FROM %s WHERE webhook_id = '%s' ALLOW FILTERING", KeySpace+"."+models.Collections.WebhookLog, webhook.ID)
|
||||
scanner := p.db.Query(getWebhookLogQuery).Iter().Scanner()
|
||||
webhookLogIDs := ""
|
||||
for scanner.Next() {
|
||||
var wlID string
|
||||
err = scanner.Scan(&wlID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
webhookLogIDs += fmt.Sprintf("'%s',", wlID)
|
||||
}
|
||||
webhookLogIDs = strings.TrimSuffix(webhookLogIDs, ",")
|
||||
query = fmt.Sprintf("DELETE FROM %s WHERE id IN (%s)", KeySpace+"."+models.Collections.WebhookLog, webhookLogIDs)
|
||||
err = p.db.Query(query).Exec()
|
||||
return err
|
||||
}
|
70
server/db/providers/cassandradb/webhook_log.go
Normal file
70
server/db/providers/cassandradb/webhook_log.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package cassandradb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddWebhookLog to add webhook log
|
||||
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()
|
||||
|
||||
insertQuery := fmt.Sprintf("INSERT INTO %s (id, http_status, response, request, webhook_id, created_at, updated_at) VALUES ('%s', %d,'%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.WebhookLog, webhookLog.ID, webhookLog.HttpStatus, webhookLog.Response, webhookLog.Request, webhookLog.WebhookID, webhookLog.CreatedAt, webhookLog.UpdatedAt)
|
||||
err := p.db.Query(insertQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, 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) {
|
||||
webhookLogs := []*model.WebhookLog{}
|
||||
paginationClone := pagination
|
||||
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.WebhookLog)
|
||||
// there is no offset in cassandra
|
||||
// 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)
|
||||
}
|
||||
|
||||
err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scanner := p.db.Query(query).Iter().Scanner()
|
||||
counter := int64(0)
|
||||
for scanner.Next() {
|
||||
if counter >= pagination.Offset {
|
||||
var webhookLog models.WebhookLog
|
||||
err := scanner.Scan(&webhookLog.ID, &webhookLog.HttpStatus, &webhookLog.Response, &webhookLog.Request, &webhookLog.WebhookID, &webhookLog.CreatedAt, &webhookLog.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
|
||||
}
|
||||
counter++
|
||||
}
|
||||
|
||||
return &model.WebhookLogs{
|
||||
Pagination: &paginationClone,
|
||||
WebhookLogs: webhookLogs,
|
||||
}, nil
|
||||
}
|
115
server/db/providers/mongodb/email_template.go
Normal file
115
server/db/providers/mongodb/email_template.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package mongodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// AddEmailTemplate to add EmailTemplate
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// UpdateEmailTemplate to update EmailTemplate
|
||||
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) {
|
||||
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
|
||||
err := cursor.Decode(&emailTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate())
|
||||
}
|
||||
|
||||
return &model.EmailTemplates{
|
||||
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
|
||||
emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection())
|
||||
err := emailTemplateCollection.FindOne(ctx, bson.M{"_id": emailTemplateID}).Decode(&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) {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// DeleteEmailTemplate to delete EmailTemplate
|
||||
func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error {
|
||||
emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection())
|
||||
_, err := emailTemplateCollection.DeleteOne(nil, bson.M{"_id": emailTemplate.ID}, options.Delete())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package mongodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -11,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
// AddEnv to save environment information in database
|
||||
func (p *provider) AddEnv(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,7 +21,7 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
|
||||
env.UpdatedAt = time.Now().Unix()
|
||||
env.Key = env.ID
|
||||
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||
_, err := configCollection.InsertOne(nil, env)
|
||||
_, err := configCollection.InsertOne(ctx, env)
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
@@ -28,10 +29,10 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
|
||||
}
|
||||
|
||||
// UpdateEnv to update environment information in database
|
||||
func (p *provider) UpdateEnv(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(nil, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions())
|
||||
_, err := configCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions())
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
@@ -39,14 +40,14 @@ func (p *provider) UpdateEnv(env models.Env) (models.Env, error) {
|
||||
}
|
||||
|
||||
// GetEnv to get environment information from database
|
||||
func (p *provider) GetEnv() (models.Env, error) {
|
||||
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(nil, bson.M{}, options.Find())
|
||||
cursor, err := configCollection.Find(ctx, bson.M{}, options.Find())
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
defer cursor.Close(nil)
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(nil) {
|
||||
err := cursor.Decode(&env)
|
||||
|
@@ -4,9 +4,8 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
@@ -19,7 +18,8 @@ type provider struct {
|
||||
|
||||
// NewProvider to initialize mongodb connection
|
||||
func NewProvider() (*provider, error) {
|
||||
mongodbOptions := options.Client().ApplyURI(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL))
|
||||
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
||||
mongodbOptions := options.Client().ApplyURI(dbURL)
|
||||
maxWait := time.Duration(5 * time.Second)
|
||||
mongodbOptions.ConnectTimeout = &maxWait
|
||||
mongoClient, err := mongo.NewClient(mongodbOptions)
|
||||
@@ -37,18 +37,19 @@ func NewProvider() (*provider, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mongodb := mongoClient.Database(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseName), options.Database())
|
||||
dbName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName
|
||||
mongodb := mongoClient.Database(dbName, options.Database())
|
||||
|
||||
mongodb.CreateCollection(ctx, models.Collections.User, options.CreateCollection())
|
||||
userCollection := mongodb.Collection(models.Collections.User, options.Collection())
|
||||
userCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.M{"email": 1},
|
||||
Options: options.Index().SetUnique(true).SetSparse(true),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
userCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.M{"phone_number": 1},
|
||||
Options: options.Index().SetUnique(true).SetSparse(true).SetPartialFilterExpression(map[string]interface{}{
|
||||
"phone_number": map[string]string{"$type": "string"},
|
||||
@@ -59,13 +60,13 @@ func NewProvider() (*provider, error) {
|
||||
mongodb.CreateCollection(ctx, models.Collections.VerificationRequest, options.CreateCollection())
|
||||
verificationRequestCollection := mongodb.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||
verificationRequestCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.M{"email": 1, "identifier": 1},
|
||||
Options: options.Index().SetUnique(true).SetSparse(true),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
verificationRequestCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.M{"token": 1},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
@@ -74,7 +75,7 @@ func NewProvider() (*provider, error) {
|
||||
mongodb.CreateCollection(ctx, models.Collections.Session, options.CreateCollection())
|
||||
sessionCollection := mongodb.Collection(models.Collections.Session, options.Collection())
|
||||
sessionCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.M{"user_id": 1},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
@@ -82,6 +83,33 @@ func NewProvider() (*provider, error) {
|
||||
|
||||
mongodb.CreateCollection(ctx, models.Collections.Env, options.CreateCollection())
|
||||
|
||||
mongodb.CreateCollection(ctx, models.Collections.Webhook, options.CreateCollection())
|
||||
webhookCollection := mongodb.Collection(models.Collections.Webhook, options.Collection())
|
||||
webhookCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.M{"event_name": 1},
|
||||
Options: options.Index().SetUnique(true).SetSparse(true),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
|
||||
mongodb.CreateCollection(ctx, models.Collections.WebhookLog, options.CreateCollection())
|
||||
webhookLogCollection := mongodb.Collection(models.Collections.WebhookLog, options.Collection())
|
||||
webhookLogCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.M{"webhook_id": 1},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
|
||||
mongodb.CreateCollection(ctx, models.Collections.EmailTemplate, options.CreateCollection())
|
||||
emailTemplateCollection := mongodb.Collection(models.Collections.EmailTemplate, options.Collection())
|
||||
emailTemplateCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.M{"event_name": 1},
|
||||
Options: options.Index().SetUnique(true).SetSparse(true),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
|
||||
return &provider{
|
||||
db: mongodb,
|
||||
}, nil
|
||||
|
@@ -1,16 +1,16 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// AddSession to save session information in database
|
||||
func (p *provider) AddSession(session models.Session) error {
|
||||
func (p *provider) AddSession(ctx context.Context, session models.Session) error {
|
||||
if session.ID == "" {
|
||||
session.ID = uuid.New().String()
|
||||
}
|
||||
@@ -19,17 +19,7 @@ func (p *provider) AddSession(session models.Session) error {
|
||||
session.CreatedAt = time.Now().Unix()
|
||||
session.UpdatedAt = time.Now().Unix()
|
||||
sessionCollection := p.db.Collection(models.Collections.Session, options.Collection())
|
||||
_, err := sessionCollection.InsertOne(nil, session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteSession to delete session information from database
|
||||
func (p *provider) DeleteSession(userId string) error {
|
||||
sessionCollection := p.db.Collection(models.Collections.Session, options.Collection())
|
||||
_, err := sessionCollection.DeleteMany(nil, bson.M{"user_id": userId}, options.Delete())
|
||||
_, err := sessionCollection.InsertOne(ctx, session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -1,32 +1,36 @@
|
||||
package mongodb
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/google/uuid"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// AddUser to save user information in database
|
||||
func (p *provider) AddUser(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 == "" {
|
||||
user.Roles = strings.Join(envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles), ",")
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
user.Key = user.ID
|
||||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||
_, err := userCollection.InsertOne(nil, user)
|
||||
_, err := userCollection.InsertOne(ctx, user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -35,10 +39,10 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
|
||||
}
|
||||
|
||||
// UpdateUser to update user information in database
|
||||
func (p *provider) UpdateUser(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(nil, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions())
|
||||
_, err := userCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions())
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -46,9 +50,15 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) {
|
||||
}
|
||||
|
||||
// DeleteUser to delete user information from database
|
||||
func (p *provider) DeleteUser(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(nil, bson.M{"_id": user.ID}, options.Delete())
|
||||
_, 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
|
||||
}
|
||||
@@ -57,7 +67,7 @@ func (p *provider) DeleteUser(user models.User) error {
|
||||
}
|
||||
|
||||
// ListUsers to get list of users from database
|
||||
func (p *provider) ListUsers(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)
|
||||
@@ -65,23 +75,22 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
|
||||
opts.SetSort(bson.M{"created_at": -1})
|
||||
|
||||
paginationClone := pagination
|
||||
// TODO add pagination total
|
||||
|
||||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||
count, err := userCollection.CountDocuments(nil, bson.M{}, options.Count())
|
||||
count, err := userCollection.CountDocuments(ctx, bson.M{}, options.Count())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
paginationClone.Total = count
|
||||
|
||||
cursor, err := userCollection.Find(nil, bson.M{}, opts)
|
||||
cursor, err := userCollection.Find(ctx, bson.M{}, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close(nil)
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(nil) {
|
||||
for cursor.Next(ctx) {
|
||||
var user models.User
|
||||
err := cursor.Decode(&user)
|
||||
if err != nil {
|
||||
@@ -97,10 +106,10 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
|
||||
}
|
||||
|
||||
// GetUserByEmail to get user information from database using email address
|
||||
func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
||||
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(nil, bson.M{"email": email}).Decode(&user)
|
||||
err := userCollection.FindOne(ctx, bson.M{"email": email}).Decode(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -109,11 +118,11 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
||||
}
|
||||
|
||||
// GetUserByID to get user information from database using user ID
|
||||
func (p *provider) GetUserByID(id string) (models.User, error) {
|
||||
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(nil, bson.M{"_id": id}).Decode(&user)
|
||||
err := userCollection.FindOne(ctx, bson.M{"_id": id}).Decode(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package mongodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
@@ -11,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
// AddVerification to save verification request in database
|
||||
func (p *provider) AddVerificationRequest(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()
|
||||
|
||||
@@ -19,7 +20,7 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
|
||||
verificationRequest.UpdatedAt = time.Now().Unix()
|
||||
verificationRequest.Key = verificationRequest.ID
|
||||
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||
_, err := verificationRequestCollection.InsertOne(nil, verificationRequest)
|
||||
_, err := verificationRequestCollection.InsertOne(ctx, verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
@@ -29,11 +30,11 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
|
||||
}
|
||||
|
||||
// GetVerificationRequestByToken to get verification request from database using token
|
||||
func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) {
|
||||
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(nil, bson.M{"token": token}).Decode(&verificationRequest)
|
||||
err := verificationRequestCollection.FindOne(ctx, bson.M{"token": token}).Decode(&verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
@@ -42,11 +43,11 @@ func (p *provider) GetVerificationRequestByToken(token string) (models.Verificat
|
||||
}
|
||||
|
||||
// GetVerificationRequestByEmail to get verification request by email from database
|
||||
func (p *provider) GetVerificationRequestByEmail(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
|
||||
|
||||
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||
err := verificationRequestCollection.FindOne(nil, bson.M{"email": email, "identifier": identifier}).Decode(&verificationRequest)
|
||||
err := verificationRequestCollection.FindOne(ctx, bson.M{"email": email, "identifier": identifier}).Decode(&verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
@@ -55,7 +56,7 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
|
||||
}
|
||||
|
||||
// ListVerificationRequests to get list of verification requests from database
|
||||
func (p *provider) ListVerificationRequests(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()
|
||||
@@ -65,17 +66,17 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
|
||||
|
||||
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||
|
||||
verificationRequestCollectionCount, err := verificationRequestCollection.CountDocuments(nil, bson.M{})
|
||||
verificationRequestCollectionCount, err := verificationRequestCollection.CountDocuments(ctx, bson.M{})
|
||||
paginationClone := pagination
|
||||
paginationClone.Total = verificationRequestCollectionCount
|
||||
|
||||
cursor, err := verificationRequestCollection.Find(nil, bson.M{}, opts)
|
||||
cursor, err := verificationRequestCollection.Find(ctx, bson.M{}, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close(nil)
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(nil) {
|
||||
for cursor.Next(ctx) {
|
||||
var verificationRequest models.VerificationRequest
|
||||
err := cursor.Decode(&verificationRequest)
|
||||
if err != nil {
|
||||
@@ -91,9 +92,9 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
|
||||
}
|
||||
|
||||
// DeleteVerificationRequest to delete verification request from database
|
||||
func (p *provider) DeleteVerificationRequest(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(nil, bson.M{"_id": verificationRequest.ID}, options.Delete())
|
||||
_, err := verificationRequestCollection.DeleteOne(ctx, bson.M{"_id": verificationRequest.ID}, options.Delete())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
120
server/db/providers/mongodb/webhook.go
Normal file
120
server/db/providers/mongodb/webhook.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package mongodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// AddWebhook to add webhook
|
||||
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
|
||||
webhook.CreatedAt = time.Now().Unix()
|
||||
webhook.UpdatedAt = time.Now().Unix()
|
||||
|
||||
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
||||
_, err := webhookCollection.InsertOne(ctx, webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// UpdateWebhook to update webhook
|
||||
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
||||
webhook.UpdatedAt = time.Now().Unix()
|
||||
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
||||
_, err := webhookCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": webhook.ID}}, bson.M{"$set": webhook}, options.MergeUpdateOptions())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// ListWebhooks to list webhook
|
||||
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
|
||||
var webhooks []*model.Webhook
|
||||
opts := options.Find()
|
||||
opts.SetLimit(pagination.Limit)
|
||||
opts.SetSkip(pagination.Offset)
|
||||
opts.SetSort(bson.M{"created_at": -1})
|
||||
|
||||
paginationClone := pagination
|
||||
|
||||
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
||||
count, err := webhookCollection.CountDocuments(ctx, bson.M{}, options.Count())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
paginationClone.Total = count
|
||||
|
||||
cursor, err := webhookCollection.Find(ctx, bson.M{}, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
var webhook models.Webhook
|
||||
err := cursor.Decode(&webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||
}
|
||||
|
||||
return &model.Webhooks{
|
||||
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
|
||||
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
||||
err := webhookCollection.FindOne(ctx, bson.M{"_id": webhookID}).Decode(&webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// GetWebhookByEventName to get webhook by event_name
|
||||
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
|
||||
var webhook models.Webhook
|
||||
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
||||
err := webhookCollection.FindOne(ctx, bson.M{"event_name": eventName}).Decode(&webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// DeleteWebhook to delete webhook
|
||||
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
||||
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
||||
_, err := webhookCollection.DeleteOne(nil, bson.M{"_id": webhook.ID}, options.Delete())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
webhookLogCollection := p.db.Collection(models.Collections.WebhookLog, options.Collection())
|
||||
_, err = webhookLogCollection.DeleteMany(nil, bson.M{"webhook_id": webhook.ID}, options.Delete())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
74
server/db/providers/mongodb/webhook_log.go
Normal file
74
server/db/providers/mongodb/webhook_log.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package mongodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// AddWebhookLog to add webhook log
|
||||
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()
|
||||
|
||||
webhookLogCollection := p.db.Collection(models.Collections.WebhookLog, options.Collection())
|
||||
_, err := webhookLogCollection.InsertOne(ctx, webhookLog)
|
||||
if err != nil {
|
||||
return nil, 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) {
|
||||
webhookLogs := []*model.WebhookLog{}
|
||||
opts := options.Find()
|
||||
opts.SetLimit(pagination.Limit)
|
||||
opts.SetSkip(pagination.Offset)
|
||||
opts.SetSort(bson.M{"created_at": -1})
|
||||
|
||||
paginationClone := pagination
|
||||
query := bson.M{}
|
||||
|
||||
if webhookID != "" {
|
||||
query = bson.M{"webhook_id": webhookID}
|
||||
}
|
||||
|
||||
webhookLogCollection := p.db.Collection(models.Collections.WebhookLog, options.Collection())
|
||||
count, err := webhookLogCollection.CountDocuments(ctx, query, options.Count())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
paginationClone.Total = count
|
||||
|
||||
cursor, err := webhookLogCollection.Find(ctx, query, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
var webhookLog models.WebhookLog
|
||||
err := cursor.Decode(&webhookLog)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
|
||||
}
|
||||
|
||||
return &model.WebhookLogs{
|
||||
Pagination: &paginationClone,
|
||||
WebhookLogs: webhookLogs,
|
||||
}, nil
|
||||
}
|
48
server/db/providers/provider_template/email_template.go
Normal file
48
server/db/providers/provider_template/email_template.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package provider_template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddEmailTemplate to add EmailTemplate
|
||||
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()
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// UpdateEmailTemplate to update EmailTemplate
|
||||
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) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetEmailTemplateByID to get EmailTemplate by id
|
||||
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
||||
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// DeleteEmailTemplate to delete EmailTemplate
|
||||
func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error {
|
||||
return nil
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package provider_template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
@@ -8,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
// AddEnv to save environment information in database
|
||||
func (p *provider) AddEnv(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,13 +20,13 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
|
||||
}
|
||||
|
||||
// UpdateEnv to update environment information in database
|
||||
func (p *provider) UpdateEnv(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() (models.Env, error) {
|
||||
func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
|
||||
var env models.Env
|
||||
|
||||
return env, nil
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package provider_template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
@@ -8,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
// AddSession to save session information in database
|
||||
func (p *provider) AddSession(session models.Session) error {
|
||||
func (p *provider) AddSession(ctx context.Context, session models.Session) error {
|
||||
if session.ID == "" {
|
||||
session.ID = uuid.New().String()
|
||||
}
|
||||
@@ -19,6 +20,6 @@ func (p *provider) AddSession(session models.Session) error {
|
||||
}
|
||||
|
||||
// DeleteSession to delete session information from database
|
||||
func (p *provider) DeleteSession(userId string) error {
|
||||
func (p *provider) DeleteSession(ctx context.Context, userId string) error {
|
||||
return nil
|
||||
}
|
||||
|
@@ -1,24 +1,28 @@
|
||||
package provider_template
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddUser to save user information in database
|
||||
func (p *provider) AddUser(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 == "" {
|
||||
user.Roles = strings.Join(envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles), ",")
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
@@ -28,30 +32,30 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
|
||||
}
|
||||
|
||||
// UpdateUser to update user information in database
|
||||
func (p *provider) UpdateUser(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(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(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(email string) (models.User, error) {
|
||||
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(id string) (models.User, error) {
|
||||
func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
|
||||
var user models.User
|
||||
|
||||
return user, nil
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package provider_template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
@@ -9,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
// AddVerification to save verification request in database
|
||||
func (p *provider) AddVerificationRequest(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()
|
||||
}
|
||||
@@ -21,25 +22,25 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
|
||||
}
|
||||
|
||||
// GetVerificationRequestByToken to get verification request from database using token
|
||||
func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) {
|
||||
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(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
|
||||
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
||||
// ListVerificationRequests to get list of verification requests from database
|
||||
func (p *provider) ListVerificationRequests(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(verificationRequest models.VerificationRequest) error {
|
||||
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
49
server/db/providers/provider_template/webhook.go
Normal file
49
server/db/providers/provider_template/webhook.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package provider_template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddWebhook to add webhook
|
||||
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
|
||||
webhook.CreatedAt = time.Now().Unix()
|
||||
webhook.UpdatedAt = time.Now().Unix()
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// UpdateWebhook to update webhook
|
||||
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
||||
webhook.UpdatedAt = time.Now().Unix()
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// ListWebhooks to list webhook
|
||||
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetWebhookByID to get webhook by id
|
||||
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetWebhookByEventName to get webhook by event_name
|
||||
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// DeleteWebhook to delete webhook
|
||||
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
||||
// Also delete webhook logs for given webhook id
|
||||
return nil
|
||||
}
|
27
server/db/providers/provider_template/webhook_log.go
Normal file
27
server/db/providers/provider_template/webhook_log.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package provider_template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddWebhookLog to add webhook log
|
||||
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()
|
||||
return webhookLog.AsAPIWebhookLog(), nil
|
||||
}
|
||||
|
||||
// ListWebhookLogs to list webhook logs
|
||||
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
|
||||
return nil, nil
|
||||
}
|
@@ -1,44 +1,75 @@
|
||||
package providers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
)
|
||||
|
||||
type Provider interface {
|
||||
// AddUser to save user information in database
|
||||
AddUser(user models.User) (models.User, error)
|
||||
AddUser(ctx context.Context, user models.User) (models.User, error)
|
||||
// UpdateUser to update user information in database
|
||||
UpdateUser(user models.User) (models.User, error)
|
||||
UpdateUser(ctx context.Context, user models.User) (models.User, error)
|
||||
// DeleteUser to delete user information from database
|
||||
DeleteUser(user models.User) error
|
||||
DeleteUser(ctx context.Context, user models.User) error
|
||||
// ListUsers to get list of users from database
|
||||
ListUsers(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(email string) (models.User, error)
|
||||
GetUserByEmail(ctx context.Context, email string) (models.User, error)
|
||||
// GetUserByID to get user information from database using user ID
|
||||
GetUserByID(id string) (models.User, error)
|
||||
GetUserByID(ctx context.Context, id string) (models.User, error)
|
||||
|
||||
// AddVerification to save verification request in database
|
||||
AddVerificationRequest(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(token string) (models.VerificationRequest, error)
|
||||
GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error)
|
||||
// GetVerificationRequestByEmail to get verification request by email from database
|
||||
GetVerificationRequestByEmail(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(pagination model.Pagination) (*model.VerificationRequests, error)
|
||||
ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error)
|
||||
// DeleteVerificationRequest to delete verification request from database
|
||||
DeleteVerificationRequest(verificationRequest models.VerificationRequest) error
|
||||
DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error
|
||||
|
||||
// AddSession to save session information in database
|
||||
AddSession(session models.Session) error
|
||||
// DeleteSession to delete session information from database
|
||||
DeleteSession(userId string) error
|
||||
AddSession(ctx context.Context, session models.Session) error
|
||||
|
||||
// AddEnv to save environment information in database
|
||||
AddEnv(env models.Env) (models.Env, error)
|
||||
AddEnv(ctx context.Context, env models.Env) (models.Env, error)
|
||||
// UpdateEnv to update environment information in database
|
||||
UpdateEnv(env models.Env) (models.Env, error)
|
||||
UpdateEnv(ctx context.Context, env models.Env) (models.Env, error)
|
||||
// GetEnv to get environment information from database
|
||||
GetEnv() (models.Env, error)
|
||||
GetEnv(ctx context.Context) (models.Env, error)
|
||||
|
||||
// AddWebhook to add webhook
|
||||
AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error)
|
||||
// UpdateWebhook to update webhook
|
||||
UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error)
|
||||
// ListWebhooks to list webhook
|
||||
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
|
||||
GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error)
|
||||
// DeleteWebhook to delete webhook
|
||||
DeleteWebhook(ctx context.Context, webhook *model.Webhook) error
|
||||
|
||||
// AddWebhookLog to add webhook log
|
||||
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)
|
||||
|
||||
// AddEmailTemplate to add EmailTemplate
|
||||
AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error)
|
||||
// UpdateEmailTemplate to update EmailTemplate
|
||||
UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error)
|
||||
// ListEmailTemplates to list EmailTemplate
|
||||
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
|
||||
GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error)
|
||||
// DeleteEmailTemplate to delete EmailTemplate
|
||||
DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error
|
||||
}
|
||||
|
100
server/db/providers/sql/email_template.go
Normal file
100
server/db/providers/sql/email_template.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddEmailTemplate to add EmailTemplate
|
||||
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()
|
||||
|
||||
res := p.db.Create(&emailTemplate)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// UpdateEmailTemplate to update EmailTemplate
|
||||
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
||||
|
||||
res := p.db.Save(&emailTemplate)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// ListEmailTemplates to list 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
|
||||
}
|
||||
|
||||
var total int64
|
||||
totalRes := p.db.Model(&models.EmailTemplate{}).Count(&total)
|
||||
if totalRes.Error != nil {
|
||||
return nil, totalRes.Error
|
||||
}
|
||||
|
||||
paginationClone := pagination
|
||||
paginationClone.Total = total
|
||||
|
||||
responseEmailTemplates := []*model.EmailTemplate{}
|
||||
for _, w := range emailTemplates {
|
||||
responseEmailTemplates = append(responseEmailTemplates, w.AsAPIEmailTemplate())
|
||||
}
|
||||
return &model.EmailTemplates{
|
||||
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
|
||||
|
||||
result := p.db.Where("id = ?", emailTemplateID).First(&emailTemplate)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
||||
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
||||
var emailTemplate models.EmailTemplate
|
||||
|
||||
result := p.db.Where("event_name = ?", eventName).First(&emailTemplate)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// DeleteEmailTemplate to delete EmailTemplate
|
||||
func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error {
|
||||
result := p.db.Delete(&models.EmailTemplate{
|
||||
ID: emailTemplate.ID,
|
||||
})
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
@@ -8,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
// AddEnv to save environment information in database
|
||||
func (p *provider) AddEnv(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()
|
||||
}
|
||||
@@ -25,7 +26,7 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
|
||||
}
|
||||
|
||||
// UpdateEnv to update environment information in database
|
||||
func (p *provider) UpdateEnv(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)
|
||||
|
||||
@@ -36,7 +37,7 @@ func (p *provider) UpdateEnv(env models.Env) (models.Env, error) {
|
||||
}
|
||||
|
||||
// GetEnv to get environment information from database
|
||||
func (p *provider) GetEnv() (models.Env, error) {
|
||||
func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
|
||||
var env models.Env
|
||||
result := p.db.First(&env)
|
||||
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/driver/sqlite"
|
||||
@@ -41,22 +41,26 @@ func NewProvider() (*provider, error) {
|
||||
TablePrefix: models.Prefix,
|
||||
},
|
||||
}
|
||||
switch envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) {
|
||||
case constants.DbTypePostgres, constants.DbTypeYugabyte:
|
||||
sqlDB, err = gorm.Open(postgres.Open(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
||||
|
||||
dbType := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseType
|
||||
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
||||
|
||||
switch dbType {
|
||||
case constants.DbTypePostgres, constants.DbTypeYugabyte, constants.DbTypeCockroachDB:
|
||||
sqlDB, err = gorm.Open(postgres.Open(dbURL), ormConfig)
|
||||
case constants.DbTypeSqlite:
|
||||
sqlDB, err = gorm.Open(sqlite.Open(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
||||
case constants.DbTypeMysql, constants.DbTypeMariaDB:
|
||||
sqlDB, err = gorm.Open(mysql.Open(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
||||
sqlDB, err = gorm.Open(sqlite.Open(dbURL), ormConfig)
|
||||
case constants.DbTypeMysql, constants.DbTypeMariaDB, constants.DbTypePlanetScaleDB:
|
||||
sqlDB, err = gorm.Open(mysql.Open(dbURL), ormConfig)
|
||||
case constants.DbTypeSqlserver:
|
||||
sqlDB, err = gorm.Open(sqlserver.Open(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
||||
sqlDB, err = gorm.Open(sqlserver.Open(dbURL), ormConfig)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{})
|
||||
err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}, &models.Webhook{}, models.WebhookLog{}, models.EmailTemplate{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
@@ -9,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
// AddSession to save session information in database
|
||||
func (p *provider) AddSession(session models.Session) error {
|
||||
func (p *provider) AddSession(ctx context.Context, session models.Session) error {
|
||||
if session.ID == "" {
|
||||
session.ID = uuid.New().String()
|
||||
}
|
||||
@@ -26,13 +27,3 @@ func (p *provider) AddSession(session models.Session) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteSession to delete session information from database
|
||||
func (p *provider) DeleteSession(userId string) error {
|
||||
result := p.db.Where("user_id = ?", userId).Delete(&models.Session{})
|
||||
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -1,25 +1,29 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// AddUser to save user information in database
|
||||
func (p *provider) AddUser(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 == "" {
|
||||
user.Roles = strings.Join(envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles), ",")
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
@@ -39,7 +43,7 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
|
||||
}
|
||||
|
||||
// UpdateUser to update user information in database
|
||||
func (p *provider) UpdateUser(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)
|
||||
@@ -52,18 +56,23 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) {
|
||||
}
|
||||
|
||||
// DeleteUser to delete user information from database
|
||||
func (p *provider) DeleteUser(user models.User) error {
|
||||
func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
||||
result := p.db.Delete(&user)
|
||||
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
result = p.db.Where("user_id = ?", user.ID).Delete(&models.Session{})
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListUsers to get list of users from database
|
||||
func (p *provider) ListUsers(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 {
|
||||
@@ -91,10 +100,9 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
|
||||
}
|
||||
|
||||
// GetUserByEmail to get user information from database using email address
|
||||
func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
||||
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
|
||||
}
|
||||
@@ -103,11 +111,10 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
||||
}
|
||||
|
||||
// GetUserByID to get user information from database using user ID
|
||||
func (p *provider) GetUserByID(id string) (models.User, error) {
|
||||
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
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
@@ -10,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
// AddVerification to save verification request in database
|
||||
func (p *provider) AddVerificationRequest(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()
|
||||
}
|
||||
@@ -31,7 +32,7 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
|
||||
}
|
||||
|
||||
// GetVerificationRequestByToken to get verification request from database using token
|
||||
func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) {
|
||||
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
|
||||
var verificationRequest models.VerificationRequest
|
||||
result := p.db.Where("token = ?", token).First(&verificationRequest)
|
||||
|
||||
@@ -43,7 +44,7 @@ func (p *provider) GetVerificationRequestByToken(token string) (models.Verificat
|
||||
}
|
||||
|
||||
// GetVerificationRequestByEmail to get verification request by email from database
|
||||
func (p *provider) GetVerificationRequestByEmail(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
|
||||
|
||||
result := p.db.Where("email = ? AND identifier = ?", email, identifier).First(&verificationRequest)
|
||||
@@ -56,7 +57,7 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
|
||||
}
|
||||
|
||||
// ListVerificationRequests to get list of verification requests from database
|
||||
func (p *provider) ListVerificationRequests(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)
|
||||
@@ -85,7 +86,7 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
|
||||
}
|
||||
|
||||
// DeleteVerificationRequest to delete verification request from database
|
||||
func (p *provider) DeleteVerificationRequest(verificationRequest models.VerificationRequest) error {
|
||||
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
||||
result := p.db.Delete(&verificationRequest)
|
||||
|
||||
if result.Error != nil {
|
||||
|
104
server/db/providers/sql/webhook.go
Normal file
104
server/db/providers/sql/webhook.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddWebhook to add webhook
|
||||
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
|
||||
webhook.CreatedAt = time.Now().Unix()
|
||||
webhook.UpdatedAt = time.Now().Unix()
|
||||
res := p.db.Create(&webhook)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// UpdateWebhook to update webhook
|
||||
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
||||
webhook.UpdatedAt = time.Now().Unix()
|
||||
|
||||
result := p.db.Save(&webhook)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// ListWebhooks to list webhook
|
||||
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 {
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
var total int64
|
||||
totalRes := p.db.Model(&models.Webhook{}).Count(&total)
|
||||
if totalRes.Error != nil {
|
||||
return nil, totalRes.Error
|
||||
}
|
||||
|
||||
paginationClone := pagination
|
||||
paginationClone.Total = total
|
||||
|
||||
responseWebhooks := []*model.Webhook{}
|
||||
for _, w := range webhooks {
|
||||
responseWebhooks = append(responseWebhooks, w.AsAPIWebhook())
|
||||
}
|
||||
return &model.Webhooks{
|
||||
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
|
||||
|
||||
result := p.db.Where("id = ?", webhookID).First(&webhook)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// GetWebhookByEventName to get webhook by event_name
|
||||
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
|
||||
var webhook models.Webhook
|
||||
|
||||
result := p.db.Where("event_name = ?", eventName).First(&webhook)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
||||
// DeleteWebhook to delete webhook
|
||||
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
||||
result := p.db.Delete(&models.Webhook{
|
||||
ID: webhook.ID,
|
||||
})
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
result = p.db.Where("webhook_id = ?", webhook.ID).Delete(&models.WebhookLog{})
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
return nil
|
||||
}
|
68
server/db/providers/sql/webhook_log.go
Normal file
68
server/db/providers/sql/webhook_log.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// AddWebhookLog to add webhook log
|
||||
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()
|
||||
res := p.db.Clauses(
|
||||
clause.OnConflict{
|
||||
DoNothing: true,
|
||||
}).Create(&webhookLog)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
|
||||
return webhookLog.AsAPIWebhookLog(), nil
|
||||
}
|
||||
|
||||
// ListWebhookLogs to list webhook logs
|
||||
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
|
||||
var total int64
|
||||
|
||||
if webhookID != "" {
|
||||
result = p.db.Where("webhook_id = ?", webhookID).Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&webhookLogs)
|
||||
totalRes = p.db.Where("webhook_id = ?", webhookID).Model(&models.WebhookLog{}).Count(&total)
|
||||
} else {
|
||||
result = p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&webhookLogs)
|
||||
totalRes = p.db.Model(&models.WebhookLog{}).Count(&total)
|
||||
}
|
||||
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
if totalRes.Error != nil {
|
||||
return nil, totalRes.Error
|
||||
}
|
||||
|
||||
paginationClone := pagination
|
||||
paginationClone.Total = total
|
||||
|
||||
responseWebhookLogs := []*model.WebhookLog{}
|
||||
for _, w := range webhookLogs {
|
||||
responseWebhookLogs = append(responseWebhookLogs, w.AsAPIWebhookLog())
|
||||
}
|
||||
return &model.WebhookLogs{
|
||||
WebhookLogs: responseWebhookLogs,
|
||||
Pagination: &paginationClone,
|
||||
}, nil
|
||||
}
|
@@ -11,7 +11,7 @@ import (
|
||||
gomail "gopkg.in/mail.v2"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
)
|
||||
|
||||
// addEmailTemplate is used to add html template in email body
|
||||
@@ -33,17 +33,57 @@ func addEmailTemplate(a string, b map[string]interface{}, templateName string) s
|
||||
// SendMail function to send mail
|
||||
func SendMail(to []string, Subject, bodyMessage string) error {
|
||||
// dont trigger email sending in case of test
|
||||
if envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyEnv) == "test" {
|
||||
envKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if envKey == constants.TestEnv {
|
||||
return nil
|
||||
}
|
||||
m := gomail.NewMessage()
|
||||
m.SetHeader("From", envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeySenderEmail))
|
||||
senderEmail, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySenderEmail)
|
||||
if err != nil {
|
||||
log.Errorf("Error while getting sender email from env variable: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
smtpPort, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySmtpPort)
|
||||
if err != nil {
|
||||
log.Errorf("Error while getting smtp port from env variable: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
smtpHost, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySmtpHost)
|
||||
if err != nil {
|
||||
log.Errorf("Error while getting smtp host from env variable: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
smtpUsername, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySmtpUsername)
|
||||
if err != nil {
|
||||
log.Errorf("Error while getting smtp username from env variable: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
smtpPassword, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySmtpPassword)
|
||||
if err != nil {
|
||||
log.Errorf("Error while getting smtp password from env variable: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
isProd, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsProd)
|
||||
if err != nil {
|
||||
log.Errorf("Error while getting env variable: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
m.SetHeader("From", senderEmail)
|
||||
m.SetHeader("To", to...)
|
||||
m.SetHeader("Subject", Subject)
|
||||
m.SetBody("text/html", bodyMessage)
|
||||
port, _ := strconv.Atoi(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeySmtpPort))
|
||||
d := gomail.NewDialer(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeySmtpHost), port, envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeySmtpUsername), envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeySmtpPassword))
|
||||
if envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyEnv) == "development" {
|
||||
port, _ := strconv.Atoi(smtpPort)
|
||||
d := gomail.NewDialer(smtpHost, port, smtpUsername, smtpPassword)
|
||||
if !isProd {
|
||||
d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
if err := d.DialAndSend(m); err != nil {
|
||||
|
@@ -2,14 +2,19 @@ package email
|
||||
|
||||
import (
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
)
|
||||
|
||||
// SendForgotPasswordMail to send forgot password email
|
||||
func SendForgotPasswordMail(toEmail, token, hostname string) error {
|
||||
resetPasswordUrl := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL)
|
||||
resetPasswordUrl, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resetPasswordUrl == "" {
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyResetPasswordURL, hostname+"/app/reset-password")
|
||||
if err := memorystore.Provider.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, hostname+"/app/reset-password"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// The receiver needs to be in slice as the receive supports multiple receiver
|
||||
@@ -103,8 +108,14 @@ func SendForgotPasswordMail(toEmail, token, hostname string) error {
|
||||
`
|
||||
|
||||
data := make(map[string]interface{}, 3)
|
||||
data["org_logo"] = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
||||
data["org_name"] = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
||||
data["org_logo"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data["org_name"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data["verification_url"] = resetPasswordUrl + "?token=" + token
|
||||
message = addEmailTemplate(message, data, "reset_password_email.tmpl")
|
||||
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
)
|
||||
|
||||
// InviteEmail to send invite email
|
||||
@@ -70,7 +70,7 @@ func InviteEmail(toEmail, token, verificationURL, redirectURI string) error {
|
||||
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
|
||||
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
|
||||
<p>Hi there 👋</p>
|
||||
<p>Join us! You are invited to sign-up for <b>{{.org_name}}</b>. Please accept the invitation by clicking the clicking the button below.</p> <br/>
|
||||
<p>Join us! You are invited to sign-up for <b>{{.org_name}}</b>. Please accept the invitation by clicking the button below.</p> <br/>
|
||||
<a
|
||||
clicktracking="off" href="{{.verification_url}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Get Started</a>
|
||||
</td>
|
||||
@@ -99,13 +99,20 @@ func InviteEmail(toEmail, token, verificationURL, redirectURI string) error {
|
||||
</html>
|
||||
`
|
||||
data := make(map[string]interface{}, 3)
|
||||
data["org_logo"] = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
||||
data["org_name"] = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
||||
var err error
|
||||
data["org_logo"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data["org_name"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data["verification_url"] = verificationURL + "?token=" + token + "&redirect_uri=" + redirectURI
|
||||
message = addEmailTemplate(message, data, "invite_email.tmpl")
|
||||
// bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
|
||||
|
||||
err := SendMail(Receiver, Subject, message)
|
||||
err = SendMail(Receiver, Subject, message)
|
||||
if err != nil {
|
||||
log.Warn("error sending email: ", err)
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
)
|
||||
|
||||
// SendVerificationMail to send verification email
|
||||
@@ -99,13 +99,20 @@ func SendVerificationMail(toEmail, token, hostname string) error {
|
||||
</html>
|
||||
`
|
||||
data := make(map[string]interface{}, 3)
|
||||
data["org_logo"] = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
||||
data["org_name"] = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
||||
var err error
|
||||
data["org_logo"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data["org_name"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data["verification_url"] = hostname + "/verify_email?token=" + token
|
||||
message = addEmailTemplate(message, data, "verify_email.tmpl")
|
||||
// bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
|
||||
|
||||
err := SendMail(Receiver, Subject, message)
|
||||
err = SendMail(Receiver, Subject, message)
|
||||
if err != nil {
|
||||
log.Warn("error sending email: ", err)
|
||||
}
|
||||
|
687
server/env/env.go
vendored
687
server/env/env.go
vendored
@@ -2,212 +2,247 @@ package env
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/joho/godotenv"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/crypto"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
)
|
||||
|
||||
// InitRequiredEnv to initialize EnvData and through error if required env are not present
|
||||
func InitRequiredEnv() error {
|
||||
envPath := os.Getenv(constants.EnvKeyEnvPath)
|
||||
|
||||
if envPath == "" {
|
||||
envPath = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyEnvPath)
|
||||
if envPath == "" {
|
||||
envPath = `.env`
|
||||
}
|
||||
}
|
||||
|
||||
if envstore.ARG_ENV_FILE != nil && *envstore.ARG_ENV_FILE != "" {
|
||||
envPath = *envstore.ARG_ENV_FILE
|
||||
}
|
||||
log.Info("env path: ", envPath)
|
||||
|
||||
err := godotenv.Load(envPath)
|
||||
if err != nil {
|
||||
log.Info("using OS env instead of %s file", envPath)
|
||||
}
|
||||
|
||||
dbURL := os.Getenv(constants.EnvKeyDatabaseURL)
|
||||
dbType := os.Getenv(constants.EnvKeyDatabaseType)
|
||||
dbName := os.Getenv(constants.EnvKeyDatabaseName)
|
||||
dbPort := os.Getenv(constants.EnvKeyDatabasePort)
|
||||
dbHost := os.Getenv(constants.EnvKeyDatabaseHost)
|
||||
dbUsername := os.Getenv(constants.EnvKeyDatabaseUsername)
|
||||
dbPassword := os.Getenv(constants.EnvKeyDatabasePassword)
|
||||
dbCert := os.Getenv(constants.EnvKeyDatabaseCert)
|
||||
dbCertKey := os.Getenv(constants.EnvKeyDatabaseCertKey)
|
||||
dbCACert := os.Getenv(constants.EnvKeyDatabaseCACert)
|
||||
|
||||
if strings.TrimSpace(dbType) == "" {
|
||||
if envstore.ARG_DB_TYPE != nil && *envstore.ARG_DB_TYPE != "" {
|
||||
dbType = strings.TrimSpace(*envstore.ARG_DB_TYPE)
|
||||
}
|
||||
|
||||
if dbType == "" {
|
||||
log.Debug("DATABASE_TYPE is not set")
|
||||
return errors.New("invalid database type. DATABASE_TYPE is empty")
|
||||
}
|
||||
}
|
||||
|
||||
if strings.TrimSpace(dbURL) == "" && envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL) == "" {
|
||||
if envstore.ARG_DB_URL != nil && *envstore.ARG_DB_URL != "" {
|
||||
dbURL = strings.TrimSpace(*envstore.ARG_DB_URL)
|
||||
}
|
||||
|
||||
if dbURL == "" && dbPort == "" && dbHost == "" && dbUsername == "" && dbPassword == "" {
|
||||
log.Debug("DATABASE_URL is not set")
|
||||
return errors.New("invalid database url. DATABASE_URL is required")
|
||||
}
|
||||
}
|
||||
|
||||
if dbName == "" {
|
||||
if dbName == "" {
|
||||
dbName = "authorizer"
|
||||
}
|
||||
}
|
||||
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyEnvPath, envPath)
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseURL, dbURL)
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseType, dbType)
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseName, dbName)
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseHost, dbHost)
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabasePort, dbPort)
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseUsername, dbUsername)
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabasePassword, dbPassword)
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseCert, dbCert)
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseCertKey, dbCertKey)
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseCACert, dbCACert)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitEnv to initialize EnvData and through error if required env are not present
|
||||
func InitAllEnv() error {
|
||||
envData, err := GetEnvData()
|
||||
if err != nil {
|
||||
log.Info("No env data found in db, using local clone of env data")
|
||||
// get clone of current store
|
||||
envData = envstore.EnvStoreObj.GetEnvStoreClone()
|
||||
envData, err = memorystore.Provider.GetEnvStore()
|
||||
if err != nil {
|
||||
log.Debug("Error while getting env data from memorystore: ", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
clientID := envData.StringEnv[constants.EnvKeyClientID]
|
||||
// unique client id for each instance
|
||||
if clientID == "" {
|
||||
cid, ok := envData[constants.EnvKeyClientID]
|
||||
clientID := ""
|
||||
if !ok || cid == "" {
|
||||
clientID = uuid.New().String()
|
||||
envData.StringEnv[constants.EnvKeyClientID] = clientID
|
||||
}
|
||||
|
||||
clientSecret := envData.StringEnv[constants.EnvKeyClientSecret]
|
||||
// unique client id for each instance
|
||||
if clientSecret == "" {
|
||||
clientSecret = uuid.New().String()
|
||||
envData.StringEnv[constants.EnvKeyClientSecret] = clientSecret
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyEnv] == "" {
|
||||
envData.StringEnv[constants.EnvKeyEnv] = os.Getenv(constants.EnvKeyEnv)
|
||||
if envData.StringEnv[constants.EnvKeyEnv] == "" {
|
||||
envData.StringEnv[constants.EnvKeyEnv] = "production"
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyEnv] == "production" {
|
||||
envData.BoolEnv[constants.EnvKeyIsProd] = true
|
||||
envData[constants.EnvKeyClientID] = clientID
|
||||
} else {
|
||||
envData.BoolEnv[constants.EnvKeyIsProd] = false
|
||||
}
|
||||
clientID = cid.(string)
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyAppURL] == "" {
|
||||
envData.StringEnv[constants.EnvKeyAppURL] = os.Getenv(constants.EnvKeyAppURL)
|
||||
// unique client secret for each instance
|
||||
if val, ok := envData[constants.EnvKeyClientSecret]; !ok || val != "" {
|
||||
envData[constants.EnvKeyClientSecret] = uuid.New().String()
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyAuthorizerURL] == "" {
|
||||
envData.StringEnv[constants.EnvKeyAuthorizerURL] = os.Getenv(constants.EnvKeyAuthorizerURL)
|
||||
// os string envs
|
||||
osEnv := os.Getenv(constants.EnvKeyEnv)
|
||||
osAppURL := os.Getenv(constants.EnvKeyAppURL)
|
||||
osAuthorizerURL := os.Getenv(constants.EnvKeyAuthorizerURL)
|
||||
osPort := os.Getenv(constants.EnvKeyPort)
|
||||
osAccessTokenExpiryTime := os.Getenv(constants.EnvKeyAccessTokenExpiryTime)
|
||||
osAdminSecret := os.Getenv(constants.EnvKeyAdminSecret)
|
||||
osSmtpHost := os.Getenv(constants.EnvKeySmtpHost)
|
||||
osSmtpPort := os.Getenv(constants.EnvKeySmtpPort)
|
||||
osSmtpUsername := os.Getenv(constants.EnvKeySmtpUsername)
|
||||
osSmtpPassword := os.Getenv(constants.EnvKeySmtpPassword)
|
||||
osSenderEmail := os.Getenv(constants.EnvKeySenderEmail)
|
||||
osJwtType := os.Getenv(constants.EnvKeyJwtType)
|
||||
osJwtSecret := os.Getenv(constants.EnvKeyJwtSecret)
|
||||
osJwtPrivateKey := os.Getenv(constants.EnvKeyJwtPrivateKey)
|
||||
osJwtPublicKey := os.Getenv(constants.EnvKeyJwtPublicKey)
|
||||
osJwtRoleClaim := os.Getenv(constants.EnvKeyJwtRoleClaim)
|
||||
osCustomAccessTokenScript := os.Getenv(constants.EnvKeyCustomAccessTokenScript)
|
||||
osGoogleClientID := os.Getenv(constants.EnvKeyGoogleClientID)
|
||||
osGoogleClientSecret := os.Getenv(constants.EnvKeyGoogleClientSecret)
|
||||
osGithubClientID := os.Getenv(constants.EnvKeyGithubClientID)
|
||||
osGithubClientSecret := os.Getenv(constants.EnvKeyGithubClientSecret)
|
||||
osFacebookClientID := os.Getenv(constants.EnvKeyFacebookClientID)
|
||||
osFacebookClientSecret := os.Getenv(constants.EnvKeyFacebookClientSecret)
|
||||
osLinkedInClientID := os.Getenv(constants.EnvKeyLinkedInClientID)
|
||||
osLinkedInClientSecret := os.Getenv(constants.EnvKeyLinkedInClientSecret)
|
||||
osAppleClientID := os.Getenv(constants.EnvKeyAppleClientID)
|
||||
osAppleClientSecret := os.Getenv(constants.EnvKeyAppleClientSecret)
|
||||
osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL)
|
||||
osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName)
|
||||
osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo)
|
||||
|
||||
// os bool vars
|
||||
osDisableBasicAuthentication := os.Getenv(constants.EnvKeyDisableBasicAuthentication)
|
||||
osDisableEmailVerification := os.Getenv(constants.EnvKeyDisableEmailVerification)
|
||||
osDisableMagicLinkLogin := os.Getenv(constants.EnvKeyDisableMagicLinkLogin)
|
||||
osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage)
|
||||
osDisableSignUp := os.Getenv(constants.EnvKeyDisableSignUp)
|
||||
osDisableRedisForEnv := os.Getenv(constants.EnvKeyDisableRedisForEnv)
|
||||
osDisableStrongPassword := os.Getenv(constants.EnvKeyDisableStrongPassword)
|
||||
|
||||
// os slice vars
|
||||
osAllowedOrigins := os.Getenv(constants.EnvKeyAllowedOrigins)
|
||||
osRoles := os.Getenv(constants.EnvKeyRoles)
|
||||
osDefaultRoles := os.Getenv(constants.EnvKeyDefaultRoles)
|
||||
osProtectedRoles := os.Getenv(constants.EnvKeyProtectedRoles)
|
||||
|
||||
ienv, ok := envData[constants.EnvKeyEnv]
|
||||
if !ok || ienv == "" {
|
||||
envData[constants.EnvKeyEnv] = osEnv
|
||||
if envData[constants.EnvKeyEnv] == "" {
|
||||
envData[constants.EnvKeyEnv] = "production"
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyPort] == "" {
|
||||
envData.StringEnv[constants.EnvKeyPort] = os.Getenv(constants.EnvKeyPort)
|
||||
if envData.StringEnv[constants.EnvKeyPort] == "" {
|
||||
envData.StringEnv[constants.EnvKeyPort] = "8080"
|
||||
}
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyAccessTokenExpiryTime] == "" {
|
||||
envData.StringEnv[constants.EnvKeyAccessTokenExpiryTime] = os.Getenv(constants.EnvKeyAccessTokenExpiryTime)
|
||||
if envData.StringEnv[constants.EnvKeyAccessTokenExpiryTime] == "" {
|
||||
envData.StringEnv[constants.EnvKeyAccessTokenExpiryTime] = "30m"
|
||||
}
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyAdminSecret] == "" {
|
||||
envData.StringEnv[constants.EnvKeyAdminSecret] = os.Getenv(constants.EnvKeyAdminSecret)
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeySmtpHost] == "" {
|
||||
envData.StringEnv[constants.EnvKeySmtpHost] = os.Getenv(constants.EnvKeySmtpHost)
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeySmtpPort] == "" {
|
||||
envData.StringEnv[constants.EnvKeySmtpPort] = os.Getenv(constants.EnvKeySmtpPort)
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeySmtpUsername] == "" {
|
||||
envData.StringEnv[constants.EnvKeySmtpUsername] = os.Getenv(constants.EnvKeySmtpUsername)
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeySmtpPassword] == "" {
|
||||
envData.StringEnv[constants.EnvKeySmtpPassword] = os.Getenv(constants.EnvKeySmtpPassword)
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeySenderEmail] == "" {
|
||||
envData.StringEnv[constants.EnvKeySenderEmail] = os.Getenv(constants.EnvKeySenderEmail)
|
||||
}
|
||||
|
||||
algo := envData.StringEnv[constants.EnvKeyJwtType]
|
||||
if algo == "" {
|
||||
envData.StringEnv[constants.EnvKeyJwtType] = os.Getenv(constants.EnvKeyJwtType)
|
||||
if envData.StringEnv[constants.EnvKeyJwtType] == "" {
|
||||
envData.StringEnv[constants.EnvKeyJwtType] = "RS256"
|
||||
algo = envData.StringEnv[constants.EnvKeyJwtType]
|
||||
if envData[constants.EnvKeyEnv] == "production" {
|
||||
envData[constants.EnvKeyIsProd] = true
|
||||
} else {
|
||||
algo = envData.StringEnv[constants.EnvKeyJwtType]
|
||||
envData[constants.EnvKeyIsProd] = false
|
||||
}
|
||||
}
|
||||
if osEnv != "" && osEnv != envData[constants.EnvKeyEnv] {
|
||||
envData[constants.EnvKeyEnv] = osEnv
|
||||
if envData[constants.EnvKeyEnv] == "production" {
|
||||
envData[constants.EnvKeyIsProd] = true
|
||||
} else {
|
||||
envData[constants.EnvKeyIsProd] = false
|
||||
}
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyAppURL]; !ok || val == "" {
|
||||
envData[constants.EnvKeyAppURL] = osAppURL
|
||||
}
|
||||
if osAppURL != "" && envData[constants.EnvKeyAppURL] != osAppURL {
|
||||
envData[constants.EnvKeyAppURL] = osAppURL
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyAuthorizerURL]; !ok || val == "" {
|
||||
envData[constants.EnvKeyAuthorizerURL] = osAuthorizerURL
|
||||
}
|
||||
if osAuthorizerURL != "" && envData[constants.EnvKeyAuthorizerURL] != osAuthorizerURL {
|
||||
envData[constants.EnvKeyAuthorizerURL] = osAuthorizerURL
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyPort]; !ok || val == "" {
|
||||
envData[constants.EnvKeyPort] = osPort
|
||||
if envData[constants.EnvKeyPort] == "" {
|
||||
envData[constants.EnvKeyPort] = "8080"
|
||||
}
|
||||
}
|
||||
if osPort != "" && envData[constants.EnvKeyPort] != osPort {
|
||||
envData[constants.EnvKeyPort] = osPort
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyAccessTokenExpiryTime]; !ok || val == "" {
|
||||
envData[constants.EnvKeyAccessTokenExpiryTime] = osAccessTokenExpiryTime
|
||||
if envData[constants.EnvKeyAccessTokenExpiryTime] == "" {
|
||||
envData[constants.EnvKeyAccessTokenExpiryTime] = "30m"
|
||||
}
|
||||
}
|
||||
if osAccessTokenExpiryTime != "" && envData[constants.EnvKeyAccessTokenExpiryTime] != osAccessTokenExpiryTime {
|
||||
envData[constants.EnvKeyAccessTokenExpiryTime] = osAccessTokenExpiryTime
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyAdminSecret]; !ok || val == "" {
|
||||
envData[constants.EnvKeyAdminSecret] = osAdminSecret
|
||||
}
|
||||
if osAdminSecret != "" && envData[constants.EnvKeyAdminSecret] != osAdminSecret {
|
||||
envData[constants.EnvKeyAdminSecret] = osAdminSecret
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeySmtpHost]; !ok || val == "" {
|
||||
envData[constants.EnvKeySmtpHost] = osSmtpHost
|
||||
}
|
||||
if osSmtpHost != "" && envData[constants.EnvKeySmtpHost] != osSmtpHost {
|
||||
envData[constants.EnvKeySmtpHost] = osSmtpHost
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeySmtpPort]; !ok || val == "" {
|
||||
envData[constants.EnvKeySmtpPort] = osSmtpPort
|
||||
}
|
||||
if osSmtpPort != "" && envData[constants.EnvKeySmtpPort] != osSmtpPort {
|
||||
envData[constants.EnvKeySmtpPort] = osSmtpPort
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeySmtpUsername]; !ok || val == "" {
|
||||
envData[constants.EnvKeySmtpUsername] = osSmtpUsername
|
||||
}
|
||||
if osSmtpUsername != "" && envData[constants.EnvKeySmtpUsername] != osSmtpUsername {
|
||||
envData[constants.EnvKeySmtpUsername] = osSmtpUsername
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeySmtpPassword]; !ok || val == "" {
|
||||
envData[constants.EnvKeySmtpPassword] = osSmtpPassword
|
||||
}
|
||||
if osSmtpPassword != "" && envData[constants.EnvKeySmtpPassword] != osSmtpPassword {
|
||||
envData[constants.EnvKeySmtpPassword] = osSmtpPassword
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeySenderEmail]; !ok || val == "" {
|
||||
envData[constants.EnvKeySenderEmail] = osSenderEmail
|
||||
}
|
||||
if osSenderEmail != "" && envData[constants.EnvKeySenderEmail] != osSenderEmail {
|
||||
envData[constants.EnvKeySenderEmail] = osSenderEmail
|
||||
}
|
||||
|
||||
algoVal, ok := envData[constants.EnvKeyJwtType]
|
||||
algo := ""
|
||||
if !ok || algoVal == "" {
|
||||
envData[constants.EnvKeyJwtType] = osJwtType
|
||||
if envData[constants.EnvKeyJwtType] == "" {
|
||||
envData[constants.EnvKeyJwtType] = "RS256"
|
||||
algo = envData[constants.EnvKeyJwtType].(string)
|
||||
}
|
||||
} else {
|
||||
algo = algoVal.(string)
|
||||
if !crypto.IsHMACA(algo) && !crypto.IsRSA(algo) && !crypto.IsECDSA(algo) {
|
||||
log.Debug("Invalid JWT Algorithm")
|
||||
return errors.New("invalid JWT_TYPE")
|
||||
}
|
||||
}
|
||||
if osJwtType != "" && osJwtType != algo {
|
||||
if !crypto.IsHMACA(osJwtType) && !crypto.IsRSA(osJwtType) && !crypto.IsECDSA(osJwtType) {
|
||||
log.Debug("Invalid JWT Algorithm")
|
||||
return errors.New("invalid JWT_TYPE")
|
||||
}
|
||||
algo = osJwtType
|
||||
envData[constants.EnvKeyJwtType] = osJwtType
|
||||
}
|
||||
|
||||
if crypto.IsHMACA(algo) {
|
||||
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" {
|
||||
envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv(constants.EnvKeyJwtSecret)
|
||||
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" {
|
||||
envData.StringEnv[constants.EnvKeyJwtSecret], _, err = crypto.NewHMACKey(algo, clientID)
|
||||
if val, ok := envData[constants.EnvKeyJwtSecret]; !ok || val == "" {
|
||||
envData[constants.EnvKeyJwtSecret] = osJwtSecret
|
||||
if envData[constants.EnvKeyJwtSecret] == "" {
|
||||
envData[constants.EnvKeyJwtSecret], _, err = crypto.NewHMACKey(algo, clientID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if osJwtSecret != "" && envData[constants.EnvKeyJwtSecret] != osJwtSecret {
|
||||
envData[constants.EnvKeyJwtSecret] = osJwtSecret
|
||||
}
|
||||
}
|
||||
|
||||
if crypto.IsRSA(algo) || crypto.IsECDSA(algo) {
|
||||
privateKey, publicKey := "", ""
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyJwtPrivateKey] == "" {
|
||||
privateKey = os.Getenv(constants.EnvKeyJwtPrivateKey)
|
||||
if val, ok := envData[constants.EnvKeyJwtPrivateKey]; !ok || val == "" {
|
||||
privateKey = osJwtPrivateKey
|
||||
}
|
||||
if osJwtPrivateKey != "" && privateKey != osJwtPrivateKey {
|
||||
privateKey = osJwtPrivateKey
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyJwtPublicKey] == "" {
|
||||
publicKey = os.Getenv(constants.EnvKeyJwtPublicKey)
|
||||
if val, ok := envData[constants.EnvKeyJwtPublicKey]; !ok || val == "" {
|
||||
publicKey = osJwtPublicKey
|
||||
}
|
||||
if osJwtPublicKey != "" && publicKey != osJwtPublicKey {
|
||||
publicKey = osJwtPublicKey
|
||||
}
|
||||
|
||||
// if algo is RSA / ECDSA, then we need to have both private and public key
|
||||
@@ -250,159 +285,273 @@ func InitAllEnv() error {
|
||||
}
|
||||
}
|
||||
|
||||
envData.StringEnv[constants.EnvKeyJwtPrivateKey] = privateKey
|
||||
envData.StringEnv[constants.EnvKeyJwtPublicKey] = publicKey
|
||||
envData[constants.EnvKeyJwtPrivateKey] = privateKey
|
||||
envData[constants.EnvKeyJwtPublicKey] = publicKey
|
||||
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyJwtRoleClaim] == "" {
|
||||
envData.StringEnv[constants.EnvKeyJwtRoleClaim] = os.Getenv(constants.EnvKeyJwtRoleClaim)
|
||||
if val, ok := envData[constants.EnvKeyJwtRoleClaim]; !ok || val == "" {
|
||||
envData[constants.EnvKeyJwtRoleClaim] = osJwtRoleClaim
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyJwtRoleClaim] == "" {
|
||||
envData.StringEnv[constants.EnvKeyJwtRoleClaim] = "role"
|
||||
if envData[constants.EnvKeyJwtRoleClaim] == "" {
|
||||
envData[constants.EnvKeyJwtRoleClaim] = "role"
|
||||
}
|
||||
}
|
||||
if osJwtRoleClaim != "" && envData[constants.EnvKeyJwtRoleClaim] != osJwtRoleClaim {
|
||||
envData[constants.EnvKeyJwtRoleClaim] = osJwtRoleClaim
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyCustomAccessTokenScript]; !ok || val == "" {
|
||||
envData[constants.EnvKeyCustomAccessTokenScript] = osCustomAccessTokenScript
|
||||
}
|
||||
if osCustomAccessTokenScript != "" && envData[constants.EnvKeyCustomAccessTokenScript] != osCustomAccessTokenScript {
|
||||
envData[constants.EnvKeyCustomAccessTokenScript] = osCustomAccessTokenScript
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyGoogleClientID]; !ok || val == "" {
|
||||
envData[constants.EnvKeyGoogleClientID] = osGoogleClientID
|
||||
}
|
||||
if osGoogleClientID != "" && envData[constants.EnvKeyGoogleClientID] != osGoogleClientID {
|
||||
envData[constants.EnvKeyGoogleClientID] = osGoogleClientID
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyGoogleClientSecret]; !ok || val == "" {
|
||||
envData[constants.EnvKeyGoogleClientSecret] = osGoogleClientSecret
|
||||
}
|
||||
if osGoogleClientSecret != "" && envData[constants.EnvKeyGoogleClientSecret] != osGoogleClientSecret {
|
||||
envData[constants.EnvKeyGoogleClientSecret] = osGoogleClientSecret
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyGithubClientID]; !ok || val == "" {
|
||||
envData[constants.EnvKeyGithubClientID] = osGithubClientID
|
||||
}
|
||||
if osGithubClientID != "" && envData[constants.EnvKeyGithubClientID] != osGithubClientID {
|
||||
envData[constants.EnvKeyGithubClientID] = osGithubClientID
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyGithubClientSecret]; !ok || val == "" {
|
||||
envData[constants.EnvKeyGithubClientSecret] = osGithubClientSecret
|
||||
}
|
||||
if osGithubClientSecret != "" && envData[constants.EnvKeyGithubClientSecret] != osGithubClientSecret {
|
||||
envData[constants.EnvKeyGithubClientSecret] = osGithubClientSecret
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyFacebookClientID]; !ok || val == "" {
|
||||
envData[constants.EnvKeyFacebookClientID] = osFacebookClientID
|
||||
}
|
||||
if osFacebookClientID != "" && envData[constants.EnvKeyFacebookClientID] != osFacebookClientID {
|
||||
envData[constants.EnvKeyFacebookClientID] = osFacebookClientID
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyFacebookClientSecret]; !ok || val == "" {
|
||||
envData[constants.EnvKeyFacebookClientSecret] = osFacebookClientSecret
|
||||
}
|
||||
if osFacebookClientSecret != "" && envData[constants.EnvKeyFacebookClientSecret] != osFacebookClientSecret {
|
||||
envData[constants.EnvKeyFacebookClientSecret] = osFacebookClientSecret
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyLinkedInClientID]; !ok || val == "" {
|
||||
envData[constants.EnvKeyLinkedInClientID] = osLinkedInClientID
|
||||
}
|
||||
if osFacebookClientID != "" && envData[constants.EnvKeyLinkedInClientID] != osFacebookClientID {
|
||||
envData[constants.EnvKeyLinkedInClientID] = osLinkedInClientID
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyLinkedInClientSecret]; !ok || val == "" {
|
||||
envData[constants.EnvKeyLinkedInClientSecret] = osLinkedInClientSecret
|
||||
}
|
||||
if osFacebookClientSecret != "" && envData[constants.EnvKeyLinkedInClientSecret] != osFacebookClientSecret {
|
||||
envData[constants.EnvKeyLinkedInClientSecret] = osLinkedInClientSecret
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyAppleClientID]; !ok || val == "" {
|
||||
envData[constants.EnvKeyAppleClientID] = osAppleClientID
|
||||
}
|
||||
if osFacebookClientID != "" && envData[constants.EnvKeyAppleClientID] != osFacebookClientID {
|
||||
envData[constants.EnvKeyAppleClientID] = osAppleClientID
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyAppleClientSecret]; !ok || val == "" {
|
||||
envData[constants.EnvKeyAppleClientSecret] = osAppleClientSecret
|
||||
}
|
||||
if osFacebookClientSecret != "" && envData[constants.EnvKeyAppleClientSecret] != osFacebookClientSecret {
|
||||
envData[constants.EnvKeyAppleClientSecret] = osAppleClientSecret
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" {
|
||||
envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/")
|
||||
}
|
||||
if osResetPasswordURL != "" && envData[constants.EnvKeyResetPasswordURL] != osResetPasswordURL {
|
||||
envData[constants.EnvKeyResetPasswordURL] = osResetPasswordURL
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyOrganizationName]; !ok || val == "" {
|
||||
envData[constants.EnvKeyOrganizationName] = osOrganizationName
|
||||
}
|
||||
if osOrganizationName != "" && envData[constants.EnvKeyOrganizationName] != osOrganizationName {
|
||||
envData[constants.EnvKeyOrganizationName] = osOrganizationName
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyOrganizationLogo]; !ok || val == "" {
|
||||
envData[constants.EnvKeyOrganizationLogo] = osOrganizationLogo
|
||||
}
|
||||
if osOrganizationLogo != "" && envData[constants.EnvKeyOrganizationLogo] != osOrganizationLogo {
|
||||
envData[constants.EnvKeyOrganizationLogo] = osOrganizationLogo
|
||||
}
|
||||
|
||||
if _, ok := envData[constants.EnvKeyDisableBasicAuthentication]; !ok {
|
||||
envData[constants.EnvKeyDisableBasicAuthentication] = osDisableBasicAuthentication == "true"
|
||||
}
|
||||
if osDisableBasicAuthentication != "" {
|
||||
boolValue, err := strconv.ParseBool(osDisableBasicAuthentication)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if boolValue != envData[constants.EnvKeyDisableBasicAuthentication].(bool) {
|
||||
envData[constants.EnvKeyDisableBasicAuthentication] = boolValue
|
||||
}
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyCustomAccessTokenScript] == "" {
|
||||
envData.StringEnv[constants.EnvKeyCustomAccessTokenScript] = os.Getenv(constants.EnvKeyCustomAccessTokenScript)
|
||||
if _, ok := envData[constants.EnvKeyDisableEmailVerification]; !ok {
|
||||
envData[constants.EnvKeyDisableEmailVerification] = osDisableEmailVerification == "true"
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyRedisURL] == "" {
|
||||
envData.StringEnv[constants.EnvKeyRedisURL] = os.Getenv(constants.EnvKeyRedisURL)
|
||||
if osDisableEmailVerification != "" {
|
||||
boolValue, err := strconv.ParseBool(osDisableEmailVerification)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyCookieName] == "" {
|
||||
envData.StringEnv[constants.EnvKeyCookieName] = os.Getenv(constants.EnvKeyCookieName)
|
||||
if envData.StringEnv[constants.EnvKeyCookieName] == "" {
|
||||
envData.StringEnv[constants.EnvKeyCookieName] = "authorizer"
|
||||
if boolValue != envData[constants.EnvKeyDisableEmailVerification].(bool) {
|
||||
envData[constants.EnvKeyDisableEmailVerification] = boolValue
|
||||
}
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyGoogleClientID] == "" {
|
||||
envData.StringEnv[constants.EnvKeyGoogleClientID] = os.Getenv(constants.EnvKeyGoogleClientID)
|
||||
if _, ok := envData[constants.EnvKeyDisableMagicLinkLogin]; !ok {
|
||||
envData[constants.EnvKeyDisableMagicLinkLogin] = osDisableMagicLinkLogin == "true"
|
||||
}
|
||||
if osDisableMagicLinkLogin != "" {
|
||||
boolValue, err := strconv.ParseBool(osDisableMagicLinkLogin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if boolValue != envData[constants.EnvKeyDisableMagicLinkLogin].(bool) {
|
||||
envData[constants.EnvKeyDisableMagicLinkLogin] = boolValue
|
||||
}
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyGoogleClientSecret] == "" {
|
||||
envData.StringEnv[constants.EnvKeyGoogleClientSecret] = os.Getenv(constants.EnvKeyGoogleClientSecret)
|
||||
if _, ok := envData[constants.EnvKeyDisableLoginPage]; !ok {
|
||||
envData[constants.EnvKeyDisableLoginPage] = osDisableLoginPage == "true"
|
||||
}
|
||||
if osDisableLoginPage != "" {
|
||||
boolValue, err := strconv.ParseBool(osDisableLoginPage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if boolValue != envData[constants.EnvKeyDisableLoginPage].(bool) {
|
||||
envData[constants.EnvKeyDisableLoginPage] = boolValue
|
||||
}
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyGithubClientID] == "" {
|
||||
envData.StringEnv[constants.EnvKeyGithubClientID] = os.Getenv(constants.EnvKeyGithubClientID)
|
||||
if _, ok := envData[constants.EnvKeyDisableSignUp]; !ok {
|
||||
envData[constants.EnvKeyDisableSignUp] = osDisableSignUp == "true"
|
||||
}
|
||||
if osDisableSignUp != "" {
|
||||
boolValue, err := strconv.ParseBool(osDisableSignUp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if boolValue != envData[constants.EnvKeyDisableSignUp].(bool) {
|
||||
envData[constants.EnvKeyDisableSignUp] = boolValue
|
||||
}
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyGithubClientSecret] == "" {
|
||||
envData.StringEnv[constants.EnvKeyGithubClientSecret] = os.Getenv(constants.EnvKeyGithubClientSecret)
|
||||
if _, ok := envData[constants.EnvKeyDisableRedisForEnv]; !ok {
|
||||
envData[constants.EnvKeyDisableRedisForEnv] = osDisableRedisForEnv == "true"
|
||||
}
|
||||
if osDisableRedisForEnv != "" {
|
||||
boolValue, err := strconv.ParseBool(osDisableRedisForEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if boolValue != envData[constants.EnvKeyDisableRedisForEnv].(bool) {
|
||||
envData[constants.EnvKeyDisableRedisForEnv] = boolValue
|
||||
}
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyFacebookClientID] == "" {
|
||||
envData.StringEnv[constants.EnvKeyFacebookClientID] = os.Getenv(constants.EnvKeyFacebookClientID)
|
||||
if _, ok := envData[constants.EnvKeyDisableStrongPassword]; !ok {
|
||||
envData[constants.EnvKeyDisableStrongPassword] = osDisableStrongPassword == "true"
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyFacebookClientSecret] == "" {
|
||||
envData.StringEnv[constants.EnvKeyFacebookClientSecret] = os.Getenv(constants.EnvKeyFacebookClientSecret)
|
||||
if osDisableStrongPassword != "" {
|
||||
boolValue, err := strconv.ParseBool(osDisableStrongPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if boolValue != envData[constants.EnvKeyDisableStrongPassword].(bool) {
|
||||
envData[constants.EnvKeyDisableStrongPassword] = boolValue
|
||||
}
|
||||
|
||||
if envData.StringEnv[constants.EnvKeyResetPasswordURL] == "" {
|
||||
envData.StringEnv[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(os.Getenv(constants.EnvKeyResetPasswordURL), "/")
|
||||
}
|
||||
|
||||
envData.BoolEnv[constants.EnvKeyDisableBasicAuthentication] = os.Getenv(constants.EnvKeyDisableBasicAuthentication) == "true"
|
||||
envData.BoolEnv[constants.EnvKeyDisableEmailVerification] = os.Getenv(constants.EnvKeyDisableEmailVerification) == "true"
|
||||
envData.BoolEnv[constants.EnvKeyDisableMagicLinkLogin] = os.Getenv(constants.EnvKeyDisableMagicLinkLogin) == "true"
|
||||
envData.BoolEnv[constants.EnvKeyDisableLoginPage] = os.Getenv(constants.EnvKeyDisableLoginPage) == "true"
|
||||
envData.BoolEnv[constants.EnvKeyDisableSignUp] = os.Getenv(constants.EnvKeyDisableSignUp) == "true"
|
||||
|
||||
// no need to add nil check as its already done above
|
||||
if envData.StringEnv[constants.EnvKeySmtpHost] == "" || envData.StringEnv[constants.EnvKeySmtpUsername] == "" || envData.StringEnv[constants.EnvKeySmtpPassword] == "" || envData.StringEnv[constants.EnvKeySenderEmail] == "" && envData.StringEnv[constants.EnvKeySmtpPort] == "" {
|
||||
envData.BoolEnv[constants.EnvKeyDisableEmailVerification] = true
|
||||
envData.BoolEnv[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||
if envData[constants.EnvKeySmtpHost] == "" || envData[constants.EnvKeySmtpUsername] == "" || envData[constants.EnvKeySmtpPassword] == "" || envData[constants.EnvKeySenderEmail] == "" && envData[constants.EnvKeySmtpPort] == "" {
|
||||
envData[constants.EnvKeyDisableEmailVerification] = true
|
||||
envData[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||
}
|
||||
|
||||
if envData.BoolEnv[constants.EnvKeyDisableEmailVerification] {
|
||||
envData.BoolEnv[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||
if envData[constants.EnvKeyDisableEmailVerification].(bool) {
|
||||
envData[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||
}
|
||||
|
||||
allowedOriginsSplit := strings.Split(os.Getenv(constants.EnvKeyAllowedOrigins), ",")
|
||||
allowedOrigins := []string{}
|
||||
hasWildCard := false
|
||||
|
||||
for _, val := range allowedOriginsSplit {
|
||||
trimVal := strings.TrimSpace(val)
|
||||
if trimVal != "" {
|
||||
if trimVal != "*" {
|
||||
host, port := utils.GetHostParts(trimVal)
|
||||
allowedOrigins = append(allowedOrigins, host+":"+port)
|
||||
} else {
|
||||
hasWildCard = true
|
||||
allowedOrigins = append(allowedOrigins, trimVal)
|
||||
break
|
||||
if val, ok := envData[constants.EnvKeyAllowedOrigins]; !ok || val == "" {
|
||||
envData[constants.EnvKeyAllowedOrigins] = osAllowedOrigins
|
||||
if envData[constants.EnvKeyAllowedOrigins] == "" {
|
||||
envData[constants.EnvKeyAllowedOrigins] = "*"
|
||||
}
|
||||
}
|
||||
if osAllowedOrigins != "" && envData[constants.EnvKeyAllowedOrigins] != osAllowedOrigins {
|
||||
envData[constants.EnvKeyAllowedOrigins] = osAllowedOrigins
|
||||
}
|
||||
|
||||
if len(allowedOrigins) > 1 && hasWildCard {
|
||||
allowedOrigins = []string{"*"}
|
||||
if val, ok := envData[constants.EnvKeyRoles]; !ok || val == "" {
|
||||
envData[constants.EnvKeyRoles] = osRoles
|
||||
if envData[constants.EnvKeyRoles] == "" {
|
||||
envData[constants.EnvKeyRoles] = "user"
|
||||
}
|
||||
}
|
||||
if osRoles != "" && envData[constants.EnvKeyRoles] != osRoles {
|
||||
envData[constants.EnvKeyRoles] = osRoles
|
||||
}
|
||||
roles := strings.Split(envData[constants.EnvKeyRoles].(string), ",")
|
||||
|
||||
if val, ok := envData[constants.EnvKeyDefaultRoles]; !ok || val == "" {
|
||||
envData[constants.EnvKeyDefaultRoles] = osDefaultRoles
|
||||
if envData[constants.EnvKeyDefaultRoles] == "" {
|
||||
envData[constants.EnvKeyDefaultRoles] = "user"
|
||||
}
|
||||
}
|
||||
if osDefaultRoles != "" && envData[constants.EnvKeyDefaultRoles] != osDefaultRoles {
|
||||
envData[constants.EnvKeyDefaultRoles] = osDefaultRoles
|
||||
}
|
||||
defaultRoles := strings.Split(envData[constants.EnvKeyDefaultRoles].(string), ",")
|
||||
if len(defaultRoles) == 0 {
|
||||
defaultRoles = []string{roles[0]}
|
||||
}
|
||||
|
||||
if len(allowedOrigins) == 0 {
|
||||
allowedOrigins = []string{"*"}
|
||||
}
|
||||
|
||||
envData.SliceEnv[constants.EnvKeyAllowedOrigins] = allowedOrigins
|
||||
|
||||
rolesEnv := strings.TrimSpace(os.Getenv(constants.EnvKeyRoles))
|
||||
rolesSplit := strings.Split(rolesEnv, ",")
|
||||
roles := []string{}
|
||||
if len(rolesEnv) == 0 {
|
||||
roles = []string{"user"}
|
||||
}
|
||||
|
||||
defaultRolesEnv := strings.TrimSpace(os.Getenv(constants.EnvKeyDefaultRoles))
|
||||
defaultRoleSplit := strings.Split(defaultRolesEnv, ",")
|
||||
defaultRoles := []string{}
|
||||
|
||||
if len(defaultRolesEnv) == 0 {
|
||||
defaultRoles = []string{"user"}
|
||||
}
|
||||
|
||||
protectedRolesEnv := strings.TrimSpace(os.Getenv(constants.EnvKeyProtectedRoles))
|
||||
protectedRolesSplit := strings.Split(protectedRolesEnv, ",")
|
||||
protectedRoles := []string{}
|
||||
|
||||
if len(protectedRolesEnv) > 0 {
|
||||
for _, val := range protectedRolesSplit {
|
||||
trimVal := strings.TrimSpace(val)
|
||||
protectedRoles = append(protectedRoles, trimVal)
|
||||
for _, role := range defaultRoles {
|
||||
if !utils.StringSliceContains(roles, role) {
|
||||
return fmt.Errorf("Default role %s is not defined in roles", role)
|
||||
}
|
||||
}
|
||||
|
||||
for _, val := range rolesSplit {
|
||||
trimVal := strings.TrimSpace(val)
|
||||
if trimVal != "" {
|
||||
roles = append(roles, trimVal)
|
||||
if utils.StringSliceContains(defaultRoleSplit, trimVal) {
|
||||
defaultRoles = append(defaultRoles, trimVal)
|
||||
}
|
||||
if val, ok := envData[constants.EnvKeyProtectedRoles]; !ok || val == "" {
|
||||
envData[constants.EnvKeyProtectedRoles] = osProtectedRoles
|
||||
}
|
||||
if osProtectedRoles != "" && envData[constants.EnvKeyProtectedRoles] != osProtectedRoles {
|
||||
envData[constants.EnvKeyProtectedRoles] = osProtectedRoles
|
||||
}
|
||||
|
||||
if len(roles) > 0 && len(defaultRoles) == 0 && len(defaultRolesEnv) > 0 {
|
||||
log.Debug("Default roles not found in roles list. It can be one from ROLES only")
|
||||
return errors.New(`invalid DEFAULT_ROLE environment variable. It can be one from give ROLES environment variable value`)
|
||||
err = memorystore.Provider.UpdateEnvStore(envData)
|
||||
if err != nil {
|
||||
log.Debug("Error while updating env store: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
envData.SliceEnv[constants.EnvKeyRoles] = roles
|
||||
envData.SliceEnv[constants.EnvKeyDefaultRoles] = defaultRoles
|
||||
envData.SliceEnv[constants.EnvKeyProtectedRoles] = protectedRoles
|
||||
|
||||
if os.Getenv(constants.EnvKeyOrganizationName) != "" {
|
||||
envData.StringEnv[constants.EnvKeyOrganizationName] = os.Getenv(constants.EnvKeyOrganizationName)
|
||||
}
|
||||
|
||||
if os.Getenv(constants.EnvKeyOrganizationLogo) != "" {
|
||||
envData.StringEnv[constants.EnvKeyOrganizationLogo] = os.Getenv(constants.EnvKeyOrganizationLogo)
|
||||
}
|
||||
|
||||
envstore.EnvStoreObj.UpdateEnvStore(envData)
|
||||
return nil
|
||||
}
|
||||
|
156
server/env/persist_env.go
vendored
156
server/env/persist_env.go
vendored
@@ -1,8 +1,10 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -13,14 +15,52 @@ import (
|
||||
"github.com/authorizerdev/authorizer/server/crypto"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
)
|
||||
|
||||
func fixBackwardCompatibility(data map[string]interface{}) (bool, map[string]interface{}) {
|
||||
result := data
|
||||
// check if env data is stored in older format
|
||||
hasOlderFormat := false
|
||||
if _, ok := result["bool_env"]; ok {
|
||||
for key, value := range result["bool_env"].(map[string]interface{}) {
|
||||
result[key] = value
|
||||
}
|
||||
hasOlderFormat = true
|
||||
delete(result, "bool_env")
|
||||
}
|
||||
|
||||
if _, ok := result["string_env"]; ok {
|
||||
for key, value := range result["string_env"].(map[string]interface{}) {
|
||||
result[key] = value
|
||||
}
|
||||
hasOlderFormat = true
|
||||
delete(result, "string_env")
|
||||
}
|
||||
|
||||
if _, ok := result["slice_env"]; ok {
|
||||
for key, value := range result["slice_env"].(map[string]interface{}) {
|
||||
typeOfValue := reflect.TypeOf(value)
|
||||
if strings.Contains(typeOfValue.String(), "[]string") {
|
||||
result[key] = strings.Join(value.([]string), ",")
|
||||
}
|
||||
if strings.Contains(typeOfValue.String(), "[]interface") {
|
||||
result[key] = strings.Join(utils.ConvertInterfaceToStringSlice(value), ",")
|
||||
}
|
||||
}
|
||||
hasOlderFormat = true
|
||||
delete(result, "slice_env")
|
||||
}
|
||||
|
||||
return hasOlderFormat, result
|
||||
}
|
||||
|
||||
// GetEnvData returns the env data from database
|
||||
func GetEnvData() (envstore.Store, error) {
|
||||
var result envstore.Store
|
||||
env, err := db.Provider.GetEnv()
|
||||
func GetEnvData() (map[string]interface{}, error) {
|
||||
var result map[string]interface{}
|
||||
ctx := context.Background()
|
||||
env, err := db.Provider.GetEnv(ctx)
|
||||
// config not found in db
|
||||
if err != nil {
|
||||
log.Debug("Error while getting env data from db: ", err)
|
||||
@@ -34,7 +74,7 @@ func GetEnvData() (envstore.Store, error) {
|
||||
return result, err
|
||||
}
|
||||
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
|
||||
|
||||
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
|
||||
if err != nil {
|
||||
@@ -54,20 +94,42 @@ func GetEnvData() (envstore.Store, error) {
|
||||
return result, err
|
||||
}
|
||||
|
||||
hasOlderFormat, result := fixBackwardCompatibility(result)
|
||||
|
||||
if hasOlderFormat {
|
||||
err = memorystore.Provider.UpdateEnvStore(result)
|
||||
if err != nil {
|
||||
log.Debug("Error while updating env store: ", err)
|
||||
return result, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// PersistEnv persists the environment variables to the database
|
||||
func PersistEnv() error {
|
||||
env, err := db.Provider.GetEnv()
|
||||
ctx := context.Background()
|
||||
env, err := db.Provider.GetEnv(ctx)
|
||||
// config not found in db
|
||||
if err != nil {
|
||||
if err != nil || env.EnvData == "" {
|
||||
// AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid
|
||||
hash := uuid.New().String()[:36-4]
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyEncryptionKey, hash)
|
||||
err := memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, hash)
|
||||
if err != nil {
|
||||
log.Debug("Error while updating encryption env variable: ", err)
|
||||
return err
|
||||
}
|
||||
encodedHash := crypto.EncryptB64(hash)
|
||||
|
||||
encryptedConfig, err := crypto.EncryptEnvData(envstore.EnvStoreObj.GetEnvStoreClone())
|
||||
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
|
||||
@@ -78,7 +140,7 @@ func PersistEnv() error {
|
||||
EnvData: encryptedConfig,
|
||||
}
|
||||
|
||||
env, err = db.Provider.AddEnv(env)
|
||||
env, err = db.Provider.AddEnv(ctx, env)
|
||||
if err != nil {
|
||||
log.Debug("Error while persisting env data to db: ", err)
|
||||
return err
|
||||
@@ -93,7 +155,7 @@ func PersistEnv() error {
|
||||
return err
|
||||
}
|
||||
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
|
||||
|
||||
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
|
||||
if err != nil {
|
||||
@@ -108,83 +170,81 @@ func PersistEnv() error {
|
||||
}
|
||||
|
||||
// temp store variable
|
||||
var storeData envstore.Store
|
||||
storeData := map[string]interface{}{}
|
||||
|
||||
err = json.Unmarshal(decryptedConfigs, &storeData)
|
||||
if err != nil {
|
||||
log.Debug("Error while unmarshalling env data: ", err)
|
||||
log.Debug("Error while un-marshalling env data: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
hasOlderFormat, result := fixBackwardCompatibility(storeData)
|
||||
if hasOlderFormat {
|
||||
err = memorystore.Provider.UpdateEnvStore(result)
|
||||
if err != nil {
|
||||
log.Debug("Error while updating env store: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if env is changed via env file or OS env
|
||||
// give that higher preference and update db, but we don't recommend it
|
||||
|
||||
hasChanged := false
|
||||
|
||||
for key, value := range storeData.StringEnv {
|
||||
for key, value := range storeData {
|
||||
// don't override unexposed envs
|
||||
if key != constants.EnvKeyEncryptionKey {
|
||||
// check only for derivative keys
|
||||
// No need to check for ENCRYPTION_KEY which special key we use for encrypting config data
|
||||
// as we have removed it from json
|
||||
if key != constants.EnvKeyEncryptionKey {
|
||||
envValue := strings.TrimSpace(os.Getenv(key))
|
||||
|
||||
// env is not empty
|
||||
if envValue != "" {
|
||||
if value != envValue {
|
||||
storeData.StringEnv[key] = envValue
|
||||
switch key {
|
||||
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword:
|
||||
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
||||
if value.(bool) != envValueBool {
|
||||
storeData[key] = envValueBool
|
||||
hasChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for key, value := range storeData.BoolEnv {
|
||||
envValue := strings.TrimSpace(os.Getenv(key))
|
||||
// env is not empty
|
||||
if envValue != "" {
|
||||
envValueBool, _ := strconv.ParseBool(envValue)
|
||||
if value != envValueBool {
|
||||
storeData.BoolEnv[key] = envValueBool
|
||||
default:
|
||||
if value != nil && value.(string) != envValue {
|
||||
storeData[key] = envValue
|
||||
hasChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for key, value := range storeData.SliceEnv {
|
||||
envValue := strings.TrimSpace(os.Getenv(key))
|
||||
// env is not empty
|
||||
if envValue != "" {
|
||||
envStringArr := strings.Split(envValue, ",")
|
||||
if !utils.IsStringArrayEqual(value, envStringArr) {
|
||||
storeData.SliceEnv[key] = envStringArr
|
||||
hasChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle derivative cases like disabling email verification & magic login
|
||||
// in case SMTP is off but env is set to true
|
||||
if storeData.StringEnv[constants.EnvKeySmtpHost] == "" || storeData.StringEnv[constants.EnvKeySmtpUsername] == "" || storeData.StringEnv[constants.EnvKeySmtpPassword] == "" || storeData.StringEnv[constants.EnvKeySenderEmail] == "" && storeData.StringEnv[constants.EnvKeySmtpPort] == "" {
|
||||
if !storeData.BoolEnv[constants.EnvKeyDisableEmailVerification] {
|
||||
storeData.BoolEnv[constants.EnvKeyDisableEmailVerification] = true
|
||||
if storeData[constants.EnvKeySmtpHost] == "" || storeData[constants.EnvKeySmtpUsername] == "" || storeData[constants.EnvKeySmtpPassword] == "" || storeData[constants.EnvKeySenderEmail] == "" && storeData[constants.EnvKeySmtpPort] == "" {
|
||||
if !storeData[constants.EnvKeyDisableEmailVerification].(bool) {
|
||||
storeData[constants.EnvKeyDisableEmailVerification] = true
|
||||
hasChanged = true
|
||||
}
|
||||
|
||||
if !storeData.BoolEnv[constants.EnvKeyDisableMagicLinkLogin] {
|
||||
storeData.BoolEnv[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||
if !storeData[constants.EnvKeyDisableMagicLinkLogin].(bool) {
|
||||
storeData[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||
hasChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
envstore.EnvStoreObj.UpdateEnvStore(storeData)
|
||||
err = memorystore.Provider.UpdateEnvStore(storeData)
|
||||
if err != nil {
|
||||
log.Debug("Error while updating env store: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
jwk, err := crypto.GenerateJWKBasedOnEnv()
|
||||
if err != nil {
|
||||
log.Debug("Error while generating JWK: ", err)
|
||||
return err
|
||||
}
|
||||
// updating jwk
|
||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJWK, jwk)
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJWK, jwk)
|
||||
|
||||
if hasChanged {
|
||||
encryptedConfig, err := crypto.EncryptEnvData(storeData)
|
||||
@@ -194,7 +254,7 @@ func PersistEnv() error {
|
||||
}
|
||||
|
||||
env.EnvData = encryptedConfig
|
||||
_, err = db.Provider.UpdateEnv(env)
|
||||
_, err = db.Provider.UpdateEnv(ctx, env)
|
||||
if err != nil {
|
||||
log.Debug("Failed to Update Config: ", err)
|
||||
return err
|
||||
|
@@ -1,122 +0,0 @@
|
||||
package envstore
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
)
|
||||
|
||||
var (
|
||||
// ARG_DB_URL is the cli arg variable for the database url
|
||||
ARG_DB_URL *string
|
||||
// ARG_DB_TYPE is the cli arg variable for the database type
|
||||
ARG_DB_TYPE *string
|
||||
// ARG_ENV_FILE is the cli arg variable for the env file
|
||||
ARG_ENV_FILE *string
|
||||
// ARG_LOG_LEVEL is the cli arg variable for the log level
|
||||
ARG_LOG_LEVEL *string
|
||||
)
|
||||
|
||||
// Store data structure
|
||||
type Store struct {
|
||||
StringEnv map[string]string `json:"string_env"`
|
||||
BoolEnv map[string]bool `json:"bool_env"`
|
||||
SliceEnv map[string][]string `json:"slice_env"`
|
||||
}
|
||||
|
||||
// EnvStore struct
|
||||
type EnvStore struct {
|
||||
mutex sync.Mutex
|
||||
store *Store
|
||||
}
|
||||
|
||||
var defaultStore = &EnvStore{
|
||||
store: &Store{
|
||||
StringEnv: map[string]string{
|
||||
constants.EnvKeyAdminCookieName: "authorizer-admin",
|
||||
constants.EnvKeyJwtRoleClaim: "role",
|
||||
constants.EnvKeyOrganizationName: "Authorizer",
|
||||
constants.EnvKeyOrganizationLogo: "https://www.authorizer.dev/images/logo.png",
|
||||
},
|
||||
BoolEnv: map[string]bool{
|
||||
constants.EnvKeyDisableBasicAuthentication: false,
|
||||
constants.EnvKeyDisableMagicLinkLogin: false,
|
||||
constants.EnvKeyDisableEmailVerification: false,
|
||||
constants.EnvKeyDisableLoginPage: false,
|
||||
constants.EnvKeyDisableSignUp: false,
|
||||
},
|
||||
SliceEnv: map[string][]string{},
|
||||
},
|
||||
}
|
||||
|
||||
// EnvStoreObj.GetBoolStoreEnvVariable global variable for EnvStore
|
||||
var EnvStoreObj = defaultStore
|
||||
|
||||
// UpdateEnvStore to update the whole env store object
|
||||
func (e *EnvStore) UpdateEnvStore(store Store) {
|
||||
e.mutex.Lock()
|
||||
defer e.mutex.Unlock()
|
||||
// just override the keys + new keys
|
||||
|
||||
for key, value := range store.StringEnv {
|
||||
e.store.StringEnv[key] = value
|
||||
}
|
||||
|
||||
for key, value := range store.BoolEnv {
|
||||
e.store.BoolEnv[key] = value
|
||||
}
|
||||
|
||||
for key, value := range store.SliceEnv {
|
||||
e.store.SliceEnv[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateEnvVariable to update the particular env variable
|
||||
func (e *EnvStore) UpdateEnvVariable(storeIdentifier, key string, value interface{}) {
|
||||
e.mutex.Lock()
|
||||
defer e.mutex.Unlock()
|
||||
switch storeIdentifier {
|
||||
case constants.StringStoreIdentifier:
|
||||
e.store.StringEnv[key] = value.(string)
|
||||
case constants.BoolStoreIdentifier:
|
||||
e.store.BoolEnv[key] = value.(bool)
|
||||
case constants.SliceStoreIdentifier:
|
||||
e.store.SliceEnv[key] = value.([]string)
|
||||
}
|
||||
}
|
||||
|
||||
// GetStringStoreEnvVariable to get the env variable from string store object
|
||||
func (e *EnvStore) GetStringStoreEnvVariable(key string) string {
|
||||
// e.mutex.Lock()
|
||||
// defer e.mutex.Unlock()
|
||||
return e.store.StringEnv[key]
|
||||
}
|
||||
|
||||
// GetBoolStoreEnvVariable to get the env variable from bool store object
|
||||
func (e *EnvStore) GetBoolStoreEnvVariable(key string) bool {
|
||||
// e.mutex.Lock()
|
||||
// defer e.mutex.Unlock()
|
||||
return e.store.BoolEnv[key]
|
||||
}
|
||||
|
||||
// GetSliceStoreEnvVariable to get the env variable from slice store object
|
||||
func (e *EnvStore) GetSliceStoreEnvVariable(key string) []string {
|
||||
// e.mutex.Lock()
|
||||
// defer e.mutex.Unlock()
|
||||
return e.store.SliceEnv[key]
|
||||
}
|
||||
|
||||
// GetEnvStoreClone to get clone of current env store object
|
||||
func (e *EnvStore) GetEnvStoreClone() Store {
|
||||
e.mutex.Lock()
|
||||
defer e.mutex.Unlock()
|
||||
|
||||
result := *e.store
|
||||
return result
|
||||
}
|
||||
|
||||
func (e *EnvStore) ResetStore() {
|
||||
e.mutex.Lock()
|
||||
defer e.mutex.Unlock()
|
||||
e.store = defaultStore.store
|
||||
}
|
@@ -20,7 +20,7 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/ugorji/go v1.2.6 // indirect
|
||||
github.com/vektah/gqlparser/v2 v2.2.0
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,18 @@
|
||||
|
||||
package model
|
||||
|
||||
type AddEmailTemplateRequest struct {
|
||||
EventName string `json:"event_name"`
|
||||
Template string `json:"template"`
|
||||
}
|
||||
|
||||
type AddWebhookRequest struct {
|
||||
EventName string `json:"event_name"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Headers map[string]interface{} `json:"headers"`
|
||||
}
|
||||
|
||||
type AdminLoginInput struct {
|
||||
AdminSecret string `json:"admin_secret"`
|
||||
}
|
||||
@@ -19,20 +31,37 @@ type AuthResponse struct {
|
||||
User *User `json:"user"`
|
||||
}
|
||||
|
||||
type DeleteEmailTemplateRequest struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
type DeleteUserInput struct {
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
type EmailTemplate struct {
|
||||
ID string `json:"id"`
|
||||
EventName string `json:"event_name"`
|
||||
Template string `json:"template"`
|
||||
CreatedAt *int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
type EmailTemplates struct {
|
||||
Pagination *Pagination `json:"pagination"`
|
||||
EmailTemplates []*EmailTemplate `json:"EmailTemplates"`
|
||||
}
|
||||
|
||||
type Env struct {
|
||||
AccessTokenExpiryTime *string `json:"ACCESS_TOKEN_EXPIRY_TIME"`
|
||||
AdminSecret *string `json:"ADMIN_SECRET"`
|
||||
DatabaseName string `json:"DATABASE_NAME"`
|
||||
DatabaseURL string `json:"DATABASE_URL"`
|
||||
DatabaseType string `json:"DATABASE_TYPE"`
|
||||
DatabaseUsername string `json:"DATABASE_USERNAME"`
|
||||
DatabasePassword string `json:"DATABASE_PASSWORD"`
|
||||
DatabaseHost string `json:"DATABASE_HOST"`
|
||||
DatabasePort string `json:"DATABASE_PORT"`
|
||||
DatabaseName *string `json:"DATABASE_NAME"`
|
||||
DatabaseURL *string `json:"DATABASE_URL"`
|
||||
DatabaseType *string `json:"DATABASE_TYPE"`
|
||||
DatabaseUsername *string `json:"DATABASE_USERNAME"`
|
||||
DatabasePassword *string `json:"DATABASE_PASSWORD"`
|
||||
DatabaseHost *string `json:"DATABASE_HOST"`
|
||||
DatabasePort *string `json:"DATABASE_PORT"`
|
||||
ClientID string `json:"CLIENT_ID"`
|
||||
ClientSecret string `json:"CLIENT_SECRET"`
|
||||
CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT"`
|
||||
@@ -48,13 +77,14 @@ type Env struct {
|
||||
AllowedOrigins []string `json:"ALLOWED_ORIGINS"`
|
||||
AppURL *string `json:"APP_URL"`
|
||||
RedisURL *string `json:"REDIS_URL"`
|
||||
CookieName *string `json:"COOKIE_NAME"`
|
||||
ResetPasswordURL *string `json:"RESET_PASSWORD_URL"`
|
||||
DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION"`
|
||||
DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION"`
|
||||
DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN"`
|
||||
DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE"`
|
||||
DisableSignUp *bool `json:"DISABLE_SIGN_UP"`
|
||||
DisableEmailVerification bool `json:"DISABLE_EMAIL_VERIFICATION"`
|
||||
DisableBasicAuthentication bool `json:"DISABLE_BASIC_AUTHENTICATION"`
|
||||
DisableMagicLinkLogin bool `json:"DISABLE_MAGIC_LINK_LOGIN"`
|
||||
DisableLoginPage bool `json:"DISABLE_LOGIN_PAGE"`
|
||||
DisableSignUp bool `json:"DISABLE_SIGN_UP"`
|
||||
DisableRedisForEnv bool `json:"DISABLE_REDIS_FOR_ENV"`
|
||||
DisableStrongPassword bool `json:"DISABLE_STRONG_PASSWORD"`
|
||||
Roles []string `json:"ROLES"`
|
||||
ProtectedRoles []string `json:"PROTECTED_ROLES"`
|
||||
DefaultRoles []string `json:"DEFAULT_ROLES"`
|
||||
@@ -65,6 +95,10 @@ type Env struct {
|
||||
GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"`
|
||||
FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"`
|
||||
FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"`
|
||||
LinkedinClientID *string `json:"LINKEDIN_CLIENT_ID"`
|
||||
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET"`
|
||||
AppleClientID *string `json:"APPLE_CLIENT_ID"`
|
||||
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
|
||||
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
||||
}
|
||||
@@ -95,6 +129,11 @@ type InviteMemberInput struct {
|
||||
RedirectURI *string `json:"redirect_uri"`
|
||||
}
|
||||
|
||||
type ListWebhookLogRequest struct {
|
||||
Pagination *PaginationInput `json:"pagination"`
|
||||
WebhookID *string `json:"webhook_id"`
|
||||
}
|
||||
|
||||
type LoginInput struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
@@ -116,10 +155,13 @@ type Meta struct {
|
||||
IsGoogleLoginEnabled bool `json:"is_google_login_enabled"`
|
||||
IsFacebookLoginEnabled bool `json:"is_facebook_login_enabled"`
|
||||
IsGithubLoginEnabled bool `json:"is_github_login_enabled"`
|
||||
IsLinkedinLoginEnabled bool `json:"is_linkedin_login_enabled"`
|
||||
IsAppleLoginEnabled bool `json:"is_apple_login_enabled"`
|
||||
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
||||
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
||||
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
||||
IsSignUpEnabled bool `json:"is_sign_up_enabled"`
|
||||
IsStrongPasswordEnabled bool `json:"is_strong_password_enabled"`
|
||||
}
|
||||
|
||||
type OAuthRevokeInput struct {
|
||||
@@ -179,10 +221,27 @@ type SignUpInput struct {
|
||||
RedirectURI *string `json:"redirect_uri"`
|
||||
}
|
||||
|
||||
type TestEndpointRequest struct {
|
||||
Endpoint string `json:"endpoint"`
|
||||
EventName string `json:"event_name"`
|
||||
Headers map[string]interface{} `json:"headers"`
|
||||
}
|
||||
|
||||
type TestEndpointResponse struct {
|
||||
HTTPStatus *int64 `json:"http_status"`
|
||||
Response *string `json:"response"`
|
||||
}
|
||||
|
||||
type UpdateAccessInput struct {
|
||||
UserID string `json:"user_id"`
|
||||
}
|
||||
|
||||
type UpdateEmailTemplateRequest struct {
|
||||
ID string `json:"id"`
|
||||
EventName *string `json:"event_name"`
|
||||
Template *string `json:"template"`
|
||||
}
|
||||
|
||||
type UpdateEnvInput struct {
|
||||
AccessTokenExpiryTime *string `json:"ACCESS_TOKEN_EXPIRY_TIME"`
|
||||
AdminSecret *string `json:"ADMIN_SECRET"`
|
||||
@@ -199,14 +258,14 @@ type UpdateEnvInput struct {
|
||||
JwtPublicKey *string `json:"JWT_PUBLIC_KEY"`
|
||||
AllowedOrigins []string `json:"ALLOWED_ORIGINS"`
|
||||
AppURL *string `json:"APP_URL"`
|
||||
RedisURL *string `json:"REDIS_URL"`
|
||||
CookieName *string `json:"COOKIE_NAME"`
|
||||
ResetPasswordURL *string `json:"RESET_PASSWORD_URL"`
|
||||
DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION"`
|
||||
DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION"`
|
||||
DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN"`
|
||||
DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE"`
|
||||
DisableSignUp *bool `json:"DISABLE_SIGN_UP"`
|
||||
DisableRedisForEnv *bool `json:"DISABLE_REDIS_FOR_ENV"`
|
||||
DisableStrongPassword *bool `json:"DISABLE_STRONG_PASSWORD"`
|
||||
Roles []string `json:"ROLES"`
|
||||
ProtectedRoles []string `json:"PROTECTED_ROLES"`
|
||||
DefaultRoles []string `json:"DEFAULT_ROLES"`
|
||||
@@ -217,6 +276,10 @@ type UpdateEnvInput struct {
|
||||
GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"`
|
||||
FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"`
|
||||
FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"`
|
||||
LinkedinClientID *string `json:"LINKEDIN_CLIENT_ID"`
|
||||
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET"`
|
||||
AppleClientID *string `json:"APPLE_CLIENT_ID"`
|
||||
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
|
||||
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
||||
}
|
||||
@@ -251,6 +314,14 @@ type UpdateUserInput struct {
|
||||
Roles []*string `json:"roles"`
|
||||
}
|
||||
|
||||
type UpdateWebhookRequest struct {
|
||||
ID string `json:"id"`
|
||||
EventName *string `json:"event_name"`
|
||||
Endpoint *string `json:"endpoint"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
Headers map[string]interface{} `json:"headers"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
@@ -307,3 +378,37 @@ type VerificationRequests struct {
|
||||
type VerifyEmailInput struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
type Webhook struct {
|
||||
ID string `json:"id"`
|
||||
EventName *string `json:"event_name"`
|
||||
Endpoint *string `json:"endpoint"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
Headers map[string]interface{} `json:"headers"`
|
||||
CreatedAt *int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
type WebhookLog struct {
|
||||
ID string `json:"id"`
|
||||
HTTPStatus *int64 `json:"http_status"`
|
||||
Response *string `json:"response"`
|
||||
Request *string `json:"request"`
|
||||
WebhookID *string `json:"webhook_id"`
|
||||
CreatedAt *int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
type WebhookLogs struct {
|
||||
Pagination *Pagination `json:"pagination"`
|
||||
WebhookLogs []*WebhookLog `json:"webhook_logs"`
|
||||
}
|
||||
|
||||
type WebhookRequest struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
type Webhooks struct {
|
||||
Pagination *Pagination `json:"pagination"`
|
||||
Webhooks []*Webhook `json:"webhooks"`
|
||||
}
|
||||
|
@@ -18,10 +18,13 @@ type Meta {
|
||||
is_google_login_enabled: Boolean!
|
||||
is_facebook_login_enabled: Boolean!
|
||||
is_github_login_enabled: Boolean!
|
||||
is_linkedin_login_enabled: Boolean!
|
||||
is_apple_login_enabled: Boolean!
|
||||
is_email_verification_enabled: Boolean!
|
||||
is_basic_authentication_enabled: Boolean!
|
||||
is_magic_link_login_enabled: Boolean!
|
||||
is_sign_up_enabled: Boolean!
|
||||
is_strong_password_enabled: Boolean!
|
||||
}
|
||||
|
||||
type User {
|
||||
@@ -89,13 +92,13 @@ type Response {
|
||||
type Env {
|
||||
ACCESS_TOKEN_EXPIRY_TIME: String
|
||||
ADMIN_SECRET: String
|
||||
DATABASE_NAME: String!
|
||||
DATABASE_URL: String!
|
||||
DATABASE_TYPE: String!
|
||||
DATABASE_USERNAME: String!
|
||||
DATABASE_PASSWORD: String!
|
||||
DATABASE_HOST: String!
|
||||
DATABASE_PORT: String!
|
||||
DATABASE_NAME: String
|
||||
DATABASE_URL: String
|
||||
DATABASE_TYPE: String
|
||||
DATABASE_USERNAME: String
|
||||
DATABASE_PASSWORD: String
|
||||
DATABASE_HOST: String
|
||||
DATABASE_PORT: String
|
||||
CLIENT_ID: String!
|
||||
CLIENT_SECRET: String!
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT: String
|
||||
@@ -111,13 +114,14 @@ type Env {
|
||||
ALLOWED_ORIGINS: [String!]
|
||||
APP_URL: String
|
||||
REDIS_URL: String
|
||||
COOKIE_NAME: String
|
||||
RESET_PASSWORD_URL: String
|
||||
DISABLE_EMAIL_VERIFICATION: Boolean
|
||||
DISABLE_BASIC_AUTHENTICATION: Boolean
|
||||
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
||||
DISABLE_LOGIN_PAGE: Boolean
|
||||
DISABLE_SIGN_UP: Boolean
|
||||
DISABLE_EMAIL_VERIFICATION: Boolean!
|
||||
DISABLE_BASIC_AUTHENTICATION: Boolean!
|
||||
DISABLE_MAGIC_LINK_LOGIN: Boolean!
|
||||
DISABLE_LOGIN_PAGE: Boolean!
|
||||
DISABLE_SIGN_UP: Boolean!
|
||||
DISABLE_REDIS_FOR_ENV: Boolean!
|
||||
DISABLE_STRONG_PASSWORD: Boolean!
|
||||
ROLES: [String!]
|
||||
PROTECTED_ROLES: [String!]
|
||||
DEFAULT_ROLES: [String!]
|
||||
@@ -128,6 +132,10 @@ type Env {
|
||||
GITHUB_CLIENT_SECRET: String
|
||||
FACEBOOK_CLIENT_ID: String
|
||||
FACEBOOK_CLIENT_SECRET: String
|
||||
LINKEDIN_CLIENT_ID: String
|
||||
LINKEDIN_CLIENT_SECRET: String
|
||||
APPLE_CLIENT_ID: String
|
||||
APPLE_CLIENT_SECRET: String
|
||||
ORGANIZATION_NAME: String
|
||||
ORGANIZATION_LOGO: String
|
||||
}
|
||||
@@ -142,6 +150,54 @@ type GenerateJWTKeysResponse {
|
||||
private_key: String
|
||||
}
|
||||
|
||||
type Webhook {
|
||||
id: ID!
|
||||
event_name: String
|
||||
endpoint: String
|
||||
enabled: Boolean
|
||||
headers: Map
|
||||
created_at: Int64
|
||||
updated_at: Int64
|
||||
}
|
||||
|
||||
type Webhooks {
|
||||
pagination: Pagination!
|
||||
webhooks: [Webhook!]!
|
||||
}
|
||||
|
||||
type WebhookLog {
|
||||
id: ID!
|
||||
http_status: Int64
|
||||
response: String
|
||||
request: String
|
||||
webhook_id: ID
|
||||
created_at: Int64
|
||||
updated_at: Int64
|
||||
}
|
||||
|
||||
type TestEndpointResponse {
|
||||
http_status: Int64
|
||||
response: String
|
||||
}
|
||||
|
||||
type WebhookLogs {
|
||||
pagination: Pagination!
|
||||
webhook_logs: [WebhookLog!]!
|
||||
}
|
||||
|
||||
type EmailTemplate {
|
||||
id: ID!
|
||||
event_name: String!
|
||||
template: String!
|
||||
created_at: Int64
|
||||
updated_at: Int64
|
||||
}
|
||||
|
||||
type EmailTemplates {
|
||||
pagination: Pagination!
|
||||
EmailTemplates: [EmailTemplate!]!
|
||||
}
|
||||
|
||||
input UpdateEnvInput {
|
||||
ACCESS_TOKEN_EXPIRY_TIME: String
|
||||
ADMIN_SECRET: String
|
||||
@@ -158,14 +214,14 @@ input UpdateEnvInput {
|
||||
JWT_PUBLIC_KEY: String
|
||||
ALLOWED_ORIGINS: [String!]
|
||||
APP_URL: String
|
||||
REDIS_URL: String
|
||||
COOKIE_NAME: String
|
||||
RESET_PASSWORD_URL: String
|
||||
DISABLE_EMAIL_VERIFICATION: Boolean
|
||||
DISABLE_BASIC_AUTHENTICATION: Boolean
|
||||
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
||||
DISABLE_LOGIN_PAGE: Boolean
|
||||
DISABLE_SIGN_UP: Boolean
|
||||
DISABLE_REDIS_FOR_ENV: Boolean
|
||||
DISABLE_STRONG_PASSWORD: Boolean
|
||||
ROLES: [String!]
|
||||
PROTECTED_ROLES: [String!]
|
||||
DEFAULT_ROLES: [String!]
|
||||
@@ -176,6 +232,10 @@ input UpdateEnvInput {
|
||||
GITHUB_CLIENT_SECRET: String
|
||||
FACEBOOK_CLIENT_ID: String
|
||||
FACEBOOK_CLIENT_SECRET: String
|
||||
LINKEDIN_CLIENT_ID: String
|
||||
LINKEDIN_CLIENT_SECRET: String
|
||||
APPLE_CLIENT_ID: String
|
||||
APPLE_CLIENT_SECRET: String
|
||||
ORGANIZATION_NAME: String
|
||||
ORGANIZATION_LOGO: String
|
||||
}
|
||||
@@ -312,6 +372,51 @@ input GenerateJWTKeysInput {
|
||||
type: String!
|
||||
}
|
||||
|
||||
input ListWebhookLogRequest {
|
||||
pagination: PaginationInput
|
||||
webhook_id: String
|
||||
}
|
||||
|
||||
input AddWebhookRequest {
|
||||
event_name: String!
|
||||
endpoint: String!
|
||||
enabled: Boolean!
|
||||
headers: Map
|
||||
}
|
||||
|
||||
input UpdateWebhookRequest {
|
||||
id: ID!
|
||||
event_name: String
|
||||
endpoint: String
|
||||
enabled: Boolean
|
||||
headers: Map
|
||||
}
|
||||
|
||||
input WebhookRequest {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
input TestEndpointRequest {
|
||||
endpoint: String!
|
||||
event_name: String!
|
||||
headers: Map
|
||||
}
|
||||
|
||||
input AddEmailTemplateRequest {
|
||||
event_name: String!
|
||||
template: String!
|
||||
}
|
||||
|
||||
input UpdateEmailTemplateRequest {
|
||||
id: ID!
|
||||
event_name: String
|
||||
template: String
|
||||
}
|
||||
|
||||
input DeleteEmailTemplateRequest {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
signup(params: SignUpInput!): AuthResponse!
|
||||
login(params: LoginInput!): AuthResponse!
|
||||
@@ -334,6 +439,13 @@ type Mutation {
|
||||
_revoke_access(param: UpdateAccessInput!): Response!
|
||||
_enable_access(param: UpdateAccessInput!): Response!
|
||||
_generate_jwt_keys(params: GenerateJWTKeysInput!): GenerateJWTKeysResponse!
|
||||
_add_webhook(params: AddWebhookRequest!): Response!
|
||||
_update_webhook(params: UpdateWebhookRequest!): Response!
|
||||
_delete_webhook(params: WebhookRequest!): Response!
|
||||
_test_endpoint(params: TestEndpointRequest!): TestEndpointResponse!
|
||||
_add_email_template(params: AddEmailTemplateRequest!): Response!
|
||||
_update_email_template(params: UpdateEmailTemplateRequest!): Response!
|
||||
_delete_email_template(params: DeleteEmailTemplateRequest!): Response!
|
||||
}
|
||||
|
||||
type Query {
|
||||
@@ -346,4 +458,8 @@ type Query {
|
||||
_verification_requests(params: PaginatedInput): VerificationRequests!
|
||||
_admin_session: Response!
|
||||
_env: Env!
|
||||
_webhook(params: WebhookRequest!): Webhook!
|
||||
_webhooks(params: PaginatedInput): Webhooks!
|
||||
_webhook_logs(params: ListWebhookLogRequest): WebhookLogs!
|
||||
_email_templates(params: PaginatedInput): EmailTemplates!
|
||||
}
|
||||
|
@@ -91,6 +91,34 @@ func (r *mutationResolver) GenerateJwtKeys(ctx context.Context, params model.Gen
|
||||
return resolvers.GenerateJWTKeysResolver(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) AddWebhook(ctx context.Context, params model.AddWebhookRequest) (*model.Response, error) {
|
||||
return resolvers.AddWebhookResolver(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateWebhook(ctx context.Context, params model.UpdateWebhookRequest) (*model.Response, error) {
|
||||
return resolvers.UpdateWebhookResolver(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteWebhook(ctx context.Context, params model.WebhookRequest) (*model.Response, error) {
|
||||
return resolvers.DeleteWebhookResolver(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) TestEndpoint(ctx context.Context, params model.TestEndpointRequest) (*model.TestEndpointResponse, error) {
|
||||
return resolvers.TestEndpointResolver(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) AddEmailTemplate(ctx context.Context, params model.AddEmailTemplateRequest) (*model.Response, error) {
|
||||
return resolvers.AddEmailTemplateResolver(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateEmailTemplate(ctx context.Context, params model.UpdateEmailTemplateRequest) (*model.Response, error) {
|
||||
return resolvers.UpdateEmailTemplateResolver(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteEmailTemplate(ctx context.Context, params model.DeleteEmailTemplateRequest) (*model.Response, error) {
|
||||
return resolvers.DeleteEmailTemplateResolver(ctx, params)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Meta(ctx context.Context) (*model.Meta, error) {
|
||||
return resolvers.MetaResolver(ctx)
|
||||
}
|
||||
@@ -123,6 +151,22 @@ func (r *queryResolver) Env(ctx context.Context) (*model.Env, error) {
|
||||
return resolvers.EnvResolver(ctx)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Webhook(ctx context.Context, params model.WebhookRequest) (*model.Webhook, error) {
|
||||
return resolvers.WebhookResolver(ctx, params)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Webhooks(ctx context.Context, params *model.PaginatedInput) (*model.Webhooks, error) {
|
||||
return resolvers.WebhooksResolver(ctx, params)
|
||||
}
|
||||
|
||||
func (r *queryResolver) WebhookLogs(ctx context.Context, params *model.ListWebhookLogRequest) (*model.WebhookLogs, error) {
|
||||
return resolvers.WebhookLogsResolver(ctx, params)
|
||||
}
|
||||
|
||||
func (r *queryResolver) EmailTemplates(ctx context.Context, params *model.PaginatedInput) (*model.EmailTemplates, error) {
|
||||
return resolvers.EmailTemplatesResolver(ctx, params)
|
||||
}
|
||||
|
||||
// Mutation returns generated.MutationResolver implementation.
|
||||
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }
|
||||
|
||||
|
@@ -8,8 +8,9 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/parsers"
|
||||
"github.com/authorizerdev/authorizer/server/validators"
|
||||
)
|
||||
|
||||
// State is the struct that holds authorizer url and redirect url
|
||||
@@ -22,8 +23,8 @@ type State struct {
|
||||
// AppHandler is the handler for the /app route
|
||||
func AppHandler() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
hostname := utils.GetHost(c)
|
||||
if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableLoginPage) {
|
||||
hostname := parsers.GetHost(c)
|
||||
if isLoginPageDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableLoginPage); err != nil || isLoginPageDisabled {
|
||||
log.Debug("Login page is disabled")
|
||||
c.JSON(400, gin.H{"error": "login page is not enabled"})
|
||||
return
|
||||
@@ -44,7 +45,7 @@ func AppHandler() gin.HandlerFunc {
|
||||
redirect_uri = hostname + "/app"
|
||||
} else {
|
||||
// validate redirect url with allowed origins
|
||||
if !utils.IsValidOrigin(redirect_uri) {
|
||||
if !validators.IsValidOrigin(redirect_uri) {
|
||||
log.Debug("Invalid redirect_uri")
|
||||
c.JSON(400, gin.H{"error": "invalid redirect url"})
|
||||
return
|
||||
@@ -58,14 +59,27 @@ func AppHandler() gin.HandlerFunc {
|
||||
log.Debug("Failed to push file path: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
orgName, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get organization name")
|
||||
c.JSON(400, gin.H{"error": "failed to get organization name"})
|
||||
return
|
||||
}
|
||||
orgLogo, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get organization logo")
|
||||
c.JSON(400, gin.H{"error": "failed to get organization logo"})
|
||||
return
|
||||
}
|
||||
c.HTML(http.StatusOK, "app.tmpl", gin.H{
|
||||
"data": map[string]interface{}{
|
||||
"authorizerURL": hostname,
|
||||
"redirectURL": redirect_uri,
|
||||
"scope": scope,
|
||||
"state": state,
|
||||
"organizationName": envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName),
|
||||
"organizationLogo": envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo),
|
||||
"organizationName": orgName,
|
||||
"organizationLogo": orgLogo,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@@ -13,8 +13,7 @@ import (
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/cookie"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/sessionstore"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/token"
|
||||
)
|
||||
|
||||
@@ -80,7 +79,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if clientID != envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyClientID) {
|
||||
if client, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); client != clientID || err != nil {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
@@ -200,7 +199,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
userID := claims.Subject
|
||||
user, err := db.Provider.GetUserByID(userID)
|
||||
user, err := db.Provider.GetUserByID(gc, userID)
|
||||
if err != nil {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
@@ -219,13 +218,18 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
sessionKey := user.ID
|
||||
if claims.LoginMethod != "" {
|
||||
sessionKey = claims.LoginMethod + ":" + user.ID
|
||||
}
|
||||
|
||||
// if user is logged in
|
||||
// based on the response type, generate the response
|
||||
// based on the response type code, generate the response
|
||||
if isResponseTypeCode {
|
||||
// rollover the session for security
|
||||
sessionstore.RemoveState(sessionToken)
|
||||
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
|
||||
nonce := uuid.New().String()
|
||||
newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope)
|
||||
newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod)
|
||||
if err != nil {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
@@ -244,10 +248,10 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
sessionstore.SetState(newSessionToken, newSessionTokenData.Nonce+"@"+user.ID)
|
||||
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken)
|
||||
cookie.SetSession(gc, newSessionToken)
|
||||
code := uuid.New().String()
|
||||
sessionstore.SetState(codeChallenge, code+"@"+newSessionToken)
|
||||
memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken)
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
@@ -263,7 +267,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
|
||||
if isResponseTypeToken {
|
||||
// rollover the session for security
|
||||
authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope)
|
||||
authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod)
|
||||
if err != nil {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
@@ -281,9 +285,10 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
}
|
||||
return
|
||||
}
|
||||
sessionstore.RemoveState(sessionToken)
|
||||
sessionstore.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
||||
sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
||||
|
||||
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||
|
||||
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||
@@ -306,7 +311,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
if authToken.RefreshToken != nil {
|
||||
res["refresh_token"] = authToken.RefreshToken.Token
|
||||
params += "&refresh_token=" + authToken.RefreshToken.Token
|
||||
sessionstore.SetState(authToken.RefreshToken.Token, authToken.FingerPrint+"@"+user.ID)
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||
}
|
||||
|
||||
if isQuery {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user