Compare commits
365 Commits
fix/add-su
...
discours
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5758fe1e2c | ||
![]() |
9c27d7fcab | ||
![]() |
282c700431 | ||
acc471e500 | |||
586b2cc3af | |||
6a4b3553af | |||
48e1dbf8aa | |||
55121656a8 | |||
e9f54a74f0 | |||
bfa192d21e | |||
800fc4f8d8 | |||
86453d483e | |||
7d5d31692f | |||
5745a9b3c4 | |||
641c5bc248 | |||
085faf73e7 | |||
3197154fec | |||
b8f5e9ebb9 | |||
76f976937a | |||
693f252ae9 | |||
12af7fc617 | |||
32eaff5c5d | |||
0b823ffc33 | |||
42017035fc | |||
c18209418f | |||
c8ba8c1453 | |||
04a8e292c0 | |||
![]() |
9336d3e003 | ||
![]() |
c6f19a82a4 | ||
![]() |
28390ebbe4 | ||
![]() |
5add964449 | ||
![]() |
4eb8ca0d65 | ||
![]() |
d924e36786 | ||
![]() |
d0e6392f1a | ||
![]() |
b931652769 | ||
fb65fcbad5 | |||
79d2d52fc0 | |||
2a766d587f | |||
5c33b159dc | |||
![]() |
ca0118df5e | ||
![]() |
8eb9650142 | ||
![]() |
cfaf6c49b4 | ||
![]() |
4990a77786 | ||
![]() |
82f639757f | ||
![]() |
28b574c827 | ||
![]() |
67f866a787 | ||
![]() |
2420297c20 | ||
5616186be7 | |||
4351f5cd32 | |||
29026ed6fb | |||
f244330401 | |||
132f965c8b | |||
8deba4849d | |||
3a3407f85e | |||
7a1df30325 | |||
d9fd6c2b36 | |||
11472d5b06 | |||
3502d8b3d1 | |||
7c949417c1 | |||
09e4daf66e | |||
32f903f40a | |||
348a9426cc | |||
9ddbfb5df7 | |||
9fa248ca41 | |||
0b0ab12bf0 | |||
be58bb8c6d | |||
cdad58bd02 | |||
934f433dd2 | |||
d6fec9121c | |||
f9e1316145 | |||
362d410e37 | |||
78930dc8f3 | |||
baeb5a68ea | |||
040f7ead7e | |||
3246d32a23 | |||
ce5b09953e | |||
31079f2628 | |||
8fca4cf4c0 | |||
94917e7735 | |||
0f9b95cafe | |||
871c65b9dd | |||
2487077adc | |||
7c03b383f1 | |||
e0db7c1051 | |||
19f5e7e174 | |||
02deafa879 | |||
42efbc232b | |||
7bc9fca4c4 | |||
b20f5986c1 | |||
a66393e754 | |||
e963f325f8 | |||
570436e6e8 | |||
c4472340ef | |||
7a6ae24aaa | |||
db25ceb0b5 | |||
40b8e020a3 | |||
4b249d643f | |||
41f99d1199 | |||
83bb18ae79 | |||
416640ac13 | |||
![]() |
853f8c44bb | ||
bdcf2c39f7 | |||
c53ada95eb | |||
07a26991e9 | |||
c8413665ae | |||
69a87896e9 | |||
![]() |
27b51ad369 | ||
![]() |
747c82f1b9 | ||
![]() |
b1bfaf6688 | ||
034d80303f | |||
![]() |
a328121aa3 | ||
![]() |
40a0a2fbcc | ||
![]() |
e52164665f | ||
![]() |
a63d00b0c8 | ||
![]() |
0bce901749 | ||
![]() |
e5fbaa26e1 | ||
bb62b4adfd | |||
d47b39bb1d | |||
0aa1c2532b | |||
0ab26c19b6 | |||
b8aade7dc0 | |||
6e0ab799b8 | |||
2ccc2ae4eb | |||
95807ae319 | |||
e62f356a79 | |||
0331d34afc | |||
5af71dfc94 | |||
dd4b41674a | |||
58a91814ae | |||
2fba6af769 | |||
ee454aeabe | |||
896e890421 | |||
c5aaad0662 | |||
68c761a181 | |||
f30881de3d | |||
534b5624af | |||
be88e231e0 | |||
1f3cb1aab9 | |||
![]() |
cb01dea902 | ||
![]() |
7bcd5a70c3 | ||
![]() |
3bd3a52d3b | ||
![]() |
ade676f92c | ||
![]() |
ca71aba96d | ||
![]() |
ef2a590608 | ||
![]() |
59ed4e273f | ||
![]() |
751933d40e | ||
![]() |
5fac440205 | ||
![]() |
5ba30ccd12 | ||
![]() |
02f7a62918 | ||
![]() |
1172c95a23 | ||
![]() |
c9c2789097 | ||
![]() |
ed3100c179 | ||
![]() |
b8c6ee0a6d | ||
![]() |
0a5357c948 | ||
![]() |
a002e2faf7 | ||
![]() |
d8b9ffe9ce | ||
![]() |
47f26103b0 | ||
![]() |
48ada9ab26 | ||
![]() |
b8c2ab4cf8 | ||
![]() |
5cb94a7820 | ||
![]() |
7e9fac335b | ||
![]() |
febf4f9b15 | ||
![]() |
b0f54b181d | ||
![]() |
df5978fb5a | ||
![]() |
2a0e0da436 | ||
![]() |
e4a8eb3542 | ||
![]() |
06214f0b1d | ||
![]() |
a203b853f2 | ||
![]() |
109b38e588 | ||
![]() |
e8b99f73c3 | ||
![]() |
3fa892431e | ||
![]() |
4b341c0a5d | ||
![]() |
c95db8b07b | ||
![]() |
32fcba0f8d | ||
![]() |
5b75521490 | ||
![]() |
f70310f04f | ||
![]() |
bea6eb8342 | ||
![]() |
cac67b7915 | ||
![]() |
d7da81d308 | ||
![]() |
e49e315967 | ||
![]() |
fbb4975c02 | ||
![]() |
7f6ddca3fc | ||
![]() |
e71da3def6 | ||
![]() |
46d6f86ab0 | ||
![]() |
1890db8f03 | ||
![]() |
0e96e0b6f0 | ||
![]() |
bbddf484ed | ||
![]() |
7d4c641297 | ||
![]() |
bd343f0b27 | ||
![]() |
ad8bd64987 | ||
![]() |
de5c18b60f | ||
![]() |
fe4c693324 | ||
![]() |
d8cd965004 | ||
![]() |
fdd41721a8 | ||
![]() |
281714b86d | ||
![]() |
a05f5ce063 | ||
![]() |
b7627a36a6 | ||
![]() |
85bbd1223e | ||
![]() |
885a147463 | ||
![]() |
9a6f1a659a | ||
![]() |
4bddbde280 | ||
![]() |
3ed31b0557 | ||
![]() |
4d1fcc3004 | ||
![]() |
99441964b5 | ||
![]() |
be3d8cf69b | ||
![]() |
734e54db69 | ||
![]() |
a3bda429d0 | ||
![]() |
3fba4e4c28 | ||
![]() |
2a759de311 | ||
![]() |
e7c4ee5630 | ||
![]() |
6a4568dcf3 | ||
![]() |
e941e4834a | ||
![]() |
f906fb74af | ||
![]() |
7ced811e6e | ||
![]() |
c1e1ee13f2 | ||
![]() |
60de61a74e | ||
![]() |
843bc022fe | ||
![]() |
ad41bcf792 | ||
![]() |
ea2596b9ae | ||
![]() |
c8ccb89a67 | ||
![]() |
9519b53d4e | ||
![]() |
e7cfaf4fbe | ||
![]() |
0428488dab | ||
![]() |
f3b672a4cf | ||
![]() |
1d6f569f92 | ||
![]() |
fbdc24f314 | ||
![]() |
1275644abe | ||
![]() |
ac6b08c093 | ||
![]() |
fe461b675b | ||
![]() |
77e219d990 | ||
![]() |
3ea13d7e93 | ||
![]() |
940a09d172 | ||
![]() |
3ac6875f87 | ||
![]() |
937506ff64 | ||
![]() |
9795ba9097 | ||
![]() |
11dbe9d97a | ||
![]() |
c9b8bbc3e1 | ||
![]() |
a124edfaee | ||
![]() |
5e6b033024 | ||
![]() |
171d4e3fff | ||
![]() |
cf96a0087f | ||
![]() |
09cfad9c27 | ||
![]() |
35e563ab3b | ||
![]() |
e625ed9633 | ||
![]() |
a042c202a0 | ||
![]() |
7a76b783b1 | ||
![]() |
e5400bc7bd | ||
![]() |
a8503666e3 | ||
![]() |
b028be3cbc | ||
![]() |
9a8d20b698 | ||
![]() |
fab3c2f87e | ||
![]() |
3fefcfcd9a | ||
![]() |
c2defdbaac | ||
![]() |
15a4be5431 | ||
![]() |
146561bacb | ||
![]() |
0c334856bc | ||
![]() |
ba0cf189de | ||
![]() |
9f52c08883 | ||
![]() |
80f3698f06 | ||
![]() |
2a2b7abc08 | ||
![]() |
27e3ed82e4 | ||
![]() |
6077702626 | ||
![]() |
cf54fcef03 | ||
![]() |
2f849b8f0c | ||
![]() |
85ca0f09bf | ||
![]() |
2fc438d810 | ||
![]() |
1796cace15 | ||
![]() |
43fdc826c4 | ||
![]() |
e7652db89c | ||
![]() |
c80b0d7028 | ||
![]() |
55fc4b2608 | ||
![]() |
fac333e195 | ||
![]() |
5018462559 | ||
![]() |
edb5412c17 | ||
![]() |
87a962504f | ||
![]() |
d04f79557a | ||
![]() |
c20e9b810a | ||
![]() |
8d145bd5fe | ||
![]() |
6fa0ad1809 | ||
![]() |
abe809ca68 | ||
![]() |
07f71e883b | ||
![]() |
6cef9064c3 | ||
![]() |
9ae616b6b5 | ||
![]() |
356428ea02 | ||
![]() |
7f47177741 | ||
![]() |
9fb00544cd | ||
![]() |
2b022d1058 | ||
![]() |
1c84d9f4a8 | ||
![]() |
0838b60fae | ||
![]() |
325134466d | ||
![]() |
58d9978dd5 | ||
![]() |
801d64e2f5 | ||
![]() |
dd3cc9de3a | ||
![]() |
8dc7366182 | ||
![]() |
7749534087 | ||
![]() |
510f16e7b0 | ||
![]() |
d5e83ea14f | ||
![]() |
b4a90de1d4 | ||
![]() |
c525ad92f2 | ||
![]() |
9028682e93 | ||
![]() |
3d6bfe4480 | ||
![]() |
043af08bf0 | ||
![]() |
0af78479fc | ||
![]() |
096f686495 | ||
![]() |
c574c6a679 | ||
![]() |
6428b74e64 | ||
![]() |
aa3892025d | ||
![]() |
b2f3d6eb80 | ||
![]() |
348cbf8c38 | ||
![]() |
8ac33a085c | ||
![]() |
6c9b359081 | ||
![]() |
0fde46d274 | ||
![]() |
1a5b446894 | ||
![]() |
930c934fdb | ||
![]() |
4e7074d75b | ||
![]() |
bdfa045a43 | ||
![]() |
a258399bde | ||
![]() |
55a25436a8 | ||
![]() |
9fa402f5c8 | ||
![]() |
1111729ad4 | ||
![]() |
e56c2f58e5 | ||
![]() |
8dbd2556eb | ||
![]() |
17bb077f3e | ||
![]() |
f291417378 | ||
![]() |
f831379d27 | ||
![]() |
a50f6becbd | ||
![]() |
a6f6e0b18a | ||
![]() |
3868157e11 | ||
![]() |
d693c05483 | ||
![]() |
6f1fbf886d | ||
![]() |
b86487fda4 | ||
![]() |
28d4ddeb50 | ||
![]() |
b9ab1d3761 | ||
![]() |
a5b643e127 | ||
![]() |
691664e629 | ||
![]() |
efb67a9538 | ||
![]() |
a0f2eeba3e | ||
![]() |
d1a0ccd790 | ||
![]() |
729c23f578 | ||
![]() |
a074f85391 | ||
![]() |
4e7ec6cb7b | ||
![]() |
6d541cbfb9 | ||
![]() |
1ebba7f2b7 | ||
![]() |
428a0be3db | ||
![]() |
02c0ebb9c4 | ||
![]() |
9a284c03ca | ||
![]() |
c8fe05eabc | ||
![]() |
48344ffd4c | ||
![]() |
77f34e1149 | ||
![]() |
16136931a9 | ||
![]() |
c908ac94da | ||
![]() |
6604b6bbdd | ||
![]() |
2c227b5518 | ||
![]() |
e822b6f31a | ||
![]() |
a38e9d4e6c | ||
![]() |
deaf1e2ff7 | ||
![]() |
f324976801 | ||
![]() |
fad90ce1a8 | ||
![]() |
df406ba053 | ||
![]() |
4a7877a21b | ||
![]() |
79089cc009 | ||
![]() |
149d0cac7a | ||
![]() |
8863140e75 | ||
![]() |
b8ffadd36c | ||
![]() |
7dd20128af |
|
@ -2,3 +2,4 @@ ENV=production
|
||||||
DATABASE_URL=data.db
|
DATABASE_URL=data.db
|
||||||
DATABASE_TYPE=sqlite
|
DATABASE_TYPE=sqlite
|
||||||
CUSTOM_ACCESS_TOKEN_SCRIPT="function(user,tokenPayload){var data = tokenPayload;data.extra = {'x-extra-id': user.id};return data;}"
|
CUSTOM_ACCESS_TOKEN_SCRIPT="function(user,tokenPayload){var data = tokenPayload;data.extra = {'x-extra-id': user.id};return data;}"
|
||||||
|
DISABLE_PLAYGROUND=true
|
||||||
|
|
|
@ -7,4 +7,9 @@ SMTP_PORT=2525
|
||||||
SMTP_USERNAME=test
|
SMTP_USERNAME=test
|
||||||
SMTP_PASSWORD=test
|
SMTP_PASSWORD=test
|
||||||
SENDER_EMAIL="info@authorizer.dev"
|
SENDER_EMAIL="info@authorizer.dev"
|
||||||
|
TWILIO_API_KEY=test
|
||||||
|
TWILIO_API_SECRET=test
|
||||||
|
TWILIO_ACCOUNT_SID=ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
|
TWILIO_SENDER=909921212112
|
||||||
|
SENDER_NAME="Authorizer"
|
||||||
AWS_REGION=ap-south-1
|
AWS_REGION=ap-south-1
|
36
.gitea/workflows/main.yml
Normal file
36
.gitea/workflows/main.yml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
name: "deploy"
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Cloning repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get Repo Name
|
||||||
|
id: repo_name
|
||||||
|
run: echo "::set-output name=repo::$(echo ${GITHUB_REPOSITORY##*/})"
|
||||||
|
|
||||||
|
- name: Get Branch Name
|
||||||
|
id: branch_name
|
||||||
|
run: echo "::set-output name=branch::$(echo ${GITHUB_REF##*/})"
|
||||||
|
|
||||||
|
- name: Push branch 'discours-dev' to staging
|
||||||
|
if: steps.branch_name.outputs.branch == 'discours-dev'
|
||||||
|
uses: dokku/github-action@master
|
||||||
|
with:
|
||||||
|
branch: "main"
|
||||||
|
git_remote_url: "ssh://dokku@staging.discours.io:22/authorizer"
|
||||||
|
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
- name: Push branch 'discours' to v2.discours.io
|
||||||
|
if: steps.branch_name.outputs.branch == 'discours'
|
||||||
|
uses: dokku/github-action@master
|
||||||
|
with:
|
||||||
|
branch: "main"
|
||||||
|
git_remote_url: "ssh://dokku@v2.discours.io:22/authorizer"
|
||||||
|
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
git_push_flags: '--force'
|
28
.github/CONTRIBUTING.md
vendored
28
.github/CONTRIBUTING.md
vendored
|
@ -45,12 +45,30 @@ Please ask as many questions as you need, either directly in the issue or on [Di
|
||||||
1. Fork the [authorizer](https://github.com/authorizerdev/authorizer) repository (**Skip this step if you have access to repo**)
|
1. Fork the [authorizer](https://github.com/authorizerdev/authorizer) repository (**Skip this step if you have access to repo**)
|
||||||
2. Clone repo: `git clone https://github.com/authorizerdev/authorizer.git` or use the forked url from step 1
|
2. Clone repo: `git clone https://github.com/authorizerdev/authorizer.git` or use the forked url from step 1
|
||||||
3. Change directory to authorizer: `cd authorizer`
|
3. Change directory to authorizer: `cd authorizer`
|
||||||
5. Create Env file `cp .env.sample .env`. Check all the supported env [here](https://docs.authorizer.dev/core/env/)
|
4. Create Env file `cp .env.sample .env`. Check all the supported env [here](https://docs.authorizer.dev/core/env/)
|
||||||
6. Build Dashboard `make build-dashboard`
|
5. Build Dashboard `make build-dashboard`
|
||||||
7. Build App `make build-app`
|
6. Build App `make build-app`
|
||||||
8. Build Server `make clean && make`
|
7. Build Server `make clean && make`
|
||||||
> Note: if you don't have [`make`](https://www.ibm.com/docs/en/aix/7.2?topic=concepts-make-command), you can `cd` into `server` dir and build using the `go build` command. In that case you will have to build `dashboard` & `app` manually using `npm run build` on both dirs.
|
> Note: if you don't have [`make`](https://www.ibm.com/docs/en/aix/7.2?topic=concepts-make-command), you can `cd` into `server` dir and build using the `go build` command. In that case you will have to build `dashboard` & `app` manually using `npm run build` on both dirs.
|
||||||
9. Run binary `./build/server`
|
8. Run binary `./build/server`
|
||||||
|
|
||||||
|
### Updating GraphQL schema
|
||||||
|
|
||||||
|
- Modify `server/graph/schema.graphqls` file
|
||||||
|
- Run `make generate-graphql` this will update the models and required methods
|
||||||
|
- If a new mutation or query is added
|
||||||
|
- Write the implementation for the new resolver in `server/resolvers/NEW_RESOLVER.GO`
|
||||||
|
- Update `server/graph/schema.resolvers.go` with the new resolver method
|
||||||
|
|
||||||
|
### Adding support for new database
|
||||||
|
|
||||||
|
- Run `make generate-db-template dbname=NEW_DB_NAME`
|
||||||
|
eg `make generate-db-template dbname=dynamodb`
|
||||||
|
|
||||||
|
This command will generate a folder in server/db/providers/ with name specified in the above command.
|
||||||
|
One will have to implement methods present in that folder.
|
||||||
|
|
||||||
|
> Note: Connection for database and schema changes are written in `server/db/providers/DB_NAME/provider.go` > `NewProvider` method is called for any given db based on the env variables present.
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
|
|
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: authorizerdev
|
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
|
@ -62,12 +62,14 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
make clean && \
|
make clean && \
|
||||||
make build && \
|
make build && \
|
||||||
|
mkdir -p authorizer-${VERSION}-darwin-arm64/build authorizer-${VERSION}-darwin-arm64/app authorizer-${VERSION}-darwin-arm64/dashboard && cp build/darwin/arm64/server authorizer-${VERSION}-darwin-arm64/build/ && cp .env authorizer-${VERSION}-darwin-arm64/.env && cp -rf app/build authorizer-${VERSION}-darwin-arm64/app/build && cp -rf templates authorizer-${VERSION}-darwin-arm64/ && cp -rf dashboard/build authorizer-${VERSION}-darwin-arm64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-arm64.tar.gz authorizer-${VERSION}-darwin-arm64 && \
|
||||||
mkdir -p authorizer-${VERSION}-darwin-amd64/build authorizer-${VERSION}-darwin-amd64/app authorizer-${VERSION}-darwin-amd64/dashboard && cp build/darwin/amd64/server authorizer-${VERSION}-darwin-amd64/build/ && cp .env authorizer-${VERSION}-darwin-amd64/.env && cp -rf app/build authorizer-${VERSION}-darwin-amd64/app/build && cp -rf templates authorizer-${VERSION}-darwin-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-darwin-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-amd64.tar.gz authorizer-${VERSION}-darwin-amd64 && \
|
mkdir -p authorizer-${VERSION}-darwin-amd64/build authorizer-${VERSION}-darwin-amd64/app authorizer-${VERSION}-darwin-amd64/dashboard && cp build/darwin/amd64/server authorizer-${VERSION}-darwin-amd64/build/ && cp .env authorizer-${VERSION}-darwin-amd64/.env && cp -rf app/build authorizer-${VERSION}-darwin-amd64/app/build && cp -rf templates authorizer-${VERSION}-darwin-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-darwin-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-amd64.tar.gz authorizer-${VERSION}-darwin-amd64 && \
|
||||||
mkdir -p authorizer-${VERSION}-linux-amd64/build authorizer-${VERSION}-linux-amd64/app authorizer-${VERSION}-linux-amd64/dashboard && cp build/linux/amd64/server authorizer-${VERSION}-linux-amd64/build/ && cp .env authorizer-${VERSION}-linux-amd64/.env && cp -rf app/build authorizer-${VERSION}-linux-amd64/app/build && cp -rf templates authorizer-${VERSION}-linux-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz authorizer-${VERSION}-linux-amd64 && \
|
mkdir -p authorizer-${VERSION}-linux-amd64/build authorizer-${VERSION}-linux-amd64/app authorizer-${VERSION}-linux-amd64/dashboard && cp build/linux/amd64/server authorizer-${VERSION}-linux-amd64/build/ && cp .env authorizer-${VERSION}-linux-amd64/.env && cp -rf app/build authorizer-${VERSION}-linux-amd64/app/build && cp -rf templates authorizer-${VERSION}-linux-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz authorizer-${VERSION}-linux-amd64 && \
|
||||||
mkdir -p authorizer-${VERSION}-linux-arm64/build authorizer-${VERSION}-linux-arm64/app authorizer-${VERSION}-linux-arm64/dashboard && cp build/linux/arm64/server authorizer-${VERSION}-linux-arm64/build/ && cp .env authorizer-${VERSION}-linux-arm64/.env && cp -rf app/build authorizer-${VERSION}-linux-arm64/app/build && cp -rf templates authorizer-${VERSION}-linux-arm64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-arm64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-arm64.tar.gz authorizer-${VERSION}-linux-arm64 && \
|
mkdir -p authorizer-${VERSION}-linux-arm64/build authorizer-${VERSION}-linux-arm64/app authorizer-${VERSION}-linux-arm64/dashboard && cp build/linux/arm64/server authorizer-${VERSION}-linux-arm64/build/ && cp .env authorizer-${VERSION}-linux-arm64/.env && cp -rf app/build authorizer-${VERSION}-linux-arm64/app/build && cp -rf templates authorizer-${VERSION}-linux-arm64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-arm64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-arm64.tar.gz authorizer-${VERSION}-linux-arm64 && \
|
||||||
mkdir -p authorizer-${VERSION}-windows-amd64/build authorizer-${VERSION}-windows-amd64/app authorizer-${VERSION}-windows-amd64/dashboard && cp build/windows/amd64/server.exe authorizer-${VERSION}-windows-amd64/build/ && cp .env authorizer-${VERSION}-windows-amd64/.env && cp -rf app/build authorizer-${VERSION}-windows-amd64/app/build && cp -rf templates authorizer-${VERSION}-windows-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-windows-amd64/dashboard/build && zip -vr authorizer-${VERSION}-windows-amd64.zip authorizer-${VERSION}-windows-amd64
|
mkdir -p authorizer-${VERSION}-windows-amd64/build authorizer-${VERSION}-windows-amd64/app authorizer-${VERSION}-windows-amd64/dashboard && cp build/windows/amd64/server.exe authorizer-${VERSION}-windows-amd64/build/ && cp .env authorizer-${VERSION}-windows-amd64/.env && cp -rf app/build authorizer-${VERSION}-windows-amd64/app/build && cp -rf templates authorizer-${VERSION}-windows-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-windows-amd64/dashboard/build && zip -vr authorizer-${VERSION}-windows-amd64.zip authorizer-${VERSION}-windows-amd64
|
||||||
- name: Upload assets
|
- name: Upload assets
|
||||||
run: |
|
run: |
|
||||||
|
github-assets-uploader -f authorizer-${VERSION}-darwin-arm64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
|
||||||
github-assets-uploader -f authorizer-${VERSION}-darwin-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
|
github-assets-uploader -f authorizer-${VERSION}-darwin-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
|
||||||
github-assets-uploader -f authorizer-${VERSION}-linux-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
|
github-assets-uploader -f authorizer-${VERSION}-linux-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
|
||||||
github-assets-uploader -f authorizer-${VERSION}-linux-arm64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
|
github-assets-uploader -f authorizer-${VERSION}-linux-arm64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -18,3 +18,5 @@ yalc.lock
|
||||||
certs/
|
certs/
|
||||||
*-shm
|
*-shm
|
||||||
*-wal
|
*-wal
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM golang:1.19.5-alpine as go-builder
|
FROM golang:1.21.3-alpine3.18 AS go-builder
|
||||||
WORKDIR /authorizer
|
WORKDIR /authorizer
|
||||||
COPY server server
|
COPY server server
|
||||||
COPY Makefile .
|
COPY Makefile .
|
||||||
|
@ -11,7 +11,7 @@ RUN apk add build-base &&\
|
||||||
make clean && make && \
|
make clean && make && \
|
||||||
chmod 777 build/server
|
chmod 777 build/server
|
||||||
|
|
||||||
FROM node:17-alpine3.12 as node-builder
|
FROM node:20-alpine3.18 AS node-builder
|
||||||
WORKDIR /authorizer
|
WORKDIR /authorizer
|
||||||
COPY app app
|
COPY app app
|
||||||
COPY dashboard dashboard
|
COPY dashboard dashboard
|
||||||
|
@ -20,7 +20,7 @@ RUN apk add build-base &&\
|
||||||
make build-app && \
|
make build-app && \
|
||||||
make build-dashboard
|
make build-dashboard
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:3.18
|
||||||
RUN adduser -D -h /authorizer -u 1000 -k /dev/null authorizer
|
RUN adduser -D -h /authorizer -u 1000 -k /dev/null authorizer
|
||||||
WORKDIR /authorizer
|
WORKDIR /authorizer
|
||||||
RUN mkdir app dashboard
|
RUN mkdir app dashboard
|
||||||
|
|
11
Makefile
11
Makefile
|
@ -5,7 +5,7 @@ cmd:
|
||||||
cd server && go build -ldflags "-w -X main.VERSION=$(VERSION)" -o '../build/server'
|
cd server && go build -ldflags "-w -X main.VERSION=$(VERSION)" -o '../build/server'
|
||||||
build:
|
build:
|
||||||
cd server && gox \
|
cd server && gox \
|
||||||
-osarch="linux/amd64 linux/arm64 darwin/amd64 windows/amd64" \
|
-osarch="linux/amd64 linux/arm64 darwin/arm64 darwin/amd64 windows/amd64" \
|
||||||
-ldflags "-w -X main.VERSION=$(VERSION)" \
|
-ldflags "-w -X main.VERSION=$(VERSION)" \
|
||||||
-output="../build/{{.OS}}/{{.Arch}}/server" \
|
-output="../build/{{.OS}}/{{.Arch}}/server" \
|
||||||
./...
|
./...
|
||||||
|
@ -46,11 +46,14 @@ test-all-db:
|
||||||
docker run -d --name dynamodb-local-test -p 8000:8000 amazon/dynamodb-local:latest
|
docker run -d --name dynamodb-local-test -p 8000:8000 amazon/dynamodb-local:latest
|
||||||
docker run -d --name couchbase-local-test -p 8091-8097:8091-8097 -p 11210:11210 -p 11207:11207 -p 18091-18095:18091-18095 -p 18096:18096 -p 18097:18097 couchbase:latest
|
docker run -d --name couchbase-local-test -p 8091-8097:8091-8097 -p 11210:11210 -p 11207:11207 -p 18091-18095:18091-18095 -p 18096:18096 -p 18097:18097 couchbase:latest
|
||||||
sh scripts/couchbase-test.sh
|
sh scripts/couchbase-test.sh
|
||||||
cd server && go clean --testcache && TEST_DBS="sqlite,mongodb,arangodb,scylladb,dynamodb" go test -p 1 -v ./test
|
cd server && go clean --testcache && TEST_DBS="sqlite,mongodb,arangodb,scylladb,dynamodb,couchbase" go test -p 1 -v ./test
|
||||||
docker rm -vf authorizer_scylla_db
|
docker rm -vf authorizer_scylla_db
|
||||||
docker rm -vf authorizer_mongodb_db
|
docker rm -vf authorizer_mongodb_db
|
||||||
docker rm -vf authorizer_arangodb
|
docker rm -vf authorizer_arangodb
|
||||||
docker rm -vf dynamodb-local-test
|
docker rm -vf dynamodb-local-test
|
||||||
# docker rm -vf couchbase-local-test
|
docker rm -vf couchbase-local-test
|
||||||
generate:
|
generate-graphql:
|
||||||
cd server && go run github.com/99designs/gqlgen generate && go mod tidy
|
cd server && go run github.com/99designs/gqlgen generate && go mod tidy
|
||||||
|
generate-db-template:
|
||||||
|
cp -rf server/db/providers/provider_template server/db/providers/${dbname}
|
||||||
|
find server/db/providers/${dbname} -type f -exec sed -i -e 's/provider_template/${dbname}/g' {} \;
|
||||||
|
|
|
@ -68,6 +68,8 @@ Deploy production ready Authorizer instance using one click deployment options a
|
||||||
| Railway.app | <a href="https://railway.app/new/template/nwXp1C?referralCode=FEF4uT"><img src="https://railway.app/button.svg" style="height: 44px" alt="Deploy on Railway"></a> | [docs](https://docs.authorizer.dev/deployment/railway) |
|
| Railway.app | <a href="https://railway.app/new/template/nwXp1C?referralCode=FEF4uT"><img src="https://railway.app/button.svg" style="height: 44px" alt="Deploy on Railway"></a> | [docs](https://docs.authorizer.dev/deployment/railway) |
|
||||||
| Heroku | <a href="https://heroku.com/deploy?template=https://github.com/authorizerdev/authorizer-heroku"><img src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy to Heroku" style="height: 44px;"></a> | [docs](https://docs.authorizer.dev/deployment/heroku) |
|
| Heroku | <a href="https://heroku.com/deploy?template=https://github.com/authorizerdev/authorizer-heroku"><img src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy to Heroku" style="height: 44px;"></a> | [docs](https://docs.authorizer.dev/deployment/heroku) |
|
||||||
| Render | [](https://render.com/deploy?repo=https://github.com/authorizerdev/authorizer-render) | [docs](https://docs.authorizer.dev/deployment/render) |
|
| Render | [](https://render.com/deploy?repo=https://github.com/authorizerdev/authorizer-render) | [docs](https://docs.authorizer.dev/deployment/render) |
|
||||||
|
| Koyeb | <a target="_blank" href="https://app.koyeb.com/deploy?name=authorizer&type=docker&image=docker.io/lakhansamani/authorizer&env[PORT]=8000&env[DATABASE_TYPE]=postgres&env[DATABASE_URL]=CHANGE_ME&ports=8000;http;/"><img alt="Deploy to Koyeb" src="https://www.koyeb.com/static/images/deploy/button.svg" /></a> | [docs](https://docs.authorizer.dev/deployment/koyeb) |
|
||||||
|
| RepoCloud | <a href="https://repocloud.io/details/?app_id=174"><img src="https://d16t0pc4846x52.cloudfront.net/deploy.png" alt="Deploy on RepoCloud"></a> | [docs](https://repocloud.io/details/?app_id=174) |
|
||||||
|
|
||||||
### Deploy Authorizer Using Source Code
|
### Deploy Authorizer Using Source Code
|
||||||
|
|
||||||
|
|
888
app/package-lock.json
generated
888
app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -12,7 +12,7 @@
|
||||||
"author": "Lakhan Samani",
|
"author": "Lakhan Samani",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^1.1.8",
|
"@authorizerdev/authorizer-react": "^1.3.2",
|
||||||
"@types/react": "^17.0.15",
|
"@types/react": "^17.0.15",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.9",
|
||||||
"esbuild": "^0.12.17",
|
"esbuild": "^0.12.17",
|
||||||
|
|
626
app/pnpm-lock.yaml
Normal file
626
app/pnpm-lock.yaml
Normal file
|
@ -0,0 +1,626 @@
|
||||||
|
lockfileVersion: 5.4
|
||||||
|
|
||||||
|
specifiers:
|
||||||
|
'@authorizerdev/authorizer-react': ^1.1.9
|
||||||
|
'@types/react': ^17.0.15
|
||||||
|
'@types/react-dom': ^17.0.9
|
||||||
|
'@types/react-router-dom': ^5.1.8
|
||||||
|
'@types/styled-components': ^5.1.11
|
||||||
|
esbuild: ^0.12.17
|
||||||
|
prettier: 2.7.1
|
||||||
|
react: ^17.0.2
|
||||||
|
react-dom: ^17.0.2
|
||||||
|
react-is: ^17.0.2
|
||||||
|
react-router-dom: ^5.2.0
|
||||||
|
styled-components: ^5.3.0
|
||||||
|
typescript: ^4.3.5
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
'@authorizerdev/authorizer-react': 1.1.9_react@17.0.2
|
||||||
|
'@types/react': 17.0.53
|
||||||
|
'@types/react-dom': 17.0.19
|
||||||
|
esbuild: 0.12.29
|
||||||
|
react: 17.0.2
|
||||||
|
react-dom: 17.0.2_react@17.0.2
|
||||||
|
react-is: 17.0.2
|
||||||
|
react-router-dom: 5.3.4_react@17.0.2
|
||||||
|
styled-components: 5.3.9_fane7jikarojcev26y27hpbhu4
|
||||||
|
typescript: 4.9.5
|
||||||
|
|
||||||
|
devDependencies:
|
||||||
|
'@types/react-router-dom': 5.3.3
|
||||||
|
'@types/styled-components': 5.1.26
|
||||||
|
prettier: 2.7.1
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
/@authorizerdev/authorizer-js/1.2.1:
|
||||||
|
resolution: {integrity: sha512-/nFARvsHyZUsGFKrcYi8hgpnbThYR/NMJ2BJdQpWy/x7QsBnfLeCChBYWncbYHSIjFCa5PPKKfvhXM56HqVqsw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dependencies:
|
||||||
|
cross-fetch: 3.1.5
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@authorizerdev/authorizer-react/1.1.9_react@17.0.2:
|
||||||
|
resolution: {integrity: sha512-BlB4ixEm9nf+yjZ9OqIWbx5fMTmzeByEsNDAd5iYkt6HB+3Sk53DGiO5h6SgJznzPyqAwl8yg6y/QgbZreDTFA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16'
|
||||||
|
dependencies:
|
||||||
|
'@authorizerdev/authorizer-js': 1.2.1
|
||||||
|
react: 17.0.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/code-frame/7.18.6:
|
||||||
|
resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/highlight': 7.18.6
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/generator/7.21.3:
|
||||||
|
resolution: {integrity: sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/types': 7.21.3
|
||||||
|
'@jridgewell/gen-mapping': 0.3.2
|
||||||
|
'@jridgewell/trace-mapping': 0.3.17
|
||||||
|
jsesc: 2.5.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/helper-annotate-as-pure/7.18.6:
|
||||||
|
resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/types': 7.21.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/helper-environment-visitor/7.18.9:
|
||||||
|
resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/helper-function-name/7.21.0:
|
||||||
|
resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/template': 7.20.7
|
||||||
|
'@babel/types': 7.21.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/helper-hoist-variables/7.18.6:
|
||||||
|
resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/types': 7.21.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/helper-module-imports/7.18.6:
|
||||||
|
resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/types': 7.21.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/helper-split-export-declaration/7.18.6:
|
||||||
|
resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/types': 7.21.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/helper-string-parser/7.19.4:
|
||||||
|
resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/helper-validator-identifier/7.19.1:
|
||||||
|
resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/highlight/7.18.6:
|
||||||
|
resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-validator-identifier': 7.19.1
|
||||||
|
chalk: 2.4.2
|
||||||
|
js-tokens: 4.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/parser/7.21.3:
|
||||||
|
resolution: {integrity: sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/types': 7.21.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/runtime/7.21.0:
|
||||||
|
resolution: {integrity: sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime: 0.13.11
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/template/7.20.7:
|
||||||
|
resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/code-frame': 7.18.6
|
||||||
|
'@babel/parser': 7.21.3
|
||||||
|
'@babel/types': 7.21.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/traverse/7.21.3_supports-color@5.5.0:
|
||||||
|
resolution: {integrity: sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/code-frame': 7.18.6
|
||||||
|
'@babel/generator': 7.21.3
|
||||||
|
'@babel/helper-environment-visitor': 7.18.9
|
||||||
|
'@babel/helper-function-name': 7.21.0
|
||||||
|
'@babel/helper-hoist-variables': 7.18.6
|
||||||
|
'@babel/helper-split-export-declaration': 7.18.6
|
||||||
|
'@babel/parser': 7.21.3
|
||||||
|
'@babel/types': 7.21.3
|
||||||
|
debug: 4.3.4_supports-color@5.5.0
|
||||||
|
globals: 11.12.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/types/7.21.3:
|
||||||
|
resolution: {integrity: sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-string-parser': 7.19.4
|
||||||
|
'@babel/helper-validator-identifier': 7.19.1
|
||||||
|
to-fast-properties: 2.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/is-prop-valid/1.2.0:
|
||||||
|
resolution: {integrity: sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==}
|
||||||
|
dependencies:
|
||||||
|
'@emotion/memoize': 0.8.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/memoize/0.8.0:
|
||||||
|
resolution: {integrity: sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/stylis/0.8.5:
|
||||||
|
resolution: {integrity: sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/unitless/0.7.5:
|
||||||
|
resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@jridgewell/gen-mapping/0.3.2:
|
||||||
|
resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/set-array': 1.1.2
|
||||||
|
'@jridgewell/sourcemap-codec': 1.4.14
|
||||||
|
'@jridgewell/trace-mapping': 0.3.17
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@jridgewell/resolve-uri/3.1.0:
|
||||||
|
resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@jridgewell/set-array/1.1.2:
|
||||||
|
resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@jridgewell/sourcemap-codec/1.4.14:
|
||||||
|
resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@jridgewell/trace-mapping/0.3.17:
|
||||||
|
resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==}
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/resolve-uri': 3.1.0
|
||||||
|
'@jridgewell/sourcemap-codec': 1.4.14
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/history/4.7.11:
|
||||||
|
resolution: {integrity: sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/hoist-non-react-statics/3.3.1:
|
||||||
|
resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 17.0.53
|
||||||
|
hoist-non-react-statics: 3.3.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/prop-types/15.7.5:
|
||||||
|
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
||||||
|
|
||||||
|
/@types/react-dom/17.0.19:
|
||||||
|
resolution: {integrity: sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 17.0.53
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/react-router-dom/5.3.3:
|
||||||
|
resolution: {integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==}
|
||||||
|
dependencies:
|
||||||
|
'@types/history': 4.7.11
|
||||||
|
'@types/react': 17.0.53
|
||||||
|
'@types/react-router': 5.1.20
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/react-router/5.1.20:
|
||||||
|
resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==}
|
||||||
|
dependencies:
|
||||||
|
'@types/history': 4.7.11
|
||||||
|
'@types/react': 17.0.53
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/react/17.0.53:
|
||||||
|
resolution: {integrity: sha512-1yIpQR2zdYu1Z/dc1OxC+MA6GR240u3gcnP4l6mvj/PJiVaqHsQPmWttsvHsfnhfPbU2FuGmo0wSITPygjBmsw==}
|
||||||
|
dependencies:
|
||||||
|
'@types/prop-types': 15.7.5
|
||||||
|
'@types/scheduler': 0.16.3
|
||||||
|
csstype: 3.1.1
|
||||||
|
|
||||||
|
/@types/scheduler/0.16.3:
|
||||||
|
resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==}
|
||||||
|
|
||||||
|
/@types/styled-components/5.1.26:
|
||||||
|
resolution: {integrity: sha512-KuKJ9Z6xb93uJiIyxo/+ksS7yLjS1KzG6iv5i78dhVg/X3u5t1H7juRWqVmodIdz6wGVaIApo1u01kmFRdJHVw==}
|
||||||
|
dependencies:
|
||||||
|
'@types/hoist-non-react-statics': 3.3.1
|
||||||
|
'@types/react': 17.0.53
|
||||||
|
csstype: 3.1.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/ansi-styles/3.2.1:
|
||||||
|
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dependencies:
|
||||||
|
color-convert: 1.9.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/babel-plugin-styled-components/2.0.7_styled-components@5.3.9:
|
||||||
|
resolution: {integrity: sha512-i7YhvPgVqRKfoQ66toiZ06jPNA3p6ierpfUuEWxNF+fV27Uv5gxBkf8KZLHUCc1nFA9j6+80pYoIpqCeyW3/bA==}
|
||||||
|
peerDependencies:
|
||||||
|
styled-components: '>= 2'
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-annotate-as-pure': 7.18.6
|
||||||
|
'@babel/helper-module-imports': 7.18.6
|
||||||
|
babel-plugin-syntax-jsx: 6.18.0
|
||||||
|
lodash: 4.17.21
|
||||||
|
picomatch: 2.3.1
|
||||||
|
styled-components: 5.3.9_fane7jikarojcev26y27hpbhu4
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/babel-plugin-syntax-jsx/6.18.0:
|
||||||
|
resolution: {integrity: sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/camelize/1.0.1:
|
||||||
|
resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/chalk/2.4.2:
|
||||||
|
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dependencies:
|
||||||
|
ansi-styles: 3.2.1
|
||||||
|
escape-string-regexp: 1.0.5
|
||||||
|
supports-color: 5.5.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/color-convert/1.9.3:
|
||||||
|
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||||
|
dependencies:
|
||||||
|
color-name: 1.1.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/color-name/1.1.3:
|
||||||
|
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/cross-fetch/3.1.5:
|
||||||
|
resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==}
|
||||||
|
dependencies:
|
||||||
|
node-fetch: 2.6.7
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/css-color-keywords/1.0.0:
|
||||||
|
resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/css-to-react-native/3.2.0:
|
||||||
|
resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==}
|
||||||
|
dependencies:
|
||||||
|
camelize: 1.0.1
|
||||||
|
css-color-keywords: 1.0.0
|
||||||
|
postcss-value-parser: 4.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/csstype/3.1.1:
|
||||||
|
resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
|
||||||
|
|
||||||
|
/debug/4.3.4_supports-color@5.5.0:
|
||||||
|
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||||
|
engines: {node: '>=6.0'}
|
||||||
|
peerDependencies:
|
||||||
|
supports-color: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
supports-color:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
ms: 2.1.2
|
||||||
|
supports-color: 5.5.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/esbuild/0.12.29:
|
||||||
|
resolution: {integrity: sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g==}
|
||||||
|
hasBin: true
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/escape-string-regexp/1.0.5:
|
||||||
|
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
|
||||||
|
engines: {node: '>=0.8.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/globals/11.12.0:
|
||||||
|
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/has-flag/3.0.0:
|
||||||
|
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/history/4.10.1:
|
||||||
|
resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==}
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.21.0
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
resolve-pathname: 3.0.0
|
||||||
|
tiny-invariant: 1.3.1
|
||||||
|
tiny-warning: 1.0.3
|
||||||
|
value-equal: 1.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/hoist-non-react-statics/3.3.2:
|
||||||
|
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
|
||||||
|
dependencies:
|
||||||
|
react-is: 16.13.1
|
||||||
|
|
||||||
|
/isarray/0.0.1:
|
||||||
|
resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/js-tokens/4.0.0:
|
||||||
|
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/jsesc/2.5.2:
|
||||||
|
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
hasBin: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/lodash/4.17.21:
|
||||||
|
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/loose-envify/1.4.0:
|
||||||
|
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
js-tokens: 4.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/ms/2.1.2:
|
||||||
|
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/node-fetch/2.6.7:
|
||||||
|
resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
|
||||||
|
engines: {node: 4.x || >=6.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
encoding: ^0.1.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
encoding:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
whatwg-url: 5.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/object-assign/4.1.1:
|
||||||
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/path-to-regexp/1.8.0:
|
||||||
|
resolution: {integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==}
|
||||||
|
dependencies:
|
||||||
|
isarray: 0.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/picomatch/2.3.1:
|
||||||
|
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||||
|
engines: {node: '>=8.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/postcss-value-parser/4.2.0:
|
||||||
|
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/prettier/2.7.1:
|
||||||
|
resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/prop-types/15.8.1:
|
||||||
|
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||||
|
dependencies:
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
object-assign: 4.1.1
|
||||||
|
react-is: 16.13.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/react-dom/17.0.2_react@17.0.2:
|
||||||
|
resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==}
|
||||||
|
peerDependencies:
|
||||||
|
react: 17.0.2
|
||||||
|
dependencies:
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
object-assign: 4.1.1
|
||||||
|
react: 17.0.2
|
||||||
|
scheduler: 0.20.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/react-is/16.13.1:
|
||||||
|
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||||
|
|
||||||
|
/react-is/17.0.2:
|
||||||
|
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/react-router-dom/5.3.4_react@17.0.2:
|
||||||
|
resolution: {integrity: sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=15'
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.21.0
|
||||||
|
history: 4.10.1
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 17.0.2
|
||||||
|
react-router: 5.3.4_react@17.0.2
|
||||||
|
tiny-invariant: 1.3.1
|
||||||
|
tiny-warning: 1.0.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/react-router/5.3.4_react@17.0.2:
|
||||||
|
resolution: {integrity: sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=15'
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.21.0
|
||||||
|
history: 4.10.1
|
||||||
|
hoist-non-react-statics: 3.3.2
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
path-to-regexp: 1.8.0
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 17.0.2
|
||||||
|
react-is: 16.13.1
|
||||||
|
tiny-invariant: 1.3.1
|
||||||
|
tiny-warning: 1.0.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/react/17.0.2:
|
||||||
|
resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dependencies:
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
object-assign: 4.1.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/regenerator-runtime/0.13.11:
|
||||||
|
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/resolve-pathname/3.0.0:
|
||||||
|
resolution: {integrity: sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/scheduler/0.20.2:
|
||||||
|
resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==}
|
||||||
|
dependencies:
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
object-assign: 4.1.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/shallowequal/1.1.0:
|
||||||
|
resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/styled-components/5.3.9_fane7jikarojcev26y27hpbhu4:
|
||||||
|
resolution: {integrity: sha512-Aj3kb13B75DQBo2oRwRa/APdB5rSmwUfN5exyarpX+x/tlM/rwZA2vVk2vQgVSP6WKaZJHWwiFrzgHt+CLtB4A==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>= 16.8.0'
|
||||||
|
react-dom: '>= 16.8.0'
|
||||||
|
react-is: '>= 16.8.0'
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-module-imports': 7.18.6
|
||||||
|
'@babel/traverse': 7.21.3_supports-color@5.5.0
|
||||||
|
'@emotion/is-prop-valid': 1.2.0
|
||||||
|
'@emotion/stylis': 0.8.5
|
||||||
|
'@emotion/unitless': 0.7.5
|
||||||
|
babel-plugin-styled-components: 2.0.7_styled-components@5.3.9
|
||||||
|
css-to-react-native: 3.2.0
|
||||||
|
hoist-non-react-statics: 3.3.2
|
||||||
|
react: 17.0.2
|
||||||
|
react-dom: 17.0.2_react@17.0.2
|
||||||
|
react-is: 17.0.2
|
||||||
|
shallowequal: 1.1.0
|
||||||
|
supports-color: 5.5.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/supports-color/5.5.0:
|
||||||
|
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dependencies:
|
||||||
|
has-flag: 3.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/tiny-invariant/1.3.1:
|
||||||
|
resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/tiny-warning/1.0.3:
|
||||||
|
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/to-fast-properties/2.0.0:
|
||||||
|
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/tr46/0.0.3:
|
||||||
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/typescript/4.9.5:
|
||||||
|
resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==}
|
||||||
|
engines: {node: '>=4.2.0'}
|
||||||
|
hasBin: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/value-equal/1.0.1:
|
||||||
|
resolution: {integrity: sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/webidl-conversions/3.0.1:
|
||||||
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/whatwg-url/5.0.0:
|
||||||
|
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||||
|
dependencies:
|
||||||
|
tr46: 0.0.3
|
||||||
|
webidl-conversions: 3.0.1
|
||||||
|
dev: false
|
|
@ -27,13 +27,12 @@ export default function App() {
|
||||||
if (redirectURL) {
|
if (redirectURL) {
|
||||||
urlProps.redirectURL = redirectURL;
|
urlProps.redirectURL = redirectURL;
|
||||||
} else {
|
} else {
|
||||||
urlProps.redirectURL = window.location.origin + '/app';
|
urlProps.redirectURL = window.location.href;
|
||||||
}
|
}
|
||||||
const globalState: Record<string, string> = {
|
const globalState: Record<string, string> = {
|
||||||
...window['__authorizer__'],
|
...window['__authorizer__'],
|
||||||
...urlProps,
|
...urlProps,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -54,7 +53,7 @@ export default function App() {
|
||||||
<img
|
<img
|
||||||
src={`${globalState.organizationLogo}`}
|
src={`${globalState.organizationLogo}`}
|
||||||
alt="logo"
|
alt="logo"
|
||||||
style={{ height: 60, width: 60, objectFit: 'cover' }}
|
style={{ height: 60, objectFit: 'cover' }}
|
||||||
/>
|
/>
|
||||||
<h1>{globalState.organizationName}</h1>
|
<h1>{globalState.organizationName}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -59,7 +59,9 @@ export default function Root({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (token) {
|
if (token) {
|
||||||
let redirectURL = config.redirectURL || '/app';
|
let redirectURL = config.redirectURL || '/app';
|
||||||
let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}`;
|
// let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}`;
|
||||||
|
// Note: If OIDC breaks in the future, use the above params
|
||||||
|
let params = `state=${globalState.state}`;
|
||||||
|
|
||||||
if (code !== '') {
|
if (code !== '') {
|
||||||
params += `&code=${code}`;
|
params += `&code=${code}`;
|
||||||
|
|
|
@ -32,20 +32,25 @@ const FooterContent = styled.div`
|
||||||
export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
||||||
const { config } = useAuthorizer();
|
const { config } = useAuthorizer();
|
||||||
const [view, setView] = useState<VIEW_TYPES>(VIEW_TYPES.LOGIN);
|
const [view, setView] = useState<VIEW_TYPES>(VIEW_TYPES.LOGIN);
|
||||||
|
const isBasicAuth = config.is_basic_authentication_enabled;
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{view === VIEW_TYPES.LOGIN && (
|
{view === VIEW_TYPES.LOGIN && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<h1 style={{ textAlign: 'center' }}>Login</h1>
|
<h1 style={{ textAlign: 'center' }}>Login</h1>
|
||||||
<br />
|
|
||||||
<AuthorizerSocialLogin urlProps={urlProps} />
|
<AuthorizerSocialLogin urlProps={urlProps} />
|
||||||
{config.is_basic_authentication_enabled &&
|
<br />
|
||||||
|
{(config.is_basic_authentication_enabled ||
|
||||||
|
config.is_mobile_basic_authentication_enabled) &&
|
||||||
!config.is_magic_link_login_enabled && (
|
!config.is_magic_link_login_enabled && (
|
||||||
<AuthorizerBasicAuthLogin urlProps={urlProps} />
|
<AuthorizerBasicAuthLogin urlProps={urlProps} />
|
||||||
)}
|
)}
|
||||||
{config.is_magic_link_login_enabled && (
|
{config.is_magic_link_login_enabled && (
|
||||||
<AuthorizerMagicLinkLogin urlProps={urlProps} />
|
<AuthorizerMagicLinkLogin urlProps={urlProps} />
|
||||||
)}
|
)}
|
||||||
|
{(config.is_basic_authentication_enabled ||
|
||||||
|
config.is_mobile_basic_authentication_enabled) &&
|
||||||
|
!config.is_magic_link_login_enabled && (
|
||||||
<Footer>
|
<Footer>
|
||||||
<Link
|
<Link
|
||||||
to="#"
|
to="#"
|
||||||
|
@ -55,6 +60,7 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
||||||
Forgot Password?
|
Forgot Password?
|
||||||
</Link>
|
</Link>
|
||||||
</Footer>
|
</Footer>
|
||||||
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
{view === VIEW_TYPES.FORGOT_PASSWORD && (
|
{view === VIEW_TYPES.FORGOT_PASSWORD && (
|
||||||
|
@ -65,6 +71,9 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
||||||
...urlProps,
|
...urlProps,
|
||||||
redirect_uri: `${window.location.origin}/app/reset-password`,
|
redirect_uri: `${window.location.origin}/app/reset-password`,
|
||||||
}}
|
}}
|
||||||
|
onPasswordReset={() => {
|
||||||
|
setView(VIEW_TYPES.LOGIN);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Footer>
|
<Footer>
|
||||||
<Link
|
<Link
|
||||||
|
@ -81,7 +90,7 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
||||||
!config.is_magic_link_login_enabled &&
|
!config.is_magic_link_login_enabled &&
|
||||||
config.is_sign_up_enabled && (
|
config.is_sign_up_enabled && (
|
||||||
<FooterContent>
|
<FooterContent>
|
||||||
Don't have an account? <Link to="/app/signup"> Sign Up</Link>
|
Don't have an account? <Link to="/app/signup"> Sign Up</Link>
|
||||||
</FooterContent>
|
</FooterContent>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import { AuthorizerSignup } from '@authorizerdev/authorizer-react';
|
import { AuthorizerSignup, AuthorizerSocialLogin } from '@authorizerdev/authorizer-react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ export default function SignUp({
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<h1 style={{ textAlign: 'center' }}>Sign Up</h1>
|
<h1 style={{ textAlign: 'center' }}>Sign Up</h1>
|
||||||
<br />
|
<br />
|
||||||
|
<AuthorizerSocialLogin urlProps={urlProps} />
|
||||||
<AuthorizerSignup urlProps={urlProps} />
|
<AuthorizerSignup urlProps={urlProps} />
|
||||||
<FooterContent>
|
<FooterContent>
|
||||||
Already have an account? <Link to="/app"> Login</Link>
|
Already have an account? <Link to="/app"> Login</Link>
|
||||||
|
|
237
app/yarn.lock
237
app/yarn.lock
|
@ -2,35 +2,38 @@
|
||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"@authorizerdev/authorizer-js@^1.1.4":
|
"@authorizerdev/authorizer-js@^2.0.3":
|
||||||
version "1.1.4"
|
version "2.0.3"
|
||||||
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.1.4.tgz"
|
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-2.0.3.tgz"
|
||||||
integrity sha512-oLp3XMYU9xHlg5urpAOaw6NrKQ07SaI8oAi1BAMHZWivv5qi2V+6roey0y9MdvCUmsMULBBcZg87kuoMTXRJOw==
|
integrity sha512-uencwr3Ea8mwfxVKDFf2ITRCRSmzvua+O2voRuiWQORtRQTgZQjkN3M+IEkEj+WP9M1iFIl+NDgzECsp8ptC/A==
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-fetch "^3.1.5"
|
cross-fetch "^3.1.5"
|
||||||
|
|
||||||
"@authorizerdev/authorizer-react@^1.1.8":
|
"@authorizerdev/authorizer-react@^1.3.2":
|
||||||
version "1.1.8"
|
version "1.3.2"
|
||||||
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.8.tgz"
|
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.3.2.tgz"
|
||||||
integrity sha512-5v9Zc7ZxiEQEHT1Fwj1jvEemdckcrn7mZPkdmJ/z0YOWNbF20ZpM4WsfrtJB+d293m7Rb1QKwzdFPkYINMh5tw==
|
integrity sha512-3kMAygHBCa8Fc9Oo0lz1k88r+Pd6kx1PSn3NMYLwxQXy2jRt4xWn7iuGn+SDGFs3DzofaN71I61gRwQ+6dO1rw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@authorizerdev/authorizer-js" "^1.1.4"
|
"@authorizerdev/authorizer-js" "^2.0.3"
|
||||||
|
validator "^13.11.0"
|
||||||
|
|
||||||
"@babel/code-frame@^7.16.7":
|
"@babel/code-frame@^7.22.13":
|
||||||
version "7.16.7"
|
version "7.22.13"
|
||||||
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz"
|
||||||
integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==
|
integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/highlight" "^7.16.7"
|
"@babel/highlight" "^7.22.13"
|
||||||
|
chalk "^2.4.2"
|
||||||
|
|
||||||
"@babel/generator@^7.16.8":
|
"@babel/generator@^7.23.0":
|
||||||
version "7.16.8"
|
version "7.23.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz"
|
resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz"
|
||||||
integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==
|
integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.8"
|
"@babel/types" "^7.23.0"
|
||||||
|
"@jridgewell/gen-mapping" "^0.3.2"
|
||||||
|
"@jridgewell/trace-mapping" "^0.3.17"
|
||||||
jsesc "^2.5.1"
|
jsesc "^2.5.1"
|
||||||
source-map "^0.5.0"
|
|
||||||
|
|
||||||
"@babel/helper-annotate-as-pure@^7.16.0":
|
"@babel/helper-annotate-as-pure@^7.16.0":
|
||||||
version "7.16.7"
|
version "7.16.7"
|
||||||
|
@ -39,35 +42,25 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.7"
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
"@babel/helper-environment-visitor@^7.16.7":
|
"@babel/helper-environment-visitor@^7.22.20":
|
||||||
version "7.16.7"
|
version "7.22.20"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz"
|
||||||
integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==
|
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
|
||||||
dependencies:
|
|
||||||
"@babel/types" "^7.16.7"
|
|
||||||
|
|
||||||
"@babel/helper-function-name@^7.16.7":
|
"@babel/helper-function-name@^7.23.0":
|
||||||
version "7.16.7"
|
version "7.23.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz"
|
||||||
integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==
|
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-get-function-arity" "^7.16.7"
|
"@babel/template" "^7.22.15"
|
||||||
"@babel/template" "^7.16.7"
|
"@babel/types" "^7.23.0"
|
||||||
"@babel/types" "^7.16.7"
|
|
||||||
|
|
||||||
"@babel/helper-get-function-arity@^7.16.7":
|
"@babel/helper-hoist-variables@^7.22.5":
|
||||||
version "7.16.7"
|
version "7.22.5"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz"
|
||||||
integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==
|
integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.7"
|
"@babel/types" "^7.22.5"
|
||||||
|
|
||||||
"@babel/helper-hoist-variables@^7.16.7":
|
|
||||||
version "7.16.7"
|
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz"
|
|
||||||
integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==
|
|
||||||
dependencies:
|
|
||||||
"@babel/types" "^7.16.7"
|
|
||||||
|
|
||||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.0":
|
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.0":
|
||||||
version "7.16.7"
|
version "7.16.7"
|
||||||
|
@ -76,31 +69,36 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.7"
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
"@babel/helper-split-export-declaration@^7.16.7":
|
"@babel/helper-split-export-declaration@^7.22.6":
|
||||||
version "7.16.7"
|
version "7.22.6"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz"
|
||||||
integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==
|
integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.7"
|
"@babel/types" "^7.22.5"
|
||||||
|
|
||||||
"@babel/helper-validator-identifier@^7.16.7":
|
"@babel/helper-string-parser@^7.22.5":
|
||||||
version "7.16.7"
|
version "7.22.5"
|
||||||
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz"
|
||||||
integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
|
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
|
||||||
|
|
||||||
"@babel/highlight@^7.16.7":
|
"@babel/helper-validator-identifier@^7.22.20":
|
||||||
version "7.16.10"
|
version "7.22.20"
|
||||||
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz"
|
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz"
|
||||||
integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==
|
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
|
||||||
|
|
||||||
|
"@babel/highlight@^7.22.13":
|
||||||
|
version "7.22.20"
|
||||||
|
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz"
|
||||||
|
integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-validator-identifier" "^7.16.7"
|
"@babel/helper-validator-identifier" "^7.22.20"
|
||||||
chalk "^2.0.0"
|
chalk "^2.4.2"
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
|
|
||||||
"@babel/parser@^7.16.10", "@babel/parser@^7.16.7":
|
"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
|
||||||
version "7.16.12"
|
version "7.23.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.16.12.tgz"
|
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz"
|
||||||
integrity sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A==
|
integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
|
||||||
|
|
||||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1":
|
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1":
|
||||||
version "7.14.8"
|
version "7.14.8"
|
||||||
|
@ -109,37 +107,38 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/template@^7.16.7":
|
"@babel/template@^7.22.15":
|
||||||
version "7.16.7"
|
version "7.22.15"
|
||||||
resolved "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz"
|
||||||
integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==
|
integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.16.7"
|
"@babel/code-frame" "^7.22.13"
|
||||||
"@babel/parser" "^7.16.7"
|
"@babel/parser" "^7.22.15"
|
||||||
"@babel/types" "^7.16.7"
|
"@babel/types" "^7.22.15"
|
||||||
|
|
||||||
"@babel/traverse@^7.4.5":
|
"@babel/traverse@^7.4.5":
|
||||||
version "7.16.10"
|
version "7.23.2"
|
||||||
resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.10.tgz"
|
resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz"
|
||||||
integrity sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw==
|
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.16.7"
|
"@babel/code-frame" "^7.22.13"
|
||||||
"@babel/generator" "^7.16.8"
|
"@babel/generator" "^7.23.0"
|
||||||
"@babel/helper-environment-visitor" "^7.16.7"
|
"@babel/helper-environment-visitor" "^7.22.20"
|
||||||
"@babel/helper-function-name" "^7.16.7"
|
"@babel/helper-function-name" "^7.23.0"
|
||||||
"@babel/helper-hoist-variables" "^7.16.7"
|
"@babel/helper-hoist-variables" "^7.22.5"
|
||||||
"@babel/helper-split-export-declaration" "^7.16.7"
|
"@babel/helper-split-export-declaration" "^7.22.6"
|
||||||
"@babel/parser" "^7.16.10"
|
"@babel/parser" "^7.23.0"
|
||||||
"@babel/types" "^7.16.8"
|
"@babel/types" "^7.23.0"
|
||||||
debug "^4.1.0"
|
debug "^4.1.0"
|
||||||
globals "^11.1.0"
|
globals "^11.1.0"
|
||||||
|
|
||||||
"@babel/types@^7.16.7", "@babel/types@^7.16.8":
|
"@babel/types@^7.16.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
|
||||||
version "7.16.8"
|
version "7.23.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz"
|
resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz"
|
||||||
integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==
|
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-validator-identifier" "^7.16.7"
|
"@babel/helper-string-parser" "^7.22.5"
|
||||||
|
"@babel/helper-validator-identifier" "^7.22.20"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@emotion/is-prop-valid@^0.8.8":
|
"@emotion/is-prop-valid@^0.8.8":
|
||||||
|
@ -164,6 +163,38 @@
|
||||||
resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz"
|
resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz"
|
||||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||||
|
|
||||||
|
"@jridgewell/gen-mapping@^0.3.2":
|
||||||
|
version "0.3.3"
|
||||||
|
resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz"
|
||||||
|
integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
|
||||||
|
dependencies:
|
||||||
|
"@jridgewell/set-array" "^1.0.1"
|
||||||
|
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||||
|
"@jridgewell/trace-mapping" "^0.3.9"
|
||||||
|
|
||||||
|
"@jridgewell/resolve-uri@^3.1.0":
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz"
|
||||||
|
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
|
||||||
|
|
||||||
|
"@jridgewell/set-array@^1.0.1":
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz"
|
||||||
|
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
||||||
|
|
||||||
|
"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
|
||||||
|
version "1.4.15"
|
||||||
|
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"
|
||||||
|
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
|
||||||
|
|
||||||
|
"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
|
||||||
|
version "0.3.20"
|
||||||
|
resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz"
|
||||||
|
integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
|
||||||
|
dependencies:
|
||||||
|
"@jridgewell/resolve-uri" "^3.1.0"
|
||||||
|
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||||
|
|
||||||
"@types/history@*":
|
"@types/history@*":
|
||||||
version "4.7.9"
|
version "4.7.9"
|
||||||
resolved "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz"
|
resolved "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz"
|
||||||
|
@ -256,7 +287,7 @@ camelize@^1.0.0:
|
||||||
resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz"
|
||||||
integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
|
integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
|
||||||
|
|
||||||
chalk@^2.0.0:
|
chalk@^2.4.2:
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
||||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||||
|
@ -275,14 +306,14 @@ color-convert@^1.9.0:
|
||||||
color-name@1.1.3:
|
color-name@1.1.3:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
||||||
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
|
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||||
|
|
||||||
cross-fetch@^3.1.5:
|
cross-fetch@^3.1.5:
|
||||||
version "3.1.5"
|
version "3.1.8"
|
||||||
resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz"
|
resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz"
|
||||||
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
|
integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==
|
||||||
dependencies:
|
dependencies:
|
||||||
node-fetch "2.6.7"
|
node-fetch "^2.6.12"
|
||||||
|
|
||||||
css-color-keywords@^1.0.0:
|
css-color-keywords@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
|
@ -318,7 +349,7 @@ esbuild@^0.12.17:
|
||||||
escape-string-regexp@^1.0.5:
|
escape-string-regexp@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
|
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
|
||||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
|
||||||
|
|
||||||
globals@^11.1.0:
|
globals@^11.1.0:
|
||||||
version "11.12.0"
|
version "11.12.0"
|
||||||
|
@ -389,10 +420,10 @@ ms@2.1.2:
|
||||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
||||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||||
|
|
||||||
node-fetch@2.6.7:
|
node-fetch@^2.6.12:
|
||||||
version "2.6.7"
|
version "2.7.0"
|
||||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz"
|
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz"
|
||||||
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-url "^5.0.0"
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
|
@ -516,11 +547,6 @@ shallowequal@^1.1.0:
|
||||||
resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz"
|
resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz"
|
||||||
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
|
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
|
||||||
|
|
||||||
source-map@^0.5.0:
|
|
||||||
version "0.5.7"
|
|
||||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
|
|
||||||
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
|
|
||||||
|
|
||||||
styled-components@^5.3.0, "styled-components@>= 2":
|
styled-components@^5.3.0, "styled-components@>= 2":
|
||||||
version "5.3.3"
|
version "5.3.3"
|
||||||
resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz"
|
resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz"
|
||||||
|
@ -569,6 +595,11 @@ typescript@^4.3.5:
|
||||||
resolved "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz"
|
resolved "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz"
|
||||||
integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==
|
integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==
|
||||||
|
|
||||||
|
validator@^13.11.0:
|
||||||
|
version "13.11.0"
|
||||||
|
resolved "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz"
|
||||||
|
integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==
|
||||||
|
|
||||||
value-equal@^1.0.1:
|
value-equal@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz"
|
resolved "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz"
|
||||||
|
|
2480
dashboard/package-lock.json
generated
2480
dashboard/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
BIN
dashboard/public/roblox.png
Normal file
BIN
dashboard/public/roblox.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
|
@ -126,6 +126,22 @@ const EmailConfigurations = ({
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
|
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||||
|
<Text fontSize="sm">Sender Name:</Text>
|
||||||
|
</Flex>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={variables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={TextInputType.SENDER_NAME}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Flex>
|
||||||
</Stack>
|
</Stack>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,105 +8,154 @@ const Features = ({ variables, setVariables }: any) => {
|
||||||
<div>
|
<div>
|
||||||
{' '}
|
{' '}
|
||||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||||
Disable Features
|
Features
|
||||||
</Text>
|
</Text>
|
||||||
<Stack spacing={6}>
|
<Stack spacing={6}>
|
||||||
<Flex>
|
<Flex>
|
||||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
<Text fontSize="sm">Disable Login Page:</Text>
|
<Text fontSize="sm">Login Page:</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex justifyContent="start">
|
<Flex justifyContent="start">
|
||||||
<InputField
|
<InputField
|
||||||
variables={variables}
|
variables={variables}
|
||||||
setVariables={setVariables}
|
setVariables={setVariables}
|
||||||
inputType={SwitchInputType.DISABLE_LOGIN_PAGE}
|
inputType={SwitchInputType.DISABLE_LOGIN_PAGE}
|
||||||
|
hasReversedValue
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex>
|
<Flex>
|
||||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
<Text fontSize="sm">Disable Email Verification:</Text>
|
<Text fontSize="sm">Email Verification:</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex justifyContent="start">
|
<Flex justifyContent="start">
|
||||||
<InputField
|
<InputField
|
||||||
variables={variables}
|
variables={variables}
|
||||||
setVariables={setVariables}
|
setVariables={setVariables}
|
||||||
inputType={SwitchInputType.DISABLE_EMAIL_VERIFICATION}
|
inputType={SwitchInputType.DISABLE_EMAIL_VERIFICATION}
|
||||||
|
hasReversedValue
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex>
|
<Flex>
|
||||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
<Text fontSize="sm">Disable Magic Login Link:</Text>
|
<Text fontSize="sm">Magic Login Link:</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex justifyContent="start">
|
<Flex justifyContent="start">
|
||||||
<InputField
|
<InputField
|
||||||
variables={variables}
|
variables={variables}
|
||||||
setVariables={setVariables}
|
setVariables={setVariables}
|
||||||
inputType={SwitchInputType.DISABLE_MAGIC_LINK_LOGIN}
|
inputType={SwitchInputType.DISABLE_MAGIC_LINK_LOGIN}
|
||||||
|
hasReversedValue
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex>
|
<Flex>
|
||||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
<Text fontSize="sm">Disable Basic Authentication:</Text>
|
<Text fontSize="sm">Email Basic Authentication:</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex justifyContent="start">
|
<Flex justifyContent="start">
|
||||||
<InputField
|
<InputField
|
||||||
variables={variables}
|
variables={variables}
|
||||||
setVariables={setVariables}
|
setVariables={setVariables}
|
||||||
inputType={SwitchInputType.DISABLE_BASIC_AUTHENTICATION}
|
inputType={SwitchInputType.DISABLE_BASIC_AUTHENTICATION}
|
||||||
|
hasReversedValue
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex>
|
<Flex>
|
||||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
<Text fontSize="sm">Disable Sign Up:</Text>
|
<Text fontSize="sm">Mobile Basic Authentication:</Text>
|
||||||
|
</Flex>
|
||||||
|
<Flex justifyContent="start">
|
||||||
|
<InputField
|
||||||
|
variables={variables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={SwitchInputType.DISABLE_MOBILE_BASIC_AUTHENTICATION}
|
||||||
|
hasReversedValue
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
<Flex>
|
||||||
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
|
<Text fontSize="sm">Sign Up:</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex justifyContent="start" mb={3}>
|
<Flex justifyContent="start" mb={3}>
|
||||||
<InputField
|
<InputField
|
||||||
variables={variables}
|
variables={variables}
|
||||||
setVariables={setVariables}
|
setVariables={setVariables}
|
||||||
inputType={SwitchInputType.DISABLE_SIGN_UP}
|
inputType={SwitchInputType.DISABLE_SIGN_UP}
|
||||||
|
hasReversedValue
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex>
|
<Flex>
|
||||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
<Text fontSize="sm">Disable Strong Password:</Text>
|
<Text fontSize="sm">Strong Password:</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex justifyContent="start" mb={3}>
|
<Flex justifyContent="start" mb={3}>
|
||||||
<InputField
|
<InputField
|
||||||
variables={variables}
|
variables={variables}
|
||||||
setVariables={setVariables}
|
setVariables={setVariables}
|
||||||
inputType={SwitchInputType.DISABLE_STRONG_PASSWORD}
|
inputType={SwitchInputType.DISABLE_STRONG_PASSWORD}
|
||||||
|
hasReversedValue
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="center">
|
||||||
<Flex w="100%" alignItems="baseline" flexDir="column">
|
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||||
<Text fontSize="sm">
|
<Text fontSize="sm">Multi Factor Authentication (MFA):</Text>
|
||||||
Disable Multi Factor Authentication (MFA):
|
|
||||||
</Text>
|
|
||||||
<Text fontSize="x-small">
|
<Text fontSize="x-small">
|
||||||
Note: Enabling this will ignore Enforcing MFA shown below and will
|
Note: Enabling this will ignore Enforcing MFA shown below and will
|
||||||
also ignore the user MFA setting.
|
also ignore the user MFA setting.
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex justifyContent="start" mb={3}>
|
<Flex justifyContent="start" mb={3}>
|
||||||
<InputField
|
<InputField
|
||||||
variables={variables}
|
variables={variables}
|
||||||
setVariables={setVariables}
|
setVariables={setVariables}
|
||||||
inputType={SwitchInputType.DISABLE_MULTI_FACTOR_AUTHENTICATION}
|
inputType={SwitchInputType.DISABLE_MULTI_FACTOR_AUTHENTICATION}
|
||||||
|
hasReversedValue
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Stack>
|
{!variables.DISABLE_MULTI_FACTOR_AUTHENTICATION && (
|
||||||
<Divider paddingY={5} />
|
<Flex alignItems="center">
|
||||||
<Text fontSize="md" paddingTop={5} fontWeight="bold" mb={5}>
|
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||||
Enable Features
|
<Text fontSize="sm">Time Based OTP (TOTP):</Text>
|
||||||
</Text>
|
<Text fontSize="x-small">Note: to enable totp mfa</Text>
|
||||||
<Stack spacing={6}>
|
</Flex>
|
||||||
|
|
||||||
|
<Flex justifyContent="start" mb={3}>
|
||||||
|
<InputField
|
||||||
|
variables={variables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={SwitchInputType.DISABLE_TOTP_LOGIN}
|
||||||
|
hasReversedValue
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
{!variables.DISABLE_MULTI_FACTOR_AUTHENTICATION && (
|
||||||
|
<Flex alignItems="center">
|
||||||
|
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||||
|
<Text fontSize="sm">EMAIL OTP:</Text>
|
||||||
|
<Text fontSize="x-small">Note: to enable email otp mfa</Text>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex justifyContent="start" mb={3}>
|
||||||
|
<InputField
|
||||||
|
variables={variables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={SwitchInputType.DISABLE_MAIL_OTP_LOGIN}
|
||||||
|
hasReversedValue
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="center">
|
||||||
<Flex w="100%" alignItems="baseline" flexDir="column">
|
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||||
<Text fontSize="sm">
|
<Text fontSize="sm">
|
||||||
|
@ -125,6 +174,19 @@ const Features = ({ variables, setVariables }: any) => {
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex>
|
||||||
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
|
<Text fontSize="sm">Playground:</Text>
|
||||||
|
</Flex>
|
||||||
|
<Flex justifyContent="start">
|
||||||
|
<InputField
|
||||||
|
variables={variables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={SwitchInputType.DISABLE_PLAYGROUND}
|
||||||
|
hasReversedValue
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Divider paddingY={5} />
|
<Divider paddingY={5} />
|
||||||
<Text fontSize="md" paddingTop={5} fontWeight="bold" mb={5}>
|
<Text fontSize="md" paddingTop={5} fontWeight="bold" mb={5}>
|
||||||
|
|
|
@ -61,7 +61,6 @@ const JSTConfigurations = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{' '}
|
|
||||||
<Flex
|
<Flex
|
||||||
borderRadius={5}
|
borderRadius={5}
|
||||||
width="100%"
|
width="100%"
|
||||||
|
|
|
@ -17,8 +17,16 @@ import {
|
||||||
FaApple,
|
FaApple,
|
||||||
FaTwitter,
|
FaTwitter,
|
||||||
FaMicrosoft,
|
FaMicrosoft,
|
||||||
|
FaTwitch,
|
||||||
|
FaDiscord,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import { TextInputType, HiddenInputType } from '../../constants';
|
import {
|
||||||
|
TextInputType,
|
||||||
|
HiddenInputType,
|
||||||
|
ResponseModes,
|
||||||
|
ResponseTypes,
|
||||||
|
SelectInputType,
|
||||||
|
} from '../../constants';
|
||||||
|
|
||||||
const OAuthConfig = ({
|
const OAuthConfig = ({
|
||||||
envVariables,
|
envVariables,
|
||||||
|
@ -70,6 +78,42 @@ const OAuthConfig = ({
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
|
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||||
|
<Text fontSize="sm">Default Response Type:</Text>
|
||||||
|
</Flex>
|
||||||
|
<Flex
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '2'}
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={SelectInputType.DEFAULT_AUTHORIZE_RESPONSE_TYPE}
|
||||||
|
value={SelectInputType}
|
||||||
|
options={ResponseTypes}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
|
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||||
|
<Text fontSize="sm">Default Response Mode:</Text>
|
||||||
|
</Flex>
|
||||||
|
<Flex
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '2'}
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={SelectInputType.DEFAULT_AUTHORIZE_RESPONSE_MODE}
|
||||||
|
value={SelectInputType}
|
||||||
|
options={ResponseModes}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Divider mt={5} mb={2} color="blackAlpha.700" />
|
<Divider mt={5} mb={2} color="blackAlpha.700" />
|
||||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={4}>
|
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={4}>
|
||||||
|
@ -266,6 +310,44 @@ const OAuthConfig = ({
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||||
|
h="35px"
|
||||||
|
marginRight="1.5%"
|
||||||
|
border="1px solid #3b5998"
|
||||||
|
borderRadius="5px"
|
||||||
|
>
|
||||||
|
<FaDiscord style={{ color: '#7289da' }} />
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
marginRight="1.5%"
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={TextInputType.DISCORD_CLIENT_ID}
|
||||||
|
placeholder="Discord 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.DISCORD_CLIENT_SECRET}
|
||||||
|
placeholder="Discord Client Secret"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Flex>
|
||||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
<Center
|
<Center
|
||||||
w={isNotSmallerScreen ? '55px' : '35px'}
|
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||||
|
@ -355,6 +437,85 @@ const OAuthConfig = ({
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||||
|
h="35px"
|
||||||
|
marginRight="1.5%"
|
||||||
|
border="1px solid #3b5998"
|
||||||
|
borderRadius="5px"
|
||||||
|
>
|
||||||
|
<FaTwitch />
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
marginRight="1.5%"
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={TextInputType.TWITCH_CLIENT_ID}
|
||||||
|
placeholder="Twitch 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.TWITCH_CLIENT_SECRET}
|
||||||
|
placeholder="Twitch 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"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="https://authorizer.dev/_next/image?url=%2Fimages%2Froblox.png&w=25&q=25"
|
||||||
|
alt="Roblox"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
marginRight="1.5%"
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={TextInputType.ROBLOX_CLIENT_ID}
|
||||||
|
placeholder="Roblox 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.ROBLOX_CLIENT_SECRET}
|
||||||
|
placeholder="Roblox Client Secret"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Flex>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -48,6 +48,8 @@ const InputField = ({
|
||||||
fieldVisibility,
|
fieldVisibility,
|
||||||
setFieldVisibility,
|
setFieldVisibility,
|
||||||
availableRoles,
|
availableRoles,
|
||||||
|
// This prop is added to improve the user experience for the boolean ENV variable having `DISABLE_` prefix, as those values need to be considered in inverted form.
|
||||||
|
hasReversedValue,
|
||||||
...downshiftProps
|
...downshiftProps
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const props = {
|
const props = {
|
||||||
|
@ -398,7 +400,9 @@ const InputField = ({
|
||||||
</Text>
|
</Text>
|
||||||
<Switch
|
<Switch
|
||||||
size="md"
|
size="md"
|
||||||
isChecked={variables[inputType]}
|
isChecked={
|
||||||
|
hasReversedValue ? !variables[inputType] : variables[inputType]
|
||||||
|
}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setVariables({
|
setVariables({
|
||||||
...variables,
|
...variables,
|
||||||
|
|
|
@ -63,6 +63,7 @@ interface headersValidatorDataType {
|
||||||
interface selecetdWebhookDataTypes {
|
interface selecetdWebhookDataTypes {
|
||||||
[WebhookInputDataFields.ID]: string;
|
[WebhookInputDataFields.ID]: string;
|
||||||
[WebhookInputDataFields.EVENT_NAME]: string;
|
[WebhookInputDataFields.EVENT_NAME]: string;
|
||||||
|
[WebhookInputDataFields.EVENT_DESCRIPTION]?: string;
|
||||||
[WebhookInputDataFields.ENDPOINT]: string;
|
[WebhookInputDataFields.ENDPOINT]: string;
|
||||||
[WebhookInputDataFields.ENABLED]: boolean;
|
[WebhookInputDataFields.ENABLED]: boolean;
|
||||||
[WebhookInputDataFields.HEADERS]?: Record<string, string>;
|
[WebhookInputDataFields.HEADERS]?: Record<string, string>;
|
||||||
|
@ -86,6 +87,7 @@ const initHeadersValidatorData: headersValidatorDataType = {
|
||||||
|
|
||||||
interface webhookDataType {
|
interface webhookDataType {
|
||||||
[WebhookInputDataFields.EVENT_NAME]: string;
|
[WebhookInputDataFields.EVENT_NAME]: string;
|
||||||
|
[WebhookInputDataFields.EVENT_DESCRIPTION]?: string;
|
||||||
[WebhookInputDataFields.ENDPOINT]: string;
|
[WebhookInputDataFields.ENDPOINT]: string;
|
||||||
[WebhookInputDataFields.ENABLED]: boolean;
|
[WebhookInputDataFields.ENABLED]: boolean;
|
||||||
[WebhookInputDataFields.HEADERS]: headersDataType[];
|
[WebhookInputDataFields.HEADERS]: headersDataType[];
|
||||||
|
@ -98,6 +100,7 @@ interface validatorDataType {
|
||||||
|
|
||||||
const initWebhookData: webhookDataType = {
|
const initWebhookData: webhookDataType = {
|
||||||
[WebhookInputDataFields.EVENT_NAME]: webhookEventNames['User login'],
|
[WebhookInputDataFields.EVENT_NAME]: webhookEventNames['User login'],
|
||||||
|
[WebhookInputDataFields.EVENT_DESCRIPTION]: '',
|
||||||
[WebhookInputDataFields.ENDPOINT]: '',
|
[WebhookInputDataFields.ENDPOINT]: '',
|
||||||
[WebhookInputDataFields.ENABLED]: true,
|
[WebhookInputDataFields.ENABLED]: true,
|
||||||
[WebhookInputDataFields.HEADERS]: [{ ...initHeadersData }],
|
[WebhookInputDataFields.HEADERS]: [{ ...initHeadersData }],
|
||||||
|
@ -144,6 +147,9 @@ const UpdateWebhookModal = ({
|
||||||
case WebhookInputDataFields.EVENT_NAME:
|
case WebhookInputDataFields.EVENT_NAME:
|
||||||
setWebhook({ ...webhook, [inputType]: value });
|
setWebhook({ ...webhook, [inputType]: value });
|
||||||
break;
|
break;
|
||||||
|
case WebhookInputDataFields.EVENT_DESCRIPTION:
|
||||||
|
setWebhook({ ...webhook, [inputType]: value });
|
||||||
|
break;
|
||||||
case WebhookInputDataFields.ENDPOINT:
|
case WebhookInputDataFields.ENDPOINT:
|
||||||
setWebhook({ ...webhook, [inputType]: value });
|
setWebhook({ ...webhook, [inputType]: value });
|
||||||
setValidator({
|
setValidator({
|
||||||
|
@ -246,6 +252,8 @@ const UpdateWebhookModal = ({
|
||||||
let params: any = {
|
let params: any = {
|
||||||
[WebhookInputDataFields.EVENT_NAME]:
|
[WebhookInputDataFields.EVENT_NAME]:
|
||||||
webhook[WebhookInputDataFields.EVENT_NAME],
|
webhook[WebhookInputDataFields.EVENT_NAME],
|
||||||
|
[WebhookInputDataFields.EVENT_DESCRIPTION]:
|
||||||
|
webhook[WebhookInputDataFields.EVENT_DESCRIPTION],
|
||||||
[WebhookInputDataFields.ENDPOINT]:
|
[WebhookInputDataFields.ENDPOINT]:
|
||||||
webhook[WebhookInputDataFields.ENDPOINT],
|
webhook[WebhookInputDataFields.ENDPOINT],
|
||||||
[WebhookInputDataFields.ENABLED]: webhook[WebhookInputDataFields.ENABLED],
|
[WebhookInputDataFields.ENABLED]: webhook[WebhookInputDataFields.ENABLED],
|
||||||
|
@ -402,7 +410,9 @@ const UpdateWebhookModal = ({
|
||||||
<Flex flex="3">
|
<Flex flex="3">
|
||||||
<Select
|
<Select
|
||||||
size="md"
|
size="md"
|
||||||
value={webhook[WebhookInputDataFields.EVENT_NAME]}
|
value={
|
||||||
|
webhook[WebhookInputDataFields.EVENT_NAME].split('-')[0]
|
||||||
|
}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
inputChangehandler(
|
inputChangehandler(
|
||||||
WebhookInputDataFields.EVENT_NAME,
|
WebhookInputDataFields.EVENT_NAME,
|
||||||
|
@ -420,6 +430,30 @@ const UpdateWebhookModal = ({
|
||||||
</Select>
|
</Select>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex
|
||||||
|
width="100%"
|
||||||
|
justifyContent="start"
|
||||||
|
alignItems="center"
|
||||||
|
marginBottom="5%"
|
||||||
|
>
|
||||||
|
<Flex flex="1">Event Description</Flex>
|
||||||
|
<Flex flex="3">
|
||||||
|
<InputGroup size="md">
|
||||||
|
<Input
|
||||||
|
pr="4.5rem"
|
||||||
|
type="text"
|
||||||
|
placeholder="User event"
|
||||||
|
value={webhook[WebhookInputDataFields.EVENT_DESCRIPTION]}
|
||||||
|
onChange={(e) =>
|
||||||
|
inputChangehandler(
|
||||||
|
WebhookInputDataFields.EVENT_DESCRIPTION,
|
||||||
|
e.currentTarget.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</InputGroup>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
<Flex
|
<Flex
|
||||||
width="100%"
|
width="100%"
|
||||||
justifyContent="start"
|
justifyContent="start"
|
||||||
|
|
|
@ -9,9 +9,12 @@ export const TextInputType = {
|
||||||
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
|
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
|
||||||
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
|
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
|
||||||
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
|
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
|
||||||
|
DISCORD_CLIENT_ID: 'DISCORD_CLIENT_ID',
|
||||||
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
|
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
|
||||||
MICROSOFT_CLIENT_ID: 'MICROSOFT_CLIENT_ID',
|
MICROSOFT_CLIENT_ID: 'MICROSOFT_CLIENT_ID',
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: 'MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID',
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: 'MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID',
|
||||||
|
TWITCH_CLIENT_ID: 'TWITCH_CLIENT_ID',
|
||||||
|
ROBLOX_CLIENT_ID: 'ROBLOX_CLIENT_ID',
|
||||||
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
||||||
REDIS_URL: 'REDIS_URL',
|
REDIS_URL: 'REDIS_URL',
|
||||||
SMTP_HOST: 'SMTP_HOST',
|
SMTP_HOST: 'SMTP_HOST',
|
||||||
|
@ -19,6 +22,7 @@ export const TextInputType = {
|
||||||
SMTP_USERNAME: 'SMTP_USERNAME',
|
SMTP_USERNAME: 'SMTP_USERNAME',
|
||||||
SMTP_LOCAL_NAME: 'SMTP_LOCAL_NAME',
|
SMTP_LOCAL_NAME: 'SMTP_LOCAL_NAME',
|
||||||
SENDER_EMAIL: 'SENDER_EMAIL',
|
SENDER_EMAIL: 'SENDER_EMAIL',
|
||||||
|
SENDER_NAME: 'SENDER_NAME',
|
||||||
ORGANIZATION_NAME: 'ORGANIZATION_NAME',
|
ORGANIZATION_NAME: 'ORGANIZATION_NAME',
|
||||||
ORGANIZATION_LOGO: 'ORGANIZATION_LOGO',
|
ORGANIZATION_LOGO: 'ORGANIZATION_LOGO',
|
||||||
DATABASE_NAME: 'DATABASE_NAME',
|
DATABASE_NAME: 'DATABASE_NAME',
|
||||||
|
@ -39,8 +43,11 @@ export const HiddenInputType = {
|
||||||
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
|
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
|
||||||
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
|
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
|
||||||
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
||||||
|
DISCORD_CLIENT_SECRET: 'DISCORD_CLIENT_SECRET',
|
||||||
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
||||||
MICROSOFT_CLIENT_SECRET: 'MICROSOFT_CLIENT_SECRET',
|
MICROSOFT_CLIENT_SECRET: 'MICROSOFT_CLIENT_SECRET',
|
||||||
|
TWITCH_CLIENT_SECRET: 'TWITCH_CLIENT_SECRET',
|
||||||
|
ROBLOX_CLIENT_SECRET: 'ROBLOX_CLIENT_SECRET',
|
||||||
JWT_SECRET: 'JWT_SECRET',
|
JWT_SECRET: 'JWT_SECRET',
|
||||||
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
||||||
ADMIN_SECRET: 'ADMIN_SECRET',
|
ADMIN_SECRET: 'ADMIN_SECRET',
|
||||||
|
@ -57,6 +64,8 @@ export const ArrayInputType = {
|
||||||
export const SelectInputType = {
|
export const SelectInputType = {
|
||||||
JWT_TYPE: 'JWT_TYPE',
|
JWT_TYPE: 'JWT_TYPE',
|
||||||
GENDER: 'gender',
|
GENDER: 'gender',
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: 'DEFAULT_AUTHORIZE_RESPONSE_TYPE',
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_MODE: 'DEFAULT_AUTHORIZE_RESPONSE_MODE',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MultiSelectInputType = {
|
export const MultiSelectInputType = {
|
||||||
|
@ -76,11 +85,15 @@ export const SwitchInputType = {
|
||||||
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
|
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
|
||||||
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
|
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
|
||||||
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
|
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
|
||||||
|
DISABLE_MOBILE_BASIC_AUTHENTICATION: 'DISABLE_MOBILE_BASIC_AUTHENTICATION',
|
||||||
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
|
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
|
||||||
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
|
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
|
||||||
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
|
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
|
||||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: 'DISABLE_MULTI_FACTOR_AUTHENTICATION',
|
DISABLE_MULTI_FACTOR_AUTHENTICATION: 'DISABLE_MULTI_FACTOR_AUTHENTICATION',
|
||||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: 'ENFORCE_MULTI_FACTOR_AUTHENTICATION',
|
ENFORCE_MULTI_FACTOR_AUTHENTICATION: 'ENFORCE_MULTI_FACTOR_AUTHENTICATION',
|
||||||
|
DISABLE_PLAYGROUND: 'DISABLE_PLAYGROUND',
|
||||||
|
DISABLE_TOTP_LOGIN: 'DISABLE_TOTP_LOGIN',
|
||||||
|
DISABLE_MAIL_OTP_LOGIN: 'DISABLE_MAIL_OTP_LOGIN',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DateInputType = {
|
export const DateInputType = {
|
||||||
|
@ -121,11 +134,17 @@ export interface envVarTypes {
|
||||||
LINKEDIN_CLIENT_SECRET: string;
|
LINKEDIN_CLIENT_SECRET: string;
|
||||||
APPLE_CLIENT_ID: string;
|
APPLE_CLIENT_ID: string;
|
||||||
APPLE_CLIENT_SECRET: string;
|
APPLE_CLIENT_SECRET: string;
|
||||||
|
DISCORD_CLIENT_ID: string;
|
||||||
|
DISCORD_CLIENT_SECRET: string;
|
||||||
TWITTER_CLIENT_ID: string;
|
TWITTER_CLIENT_ID: string;
|
||||||
TWITTER_CLIENT_SECRET: string;
|
TWITTER_CLIENT_SECRET: string;
|
||||||
MICROSOFT_CLIENT_ID: string;
|
MICROSOFT_CLIENT_ID: string;
|
||||||
MICROSOFT_CLIENT_SECRET: string;
|
MICROSOFT_CLIENT_SECRET: string;
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: string;
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: string;
|
||||||
|
TWITCH_CLIENT_ID: string;
|
||||||
|
TWITCH_CLIENT_SECRET: string;
|
||||||
|
ROBLOX_CLIENT_ID: string;
|
||||||
|
ROBLOX_CLIENT_SECRET: string;
|
||||||
ROLES: [string] | [];
|
ROLES: [string] | [];
|
||||||
DEFAULT_ROLES: [string] | [];
|
DEFAULT_ROLES: [string] | [];
|
||||||
PROTECTED_ROLES: [string] | [];
|
PROTECTED_ROLES: [string] | [];
|
||||||
|
@ -141,6 +160,7 @@ export interface envVarTypes {
|
||||||
SMTP_PASSWORD: string;
|
SMTP_PASSWORD: string;
|
||||||
SMTP_LOCAL_NAME: string;
|
SMTP_LOCAL_NAME: string;
|
||||||
SENDER_EMAIL: string;
|
SENDER_EMAIL: string;
|
||||||
|
SENDER_NAME: string;
|
||||||
ALLOWED_ORIGINS: [string] | [];
|
ALLOWED_ORIGINS: [string] | [];
|
||||||
ORGANIZATION_NAME: string;
|
ORGANIZATION_NAME: string;
|
||||||
ORGANIZATION_LOGO: string;
|
ORGANIZATION_LOGO: string;
|
||||||
|
@ -152,6 +172,7 @@ export interface envVarTypes {
|
||||||
DISABLE_MAGIC_LINK_LOGIN: boolean;
|
DISABLE_MAGIC_LINK_LOGIN: boolean;
|
||||||
DISABLE_EMAIL_VERIFICATION: boolean;
|
DISABLE_EMAIL_VERIFICATION: boolean;
|
||||||
DISABLE_BASIC_AUTHENTICATION: boolean;
|
DISABLE_BASIC_AUTHENTICATION: boolean;
|
||||||
|
DISABLE_MOBILE_BASIC_AUTHENTICATION: boolean;
|
||||||
DISABLE_SIGN_UP: boolean;
|
DISABLE_SIGN_UP: boolean;
|
||||||
DISABLE_STRONG_PASSWORD: boolean;
|
DISABLE_STRONG_PASSWORD: boolean;
|
||||||
OLD_ADMIN_SECRET: string;
|
OLD_ADMIN_SECRET: string;
|
||||||
|
@ -161,6 +182,11 @@ export interface envVarTypes {
|
||||||
ACCESS_TOKEN_EXPIRY_TIME: string;
|
ACCESS_TOKEN_EXPIRY_TIME: string;
|
||||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: boolean;
|
DISABLE_MULTI_FACTOR_AUTHENTICATION: boolean;
|
||||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: boolean;
|
ENFORCE_MULTI_FACTOR_AUTHENTICATION: boolean;
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: string;
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_MODE: string;
|
||||||
|
DISABLE_PLAYGROUND: boolean;
|
||||||
|
DISABLE_TOTP_LOGIN: boolean;
|
||||||
|
DISABLE_MAIL_OTP_LOGIN: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const envSubViews = {
|
export const envSubViews = {
|
||||||
|
@ -179,6 +205,7 @@ export const envSubViews = {
|
||||||
|
|
||||||
export enum WebhookInputDataFields {
|
export enum WebhookInputDataFields {
|
||||||
ID = 'id',
|
ID = 'id',
|
||||||
|
EVENT_DESCRIPTION = 'event_description',
|
||||||
EVENT_NAME = 'event_name',
|
EVENT_NAME = 'event_name',
|
||||||
ENDPOINT = 'endpoint',
|
ENDPOINT = 'endpoint',
|
||||||
ENABLED = 'enabled',
|
ENABLED = 'enabled',
|
||||||
|
@ -213,6 +240,7 @@ export const webhookEventNames = {
|
||||||
'User deleted': 'user.deleted',
|
'User deleted': 'user.deleted',
|
||||||
'User access enabled': 'user.access_enabled',
|
'User access enabled': 'user.access_enabled',
|
||||||
'User access revoked': 'user.access_revoked',
|
'User access revoked': 'user.access_revoked',
|
||||||
|
'User deactivated': 'user.deactivated',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const emailTemplateEventNames = {
|
export const emailTemplateEventNames = {
|
||||||
|
@ -348,3 +376,16 @@ export enum EmailTemplateEditors {
|
||||||
UNLAYER_EDITOR = 'unlayer_editor',
|
UNLAYER_EDITOR = 'unlayer_editor',
|
||||||
PLAIN_HTML_EDITOR = 'plain_html_editor',
|
PLAIN_HTML_EDITOR = 'plain_html_editor',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const ResponseTypes = {
|
||||||
|
token: 'token',
|
||||||
|
code: 'code',
|
||||||
|
id_token: 'id_token',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ResponseModes = {
|
||||||
|
query: 'query',
|
||||||
|
form_post: 'form_post',
|
||||||
|
fragment: 'fragment',
|
||||||
|
web_message: 'web_message',
|
||||||
|
};
|
||||||
|
|
|
@ -30,11 +30,17 @@ export const EnvVariablesQuery = `
|
||||||
LINKEDIN_CLIENT_SECRET
|
LINKEDIN_CLIENT_SECRET
|
||||||
APPLE_CLIENT_ID
|
APPLE_CLIENT_ID
|
||||||
APPLE_CLIENT_SECRET
|
APPLE_CLIENT_SECRET
|
||||||
|
DISCORD_CLIENT_ID
|
||||||
|
DISCORD_CLIENT_SECRET
|
||||||
TWITTER_CLIENT_ID
|
TWITTER_CLIENT_ID
|
||||||
TWITTER_CLIENT_SECRET
|
TWITTER_CLIENT_SECRET
|
||||||
MICROSOFT_CLIENT_ID
|
MICROSOFT_CLIENT_ID
|
||||||
MICROSOFT_CLIENT_SECRET
|
MICROSOFT_CLIENT_SECRET
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID
|
||||||
|
TWITCH_CLIENT_ID
|
||||||
|
TWITCH_CLIENT_SECRET
|
||||||
|
ROBLOX_CLIENT_ID
|
||||||
|
ROBLOX_CLIENT_SECRET
|
||||||
DEFAULT_ROLES
|
DEFAULT_ROLES
|
||||||
PROTECTED_ROLES
|
PROTECTED_ROLES
|
||||||
ROLES
|
ROLES
|
||||||
|
@ -50,6 +56,7 @@ export const EnvVariablesQuery = `
|
||||||
SMTP_PASSWORD
|
SMTP_PASSWORD
|
||||||
SMTP_LOCAL_NAME
|
SMTP_LOCAL_NAME
|
||||||
SENDER_EMAIL
|
SENDER_EMAIL
|
||||||
|
SENDER_NAME
|
||||||
ALLOWED_ORIGINS
|
ALLOWED_ORIGINS
|
||||||
ORGANIZATION_NAME
|
ORGANIZATION_NAME
|
||||||
ORGANIZATION_LOGO
|
ORGANIZATION_LOGO
|
||||||
|
@ -60,6 +67,7 @@ export const EnvVariablesQuery = `
|
||||||
DISABLE_MAGIC_LINK_LOGIN
|
DISABLE_MAGIC_LINK_LOGIN
|
||||||
DISABLE_EMAIL_VERIFICATION
|
DISABLE_EMAIL_VERIFICATION
|
||||||
DISABLE_BASIC_AUTHENTICATION
|
DISABLE_BASIC_AUTHENTICATION
|
||||||
|
DISABLE_MOBILE_BASIC_AUTHENTICATION
|
||||||
DISABLE_SIGN_UP
|
DISABLE_SIGN_UP
|
||||||
DISABLE_STRONG_PASSWORD
|
DISABLE_STRONG_PASSWORD
|
||||||
DISABLE_REDIS_FOR_ENV
|
DISABLE_REDIS_FOR_ENV
|
||||||
|
@ -70,6 +78,11 @@ export const EnvVariablesQuery = `
|
||||||
ACCESS_TOKEN_EXPIRY_TIME
|
ACCESS_TOKEN_EXPIRY_TIME
|
||||||
DISABLE_MULTI_FACTOR_AUTHENTICATION
|
DISABLE_MULTI_FACTOR_AUTHENTICATION
|
||||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION
|
ENFORCE_MULTI_FACTOR_AUTHENTICATION
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_MODE
|
||||||
|
DISABLE_PLAYGROUND
|
||||||
|
DISABLE_TOTP_LOGIN
|
||||||
|
DISABLE_MAIL_OTP_LOGIN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -87,6 +100,7 @@ export const UserDetailsQuery = `
|
||||||
id
|
id
|
||||||
email
|
email
|
||||||
email_verified
|
email_verified
|
||||||
|
phone_number_verified
|
||||||
given_name
|
given_name
|
||||||
family_name
|
family_name
|
||||||
middle_name
|
middle_name
|
||||||
|
@ -118,6 +132,7 @@ export const WebhooksDataQuery = `
|
||||||
_webhooks(params: $params){
|
_webhooks(params: $params){
|
||||||
webhooks{
|
webhooks{
|
||||||
id
|
id
|
||||||
|
event_description
|
||||||
event_name
|
event_name
|
||||||
endpoint
|
endpoint
|
||||||
enabled
|
enabled
|
||||||
|
|
|
@ -50,11 +50,17 @@ const Environment = () => {
|
||||||
LINKEDIN_CLIENT_SECRET: '',
|
LINKEDIN_CLIENT_SECRET: '',
|
||||||
APPLE_CLIENT_ID: '',
|
APPLE_CLIENT_ID: '',
|
||||||
APPLE_CLIENT_SECRET: '',
|
APPLE_CLIENT_SECRET: '',
|
||||||
|
DISCORD_CLIENT_ID: '',
|
||||||
|
DISCORD_CLIENT_SECRET: '',
|
||||||
TWITTER_CLIENT_ID: '',
|
TWITTER_CLIENT_ID: '',
|
||||||
TWITTER_CLIENT_SECRET: '',
|
TWITTER_CLIENT_SECRET: '',
|
||||||
MICROSOFT_CLIENT_ID: '',
|
MICROSOFT_CLIENT_ID: '',
|
||||||
MICROSOFT_CLIENT_SECRET: '',
|
MICROSOFT_CLIENT_SECRET: '',
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: '',
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: '',
|
||||||
|
TWITCH_CLIENT_ID: '',
|
||||||
|
TWITCH_CLIENT_SECRET: '',
|
||||||
|
ROBLOX_CLIENT_ID: '',
|
||||||
|
ROBLOX_CLIENT_SECRET: '',
|
||||||
ROLES: [],
|
ROLES: [],
|
||||||
DEFAULT_ROLES: [],
|
DEFAULT_ROLES: [],
|
||||||
PROTECTED_ROLES: [],
|
PROTECTED_ROLES: [],
|
||||||
|
@ -70,6 +76,7 @@ const Environment = () => {
|
||||||
SMTP_PASSWORD: '',
|
SMTP_PASSWORD: '',
|
||||||
SMTP_LOCAL_NAME: '',
|
SMTP_LOCAL_NAME: '',
|
||||||
SENDER_EMAIL: '',
|
SENDER_EMAIL: '',
|
||||||
|
SENDER_NAME: '',
|
||||||
ALLOWED_ORIGINS: [],
|
ALLOWED_ORIGINS: [],
|
||||||
ORGANIZATION_NAME: '',
|
ORGANIZATION_NAME: '',
|
||||||
ORGANIZATION_LOGO: '',
|
ORGANIZATION_LOGO: '',
|
||||||
|
@ -81,6 +88,7 @@ const Environment = () => {
|
||||||
DISABLE_MAGIC_LINK_LOGIN: false,
|
DISABLE_MAGIC_LINK_LOGIN: false,
|
||||||
DISABLE_EMAIL_VERIFICATION: false,
|
DISABLE_EMAIL_VERIFICATION: false,
|
||||||
DISABLE_BASIC_AUTHENTICATION: false,
|
DISABLE_BASIC_AUTHENTICATION: false,
|
||||||
|
DISABLE_MOBILE_BASIC_AUTHENTICATION: false,
|
||||||
DISABLE_SIGN_UP: false,
|
DISABLE_SIGN_UP: false,
|
||||||
DISABLE_STRONG_PASSWORD: false,
|
DISABLE_STRONG_PASSWORD: false,
|
||||||
OLD_ADMIN_SECRET: '',
|
OLD_ADMIN_SECRET: '',
|
||||||
|
@ -90,6 +98,11 @@ const Environment = () => {
|
||||||
ACCESS_TOKEN_EXPIRY_TIME: '',
|
ACCESS_TOKEN_EXPIRY_TIME: '',
|
||||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: false,
|
DISABLE_MULTI_FACTOR_AUTHENTICATION: false,
|
||||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: false,
|
ENFORCE_MULTI_FACTOR_AUTHENTICATION: false,
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: '',
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_MODE: '',
|
||||||
|
DISABLE_PLAYGROUND: false,
|
||||||
|
DISABLE_TOTP_LOGIN: false,
|
||||||
|
DISABLE_MAIL_OTP_LOGIN: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [fieldVisibility, setFieldVisibility] = React.useState<
|
const [fieldVisibility, setFieldVisibility] = React.useState<
|
||||||
|
@ -100,7 +113,9 @@ const Environment = () => {
|
||||||
FACEBOOK_CLIENT_SECRET: false,
|
FACEBOOK_CLIENT_SECRET: false,
|
||||||
LINKEDIN_CLIENT_SECRET: false,
|
LINKEDIN_CLIENT_SECRET: false,
|
||||||
APPLE_CLIENT_SECRET: false,
|
APPLE_CLIENT_SECRET: false,
|
||||||
|
DISCORD_CLIENT_SECRET: false,
|
||||||
TWITTER_CLIENT_SECRET: false,
|
TWITTER_CLIENT_SECRET: false,
|
||||||
|
TWITCH_CLIENT_SECRET: false,
|
||||||
JWT_SECRET: false,
|
JWT_SECRET: false,
|
||||||
SMTP_PASSWORD: false,
|
SMTP_PASSWORD: false,
|
||||||
ADMIN_SECRET: false,
|
ADMIN_SECRET: false,
|
||||||
|
|
|
@ -165,14 +165,25 @@ export default function Users() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const userVerificationHandler = async (user: userDataTypes) => {
|
const userVerificationHandler = async (user: userDataTypes) => {
|
||||||
const { id, email } = user;
|
const { id, email, phone_number } = user;
|
||||||
const res = await client
|
let params = {};
|
||||||
.mutation(UpdateUser, {
|
if (email) {
|
||||||
params: {
|
params = {
|
||||||
id,
|
id,
|
||||||
email,
|
email,
|
||||||
email_verified: true,
|
email_verified: true,
|
||||||
},
|
};
|
||||||
|
}
|
||||||
|
if (phone_number) {
|
||||||
|
params = {
|
||||||
|
id,
|
||||||
|
phone_number,
|
||||||
|
phone_number_verified: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const res = await client
|
||||||
|
.mutation(UpdateUser, {
|
||||||
|
params,
|
||||||
})
|
})
|
||||||
.toPromise();
|
.toPromise();
|
||||||
if (res.error) {
|
if (res.error) {
|
||||||
|
@ -298,7 +309,7 @@ export default function Users() {
|
||||||
<Table variant="simple">
|
<Table variant="simple">
|
||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr>
|
||||||
<Th>Email</Th>
|
<Th>Email / Phone</Th>
|
||||||
<Th>Created At</Th>
|
<Th>Created At</Th>
|
||||||
<Th>Signup Methods</Th>
|
<Th>Signup Methods</Th>
|
||||||
<Th>Roles</Th>
|
<Th>Roles</Th>
|
||||||
|
@ -314,10 +325,15 @@ export default function Users() {
|
||||||
</Thead>
|
</Thead>
|
||||||
<Tbody>
|
<Tbody>
|
||||||
{userList.map((user: userDataTypes) => {
|
{userList.map((user: userDataTypes) => {
|
||||||
const { email_verified, created_at, ...rest }: any = user;
|
const {
|
||||||
|
email_verified,
|
||||||
|
phone_number_verified,
|
||||||
|
created_at,
|
||||||
|
...rest
|
||||||
|
}: any = user;
|
||||||
return (
|
return (
|
||||||
<Tr key={user.id} style={{ fontSize: 14 }}>
|
<Tr key={user.id} style={{ fontSize: 14 }}>
|
||||||
<Td maxW="300">{user.email}</Td>
|
<Td maxW="300">{user.email || user.phone_number}</Td>
|
||||||
<Td>
|
<Td>
|
||||||
{dayjs(user.created_at * 1000).format('MMM DD, YYYY')}
|
{dayjs(user.created_at * 1000).format('MMM DD, YYYY')}
|
||||||
</Td>
|
</Td>
|
||||||
|
@ -327,9 +343,15 @@ export default function Users() {
|
||||||
<Tag
|
<Tag
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
colorScheme={user.email_verified ? 'green' : 'yellow'}
|
colorScheme={
|
||||||
|
user.email_verified || user.phone_number_verified
|
||||||
|
? 'green'
|
||||||
|
: 'yellow'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{user.email_verified.toString()}
|
{(
|
||||||
|
user.email_verified || user.phone_number_verified
|
||||||
|
).toString()}
|
||||||
</Tag>
|
</Tag>
|
||||||
</Td>
|
</Td>
|
||||||
<Td>
|
<Td>
|
||||||
|
@ -368,7 +390,8 @@ export default function Users() {
|
||||||
</Flex>
|
</Flex>
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
<MenuList>
|
<MenuList>
|
||||||
{!user.email_verified && (
|
{!user.email_verified &&
|
||||||
|
!user.phone_number_verified && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => userVerificationHandler(user)}
|
onClick={() => userVerificationHandler(user)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -56,6 +56,7 @@ interface paginationPropTypes {
|
||||||
interface webhookDataTypes {
|
interface webhookDataTypes {
|
||||||
[WebhookInputDataFields.ID]: string;
|
[WebhookInputDataFields.ID]: string;
|
||||||
[WebhookInputDataFields.EVENT_NAME]: string;
|
[WebhookInputDataFields.EVENT_NAME]: string;
|
||||||
|
[WebhookInputDataFields.EVENT_DESCRIPTION]?: string;
|
||||||
[WebhookInputDataFields.ENDPOINT]: string;
|
[WebhookInputDataFields.ENDPOINT]: string;
|
||||||
[WebhookInputDataFields.ENABLED]: boolean;
|
[WebhookInputDataFields.ENABLED]: boolean;
|
||||||
[WebhookInputDataFields.HEADERS]?: Record<string, string>;
|
[WebhookInputDataFields.HEADERS]?: Record<string, string>;
|
||||||
|
@ -134,6 +135,7 @@ const Webhooks = () => {
|
||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr>
|
||||||
<Th>Event Name</Th>
|
<Th>Event Name</Th>
|
||||||
|
<Th>Event Description</Th>
|
||||||
<Th>Endpoint</Th>
|
<Th>Endpoint</Th>
|
||||||
<Th>Enabled</Th>
|
<Th>Enabled</Th>
|
||||||
<Th>Headers</Th>
|
<Th>Headers</Th>
|
||||||
|
@ -147,7 +149,10 @@ const Webhooks = () => {
|
||||||
style={{ fontSize: 14 }}
|
style={{ fontSize: 14 }}
|
||||||
>
|
>
|
||||||
<Td maxW="300">
|
<Td maxW="300">
|
||||||
{webhook[WebhookInputDataFields.EVENT_NAME]}
|
{webhook[WebhookInputDataFields.EVENT_NAME].split('-')[0]}
|
||||||
|
</Td>
|
||||||
|
<Td maxW="300">
|
||||||
|
{webhook[WebhookInputDataFields.EVENT_DESCRIPTION]}
|
||||||
</Td>
|
</Td>
|
||||||
<Td>{webhook[WebhookInputDataFields.ENDPOINT]}</Td>
|
<Td>{webhook[WebhookInputDataFields.ENDPOINT]}</Td>
|
||||||
<Td>
|
<Td>
|
||||||
|
@ -264,7 +269,7 @@ const Webhooks = () => {
|
||||||
</Text>
|
</Text>
|
||||||
</Text>
|
</Text>
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="center">
|
||||||
<Text flexShrink="0">Go to page:</Text>{' '}
|
<Text>Go to page:</Text>{' '}
|
||||||
<NumberInput
|
<NumberInput
|
||||||
ml={2}
|
ml={2}
|
||||||
mr={8}
|
mr={8}
|
||||||
|
|
2209
dashboard/yarn.lock
2209
dashboard/yarn.lock
File diff suppressed because it is too large
Load Diff
20
go.mod
Normal file
20
go.mod
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
module server
|
||||||
|
|
||||||
|
go 1.21.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/99designs/gqlgen v0.17.43 // indirect
|
||||||
|
github.com/agnivade/levenshtein v1.1.1 // indirect
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
github.com/sosodev/duration v1.1.0 // indirect
|
||||||
|
github.com/urfave/cli/v2 v2.25.5 // indirect
|
||||||
|
github.com/vektah/gqlparser/v2 v2.5.11 // indirect
|
||||||
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
|
golang.org/x/mod v0.10.0 // indirect
|
||||||
|
golang.org/x/sys v0.13.0 // indirect
|
||||||
|
golang.org/x/text v0.13.0 // indirect
|
||||||
|
golang.org/x/tools v0.9.3 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
31
go.sum
Normal file
31
go.sum
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
github.com/99designs/gqlgen v0.17.43 h1:I4SYg6ahjowErAQcHFVKy5EcWuwJ3+Xw9z2fLpuFCPo=
|
||||||
|
github.com/99designs/gqlgen v0.17.43/go.mod h1:lO0Zjy8MkZgBdv4T1U91x09r0e0WFOdhVUutlQs1Rsc=
|
||||||
|
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
|
||||||
|
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
|
||||||
|
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sosodev/duration v1.1.0 h1:kQcaiGbJaIsRqgQy7VGlZrVw1giWO+lDoX3MCPnpVO4=
|
||||||
|
github.com/sosodev/duration v1.1.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
|
||||||
|
github.com/urfave/cli/v2 v2.25.5 h1:d0NIAyhh5shGscroL7ek/Ya9QYQE0KNabJgiUinIQkc=
|
||||||
|
github.com/urfave/cli/v2 v2.25.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||||
|
github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8=
|
||||||
|
github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||||
|
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||||
|
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||||
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
|
||||||
|
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
25
server/authenticators/providers/providers.go
Normal file
25
server/authenticators/providers/providers.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package providers
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// AuthenticatorConfig defines authenticator config
|
||||||
|
type AuthenticatorConfig struct {
|
||||||
|
// ScannerImage is the base64 of QR code image
|
||||||
|
ScannerImage string
|
||||||
|
// Secrets is the secret key
|
||||||
|
Secret string
|
||||||
|
// RecoveryCode is the list of recovery codes
|
||||||
|
RecoveryCodes []string
|
||||||
|
// RecoveryCodeMap is the map of recovery codes
|
||||||
|
RecoveryCodeMap map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider defines authenticators provider
|
||||||
|
type Provider interface {
|
||||||
|
// Generate totp: to generate totp, store secret into db and returns base64 of QR code image
|
||||||
|
Generate(ctx context.Context, id string) (*AuthenticatorConfig, error)
|
||||||
|
// Validate totp: user passcode with secret stored in our db
|
||||||
|
Validate(ctx context.Context, passcode string, userID string) (bool, error)
|
||||||
|
// ValidateRecoveryCode totp: allows user to validate using recovery code incase if they lost their device
|
||||||
|
ValidateRecoveryCode(ctx context.Context, recoveryCode, userID string) (bool, error)
|
||||||
|
}
|
23
server/authenticators/providers/totp/provider.go
Normal file
23
server/authenticators/providers/totp/provider.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package totp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type provider struct {
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOTPConfig defines totp config
|
||||||
|
type TOTPConfig struct {
|
||||||
|
ScannerImage string
|
||||||
|
Secret string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProvider returns a new totp provider
|
||||||
|
func NewProvider() (*provider, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
return &provider{
|
||||||
|
ctx: ctx,
|
||||||
|
}, nil
|
||||||
|
}
|
151
server/authenticators/providers/totp/totp.go
Normal file
151
server/authenticators/providers/totp/totp.go
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
package totp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"image/png"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/pquerna/otp/totp"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/authenticators/providers"
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/crypto"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Generate generates a Time-Based One-Time Password (TOTP) for a user and returns the base64-encoded QR code for frontend display.
|
||||||
|
func (p *provider) Generate(ctx context.Context, id string) (*providers.AuthenticatorConfig, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
//get user details
|
||||||
|
user, err := db.Provider.GetUserByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// generate totp, Authenticators hash is valid for 30 seconds
|
||||||
|
key, err := totp.Generate(totp.GenerateOpts{
|
||||||
|
Issuer: "authorizer",
|
||||||
|
AccountName: refs.StringValue(user.Email),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//generating image for key and encoding to base64 for displaying in frontend
|
||||||
|
img, err := key.Image(200, 200)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
png.Encode(&buf, img)
|
||||||
|
encodedText := crypto.EncryptB64(buf.String())
|
||||||
|
secret := key.Secret()
|
||||||
|
recoveryCodes := []string{}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
recoveryCodes = append(recoveryCodes, uuid.NewString())
|
||||||
|
}
|
||||||
|
// Converting recoveryCodes to string
|
||||||
|
recoverCodesMap := map[string]bool{}
|
||||||
|
for i := 0; i < len(recoveryCodes); i++ {
|
||||||
|
recoverCodesMap[recoveryCodes[i]] = false
|
||||||
|
}
|
||||||
|
// Converting recoveryCodesMap to string
|
||||||
|
jsonData, err := json.Marshal(recoverCodesMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
recoveryCodesString := string(jsonData)
|
||||||
|
totpModel := &models.Authenticator{
|
||||||
|
Secret: secret,
|
||||||
|
RecoveryCodes: refs.NewStringRef(recoveryCodesString),
|
||||||
|
UserID: user.ID,
|
||||||
|
Method: constants.EnvKeyTOTPAuthenticator,
|
||||||
|
}
|
||||||
|
authenticator, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, user.ID, constants.EnvKeyTOTPAuthenticator)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get authenticator details by user id, creating new record: ", err)
|
||||||
|
// continue
|
||||||
|
}
|
||||||
|
if authenticator == nil {
|
||||||
|
// if authenticator is nil then create new authenticator
|
||||||
|
_, err = db.Provider.AddAuthenticator(ctx, totpModel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
authenticator.Secret = secret
|
||||||
|
authenticator.RecoveryCodes = refs.NewStringRef(recoveryCodesString)
|
||||||
|
// if authenticator is not nil then update authenticator
|
||||||
|
_, err = db.Provider.UpdateAuthenticator(ctx, authenticator)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &providers.AuthenticatorConfig{
|
||||||
|
ScannerImage: encodedText,
|
||||||
|
Secret: secret,
|
||||||
|
RecoveryCodes: recoveryCodes,
|
||||||
|
RecoveryCodeMap: recoverCodesMap,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates a Time-Based One-Time Password (TOTP) against the stored TOTP secret for a user.
|
||||||
|
func (p *provider) Validate(ctx context.Context, passcode string, userID string) (bool, error) {
|
||||||
|
// get totp details
|
||||||
|
totpModel, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, userID, constants.EnvKeyTOTPAuthenticator)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
// validate totp
|
||||||
|
status := totp.Validate(passcode, totpModel.Secret)
|
||||||
|
// checks if user not signed in for totp and totp code is correct then VerifiedAt will be stored in db
|
||||||
|
if totpModel.VerifiedAt == nil && status {
|
||||||
|
timeNow := time.Now().Unix()
|
||||||
|
totpModel.VerifiedAt = &timeNow
|
||||||
|
_, err = db.Provider.UpdateAuthenticator(ctx, totpModel)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateRecoveryCode validates a Time-Based One-Time Password (TOTP) recovery code against the stored TOTP recovery code for a user.
|
||||||
|
func (p *provider) ValidateRecoveryCode(ctx context.Context, recoveryCode, userID string) (bool, error) {
|
||||||
|
// get totp details
|
||||||
|
totpModel, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, userID, constants.EnvKeyTOTPAuthenticator)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
// convert recoveryCodes to map
|
||||||
|
recoveryCodesMap := map[string]bool{}
|
||||||
|
err = json.Unmarshal([]byte(refs.StringValue(totpModel.RecoveryCodes)), &recoveryCodesMap)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
// check if recovery code is valid
|
||||||
|
if val, ok := recoveryCodesMap[recoveryCode]; !ok {
|
||||||
|
return false, fmt.Errorf("invalid recovery code")
|
||||||
|
} else if val {
|
||||||
|
return false, fmt.Errorf("recovery code already used")
|
||||||
|
}
|
||||||
|
// update recovery code map
|
||||||
|
recoveryCodesMap[recoveryCode] = true
|
||||||
|
// convert recoveryCodesMap to string
|
||||||
|
jsonData, err := json.Marshal(recoveryCodesMap)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
recoveryCodesString := string(jsonData)
|
||||||
|
totpModel.RecoveryCodes = refs.NewStringRef(recoveryCodesString)
|
||||||
|
// update recovery code map in db
|
||||||
|
_, err = db.Provider.UpdateAuthenticator(ctx, totpModel)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
26
server/authenticators/totp_store.go
Normal file
26
server/authenticators/totp_store.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package authenticators
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/authorizerdev/authorizer/server/authenticators/providers"
|
||||||
|
"github.com/authorizerdev/authorizer/server/authenticators/providers/totp"
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Provider is the global authenticators provider.
|
||||||
|
var Provider providers.Provider
|
||||||
|
|
||||||
|
// InitTOTPStore initializes the TOTP authenticator store if it's not disabled in the environment variables.
|
||||||
|
// It sets the global Provider variable to a new TOTP provider.
|
||||||
|
func InitTOTPStore() error {
|
||||||
|
var err error
|
||||||
|
isTOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin)
|
||||||
|
|
||||||
|
if !isTOTPEnvServiceDisabled {
|
||||||
|
Provider, err = totp.NewProvider()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ const (
|
||||||
AuthRecipeMethodMobileBasicAuth = "mobile_basic_auth"
|
AuthRecipeMethodMobileBasicAuth = "mobile_basic_auth"
|
||||||
// AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method
|
// AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method
|
||||||
AuthRecipeMethodMagicLinkLogin = "magic_link_login"
|
AuthRecipeMethodMagicLinkLogin = "magic_link_login"
|
||||||
|
// AuthRecipeMethodMobileOTP is the mobile_otp auth method
|
||||||
|
AuthRecipeMethodMobileOTP = "mobile_otp"
|
||||||
// AuthRecipeMethodGoogle is the google auth method
|
// AuthRecipeMethodGoogle is the google auth method
|
||||||
AuthRecipeMethodGoogle = "google"
|
AuthRecipeMethodGoogle = "google"
|
||||||
// AuthRecipeMethodGithub is the github auth method
|
// AuthRecipeMethodGithub is the github auth method
|
||||||
|
@ -17,8 +19,14 @@ const (
|
||||||
AuthRecipeMethodLinkedIn = "linkedin"
|
AuthRecipeMethodLinkedIn = "linkedin"
|
||||||
// AuthRecipeMethodApple is the apple auth method
|
// AuthRecipeMethodApple is the apple auth method
|
||||||
AuthRecipeMethodApple = "apple"
|
AuthRecipeMethodApple = "apple"
|
||||||
|
// AuthRecipeMethodDiscord is the discord auth method
|
||||||
|
AuthRecipeMethodDiscord = "discord"
|
||||||
// AuthRecipeMethodTwitter is the twitter auth method
|
// AuthRecipeMethodTwitter is the twitter auth method
|
||||||
AuthRecipeMethodTwitter = "twitter"
|
AuthRecipeMethodTwitter = "twitter"
|
||||||
// AuthRecipeMethodMicrosoft is the microsoft auth method
|
// AuthRecipeMethodMicrosoft is the microsoft auth method
|
||||||
AuthRecipeMethodMicrosoft = "microsoft"
|
AuthRecipeMethodMicrosoft = "microsoft"
|
||||||
|
// AuthRecipeMethodTwitch is the twitch auth method
|
||||||
|
AuthRecipeMethodTwitch = "twitch"
|
||||||
|
// AuthRecipeMethodRoblox is the roblox auth method
|
||||||
|
AuthRecipeMethodRoblox = "roblox"
|
||||||
)
|
)
|
||||||
|
|
7
server/constants/authenticator_method.go
Normal file
7
server/constants/authenticator_method.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package constants
|
||||||
|
|
||||||
|
// Authenticators Methods
|
||||||
|
const (
|
||||||
|
// EnvKeyTOTPAuthenticator key for env variable TOTP
|
||||||
|
EnvKeyTOTPAuthenticator = "totp"
|
||||||
|
)
|
|
@ -5,4 +5,6 @@ const (
|
||||||
AppCookieName = "cookie"
|
AppCookieName = "cookie"
|
||||||
// AdminCookieName is the name of the cookie that is used to store the admin token
|
// AdminCookieName is the name of the cookie that is used to store the admin token
|
||||||
AdminCookieName = "authorizer-admin"
|
AdminCookieName = "authorizer-admin"
|
||||||
|
// MfaCookieName is the name of the cookie that is used to store the mfa session
|
||||||
|
MfaCookieName = "mfa"
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,8 @@ const (
|
||||||
DbTypePostgres = "postgres"
|
DbTypePostgres = "postgres"
|
||||||
// DbTypeSqlite is the sqlite database type
|
// DbTypeSqlite is the sqlite database type
|
||||||
DbTypeSqlite = "sqlite"
|
DbTypeSqlite = "sqlite"
|
||||||
|
// DbTypeLibSQL is the libsql / Turso database type
|
||||||
|
DbTypeLibSQL = "libsql"
|
||||||
// DbTypeMysql is the mysql database type
|
// DbTypeMysql is the mysql database type
|
||||||
DbTypeMysql = "mysql"
|
DbTypeMysql = "mysql"
|
||||||
// DbTypeSqlserver is the sqlserver database type
|
// DbTypeSqlserver is the sqlserver database type
|
||||||
|
|
|
@ -62,8 +62,12 @@ const (
|
||||||
EnvKeySmtpLocalName = "SMTP_LOCAL_NAME"
|
EnvKeySmtpLocalName = "SMTP_LOCAL_NAME"
|
||||||
// EnvKeySenderEmail key for env variable SENDER_EMAIL
|
// EnvKeySenderEmail key for env variable SENDER_EMAIL
|
||||||
EnvKeySenderEmail = "SENDER_EMAIL"
|
EnvKeySenderEmail = "SENDER_EMAIL"
|
||||||
|
// EnvKeySenderName key for env variable SENDER_NAME
|
||||||
|
EnvKeySenderName = "SENDER_NAME"
|
||||||
// EnvKeyIsEmailServiceEnabled key for env variable IS_EMAIL_SERVICE_ENABLED
|
// EnvKeyIsEmailServiceEnabled key for env variable IS_EMAIL_SERVICE_ENABLED
|
||||||
EnvKeyIsEmailServiceEnabled = "IS_EMAIL_SERVICE_ENABLED"
|
EnvKeyIsEmailServiceEnabled = "IS_EMAIL_SERVICE_ENABLED"
|
||||||
|
// EnvKeyIsSMSServiceEnabled key for env variable IS_SMS_SERVICE_ENABLED
|
||||||
|
EnvKeyIsSMSServiceEnabled = "IS_SMS_SERVICE_ENABLED"
|
||||||
// EnvKeyAppCookieSecure key for env variable APP_COOKIE_SECURE
|
// EnvKeyAppCookieSecure key for env variable APP_COOKIE_SECURE
|
||||||
EnvKeyAppCookieSecure = "APP_COOKIE_SECURE"
|
EnvKeyAppCookieSecure = "APP_COOKIE_SECURE"
|
||||||
// EnvKeyAdminCookieSecure key for env variable ADMIN_COOKIE_SECURE
|
// EnvKeyAdminCookieSecure key for env variable ADMIN_COOKIE_SECURE
|
||||||
|
@ -104,6 +108,10 @@ const (
|
||||||
EnvKeyAppleClientID = "APPLE_CLIENT_ID"
|
EnvKeyAppleClientID = "APPLE_CLIENT_ID"
|
||||||
// EnvKeyAppleClientSecret key for env variable APPLE_CLIENT_SECRET
|
// EnvKeyAppleClientSecret key for env variable APPLE_CLIENT_SECRET
|
||||||
EnvKeyAppleClientSecret = "APPLE_CLIENT_SECRET"
|
EnvKeyAppleClientSecret = "APPLE_CLIENT_SECRET"
|
||||||
|
// EnvKeyDiscordClientID key for env variable DISCORD_CLIENT_ID
|
||||||
|
EnvKeyDiscordClientID = "DISCORD_CLIENT_ID"
|
||||||
|
// EnvKeyDiscordClientSecret key for env variable DISCORD_CLIENT_SECRET
|
||||||
|
EnvKeyDiscordClientSecret = "DISCORD_CLIENT_SECRET"
|
||||||
// EnvKeyTwitterClientID key for env variable TWITTER_CLIENT_ID
|
// EnvKeyTwitterClientID key for env variable TWITTER_CLIENT_ID
|
||||||
EnvKeyTwitterClientID = "TWITTER_CLIENT_ID"
|
EnvKeyTwitterClientID = "TWITTER_CLIENT_ID"
|
||||||
// EnvKeyTwitterClientSecret key for env variable TWITTER_CLIENT_SECRET
|
// EnvKeyTwitterClientSecret key for env variable TWITTER_CLIENT_SECRET
|
||||||
|
@ -114,6 +122,14 @@ const (
|
||||||
EnvKeyMicrosoftActiveDirectoryTenantID = "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID"
|
EnvKeyMicrosoftActiveDirectoryTenantID = "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID"
|
||||||
// EnvKeyMicrosoftClientSecret key for env variable MICROSOFT_CLIENT_SECRET
|
// EnvKeyMicrosoftClientSecret key for env variable MICROSOFT_CLIENT_SECRET
|
||||||
EnvKeyMicrosoftClientSecret = "MICROSOFT_CLIENT_SECRET"
|
EnvKeyMicrosoftClientSecret = "MICROSOFT_CLIENT_SECRET"
|
||||||
|
// EnvKeyTwitchClientID key for env variable TWITCH_CLIENT_ID
|
||||||
|
EnvKeyTwitchClientID = "TWITCH_CLIENT_ID"
|
||||||
|
// EnvKeyTwitchClientSecret key for env variable TWITCH_CLIENT_SECRET
|
||||||
|
EnvKeyTwitchClientSecret = "TWITCH_CLIENT_SECRET"
|
||||||
|
// EnvKeyRobloxClientID key for env variable ROBLOX_CLIENT_ID
|
||||||
|
EnvKeyRobloxClientID = "ROBLOX_CLIENT_ID"
|
||||||
|
// EnvKeyRobloxClientSecret key for env variable ROBLOX_CLIENT_SECRET
|
||||||
|
EnvKeyRobloxClientSecret = "ROBLOX_CLIENT_SECRET"
|
||||||
// EnvKeyOrganizationName key for env variable ORGANIZATION_NAME
|
// EnvKeyOrganizationName key for env variable ORGANIZATION_NAME
|
||||||
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
||||||
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
||||||
|
@ -156,6 +172,18 @@ const (
|
||||||
// EnvKeyDisableMultiFactorAuthentication is key for env variable DISABLE_MULTI_FACTOR_AUTHENTICATION
|
// EnvKeyDisableMultiFactorAuthentication is key for env variable DISABLE_MULTI_FACTOR_AUTHENTICATION
|
||||||
// this variable is used to completely disable multi factor authentication. It will have no effect on profile preference
|
// this variable is used to completely disable multi factor authentication. It will have no effect on profile preference
|
||||||
EnvKeyDisableMultiFactorAuthentication = "DISABLE_MULTI_FACTOR_AUTHENTICATION"
|
EnvKeyDisableMultiFactorAuthentication = "DISABLE_MULTI_FACTOR_AUTHENTICATION"
|
||||||
|
// EnvKeyDisableTOTPLogin is key for env variable DISABLE_TOTP_LOGIN
|
||||||
|
// this variable is used to completely disable totp verification
|
||||||
|
EnvKeyDisableTOTPLogin = "DISABLE_TOTP_LOGIN"
|
||||||
|
// EnvKeyDisableMailOTPLogin is key for env variable DISABLE_MAIL_OTP_LOGIN
|
||||||
|
// this variable is used to completely disable totp verification
|
||||||
|
EnvKeyDisableMailOTPLogin = "DISABLE_MAIL_OTP_LOGIN"
|
||||||
|
// EnvKeyDisablePhoneVerification is key for env variable DISABLE_PHONE_VERIFICATION
|
||||||
|
// this variable is used to disable phone verification
|
||||||
|
EnvKeyDisablePhoneVerification = "DISABLE_PHONE_VERIFICATION"
|
||||||
|
// EnvKeyDisablePlayGround is key for env variable DISABLE_PLAYGROUND
|
||||||
|
// this variable will disable or enable playground use in dashboard
|
||||||
|
EnvKeyDisablePlayGround = "DISABLE_PLAYGROUND"
|
||||||
|
|
||||||
// Slice variables
|
// Slice variables
|
||||||
// EnvKeyRoles key for env variable ROLES
|
// EnvKeyRoles key for env variable ROLES
|
||||||
|
@ -166,4 +194,22 @@ const (
|
||||||
EnvKeyDefaultRoles = "DEFAULT_ROLES"
|
EnvKeyDefaultRoles = "DEFAULT_ROLES"
|
||||||
// EnvKeyAllowedOrigins key for env variable ALLOWED_ORIGINS
|
// EnvKeyAllowedOrigins key for env variable ALLOWED_ORIGINS
|
||||||
EnvKeyAllowedOrigins = "ALLOWED_ORIGINS"
|
EnvKeyAllowedOrigins = "ALLOWED_ORIGINS"
|
||||||
|
|
||||||
|
// For oauth/openid/authorize
|
||||||
|
// EnvKeyDefaultAuthorizeResponseType key for env variable DEFAULT_AUTHORIZE_RESPONSE_TYPE
|
||||||
|
// This env is used for setting default response type in authorize handler
|
||||||
|
EnvKeyDefaultAuthorizeResponseType = "DEFAULT_AUTHORIZE_RESPONSE_TYPE"
|
||||||
|
// EnvKeyDefaultAuthorizeResponseMode key for env variable DEFAULT_AUTHORIZE_RESPONSE_MODE
|
||||||
|
// This env is used for setting default response mode in authorize handler
|
||||||
|
EnvKeyDefaultAuthorizeResponseMode = "DEFAULT_AUTHORIZE_RESPONSE_MODE"
|
||||||
|
|
||||||
|
// Twilio env variables
|
||||||
|
// EnvKeyTwilioAPIKey key for env variable TWILIO_API_KEY
|
||||||
|
EnvKeyTwilioAPIKey = "TWILIO_API_KEY"
|
||||||
|
// EnvKeyTwilioAPISecret key for env variable TWILIO_API_SECRET
|
||||||
|
EnvKeyTwilioAPISecret = "TWILIO_API_SECRET"
|
||||||
|
// EnvKeyTwilioAccountSID key for env variable TWILIO_ACCOUNT_SID
|
||||||
|
EnvKeyTwilioAccountSID = "TWILIO_ACCOUNT_SID"
|
||||||
|
// EnvKeyTwilioSender key for env variable TWILIO_SENDER
|
||||||
|
EnvKeyTwilioSender = "TWILIO_SENDER"
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,4 +16,7 @@ const (
|
||||||
ResponseTypeToken = "token"
|
ResponseTypeToken = "token"
|
||||||
// For the Implicit grant of id_token, use response_type=id_token to include an identifier token.
|
// For the Implicit grant of id_token, use response_type=id_token to include an identifier token.
|
||||||
ResponseTypeIDToken = "id_token"
|
ResponseTypeIDToken = "id_token"
|
||||||
|
|
||||||
|
// Constant indicating the "signup" screen hint for customizing authentication process and redirect to a signup page.
|
||||||
|
ScreenHintSignUp = "signup"
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,6 +17,10 @@ const (
|
||||||
|
|
||||||
TwitterUserInfoURL = "https://api.twitter.com/2/users/me?user.fields=id,name,profile_image_url,username"
|
TwitterUserInfoURL = "https://api.twitter.com/2/users/me?user.fields=id,name,profile_image_url,username"
|
||||||
|
|
||||||
|
// RobloxUserInfoURL is the URL to get user info from Roblox
|
||||||
|
RobloxUserInfoURL = "https://apis.roblox.com/oauth/v1/userinfo"
|
||||||
|
|
||||||
|
DiscordUserInfoURL = "https://discord.com/api/oauth2/@me"
|
||||||
// Get microsoft user info.
|
// Get microsoft user info.
|
||||||
// Ref: https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo
|
// Ref: https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo
|
||||||
MicrosoftUserInfoURL = "https://graph.microsoft.com/oidc/userinfo"
|
MicrosoftUserInfoURL = "https://graph.microsoft.com/oidc/userinfo"
|
||||||
|
|
|
@ -15,4 +15,6 @@ const (
|
||||||
UserAccessEnabledWebhookEvent = `user.access_enabled`
|
UserAccessEnabledWebhookEvent = `user.access_enabled`
|
||||||
// UserDeletedWebhookEvent name for user deleted event
|
// UserDeletedWebhookEvent name for user deleted event
|
||||||
UserDeletedWebhookEvent = `user.deleted`
|
UserDeletedWebhookEvent = `user.deleted`
|
||||||
|
// UserDeactivatedWebhookEvent name for user deactivated event
|
||||||
|
UserDeactivatedWebhookEvent = `user.deactivated`
|
||||||
)
|
)
|
||||||
|
|
89
server/cookie/mfa_session.go
Normal file
89
server/cookie/mfa_session.go
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
package cookie
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/parsers"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetMfaSession sets the mfa session cookie in the response
|
||||||
|
func SetMfaSession(gc *gin.Context, sessionID string) {
|
||||||
|
appCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAppCookieSecure)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error while getting app cookie secure from env variable: %v", err)
|
||||||
|
appCookieSecure = true
|
||||||
|
}
|
||||||
|
|
||||||
|
secure := appCookieSecure
|
||||||
|
httpOnly := appCookieSecure
|
||||||
|
hostname := parsers.GetHost(gc)
|
||||||
|
host, _ := parsers.GetHostParts(hostname)
|
||||||
|
domain := parsers.GetDomainName(hostname)
|
||||||
|
if domain != "localhost" {
|
||||||
|
domain = "." + domain
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since app cookie can come from cross site it becomes important to set this in lax mode when insecure.
|
||||||
|
// Example person using custom UI on their app domain and making request to authorizer domain.
|
||||||
|
// For more information check:
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
|
||||||
|
// https://github.com/gin-gonic/gin/blob/master/context.go#L86
|
||||||
|
// TODO add ability to sameSite = none / strict from dashboard
|
||||||
|
if !appCookieSecure {
|
||||||
|
gc.SetSameSite(http.SameSiteLaxMode)
|
||||||
|
} else {
|
||||||
|
gc.SetSameSite(http.SameSiteNoneMode)
|
||||||
|
}
|
||||||
|
// TODO allow configuring from dashboard
|
||||||
|
age := 60
|
||||||
|
|
||||||
|
gc.SetCookie(constants.MfaCookieName+"_session", sessionID, age, "/", host, secure, httpOnly)
|
||||||
|
gc.SetCookie(constants.MfaCookieName+"_session_domain", sessionID, age, "/", domain, secure, httpOnly)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMfaSession deletes the mfa session cookies to expire
|
||||||
|
func DeleteMfaSession(gc *gin.Context) {
|
||||||
|
appCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAppCookieSecure)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error while getting app cookie secure from env variable: %v", err)
|
||||||
|
appCookieSecure = true
|
||||||
|
}
|
||||||
|
|
||||||
|
secure := appCookieSecure
|
||||||
|
httpOnly := appCookieSecure
|
||||||
|
hostname := parsers.GetHost(gc)
|
||||||
|
host, _ := parsers.GetHostParts(hostname)
|
||||||
|
domain := parsers.GetDomainName(hostname)
|
||||||
|
if domain != "localhost" {
|
||||||
|
domain = "." + domain
|
||||||
|
}
|
||||||
|
|
||||||
|
gc.SetSameSite(http.SameSiteNoneMode)
|
||||||
|
gc.SetCookie(constants.MfaCookieName+"_session", "", -1, "/", host, secure, httpOnly)
|
||||||
|
gc.SetCookie(constants.MfaCookieName+"_session_domain", "", -1, "/", domain, secure, httpOnly)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMfaSession gets the mfa session cookie from context
|
||||||
|
func GetMfaSession(gc *gin.Context) (string, error) {
|
||||||
|
var cookie *http.Cookie
|
||||||
|
var err error
|
||||||
|
cookie, err = gc.Request.Cookie(constants.MfaCookieName + "_session")
|
||||||
|
if err != nil {
|
||||||
|
cookie, err = gc.Request.Cookie(constants.MfaCookieName + "_session_domain")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decodedValue, err := url.PathUnescape(cookie.Value)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return decodedValue, nil
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
@ -125,12 +127,27 @@ func EncryptEnvData(data map[string]interface{}) (string, error) {
|
||||||
return EncryptB64(string(encryptedConfig)), nil
|
return EncryptB64(string(encryptedConfig)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getSHA256 calculates the SHA-256 hash of a string
|
||||||
|
func getSHA256(input string) string {
|
||||||
|
hash := sha256.New()
|
||||||
|
hash.Write([]byte(input))
|
||||||
|
return hex.EncodeToString(hash.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyPassword compares a stored hashed password with a user-provided password
|
||||||
|
func VerifyPassword(storedHashedPassword, userProvidedPassword string) error {
|
||||||
|
// CompareHashAndPassword returns nil on success
|
||||||
|
passwordSHA256 := getSHA256(userProvidedPassword)
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(storedHashedPassword), []byte(passwordSHA256))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// EncryptPassword is used for encrypting password
|
// EncryptPassword is used for encrypting password
|
||||||
func EncryptPassword(password string) (string, error) {
|
func EncryptPassword(password string) (string, error) {
|
||||||
pw, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
passwordSHA256 := getSHA256(password)
|
||||||
|
pw, err := bcrypt.GenerateFromPassword([]byte(passwordSHA256), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return string(pw), nil
|
return string(pw), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@ package crypto
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
@ -116,3 +118,24 @@ func AsRSAStr(privateKey *rsa.PrivateKey, publickKey *rsa.PublicKey) (string, st
|
||||||
|
|
||||||
return privParsedPem, pubParsedPem, nil
|
return privParsedPem, pubParsedPem, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EncryptRSA(message string, key rsa.PublicKey) (string, error) {
|
||||||
|
label := []byte("OAEP Encrypted")
|
||||||
|
rng := rand.Reader
|
||||||
|
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rng, &key, []byte(message), label)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecryptRSA(cipherText string, privateKey rsa.PrivateKey) (string, error) {
|
||||||
|
ct, _ := base64.StdEncoding.DecodeString(cipherText)
|
||||||
|
label := []byte("OAEP Encrypted")
|
||||||
|
rng := rand.Reader
|
||||||
|
plaintext, err := rsa.DecryptOAEP(sha256.New(), rng, &privateKey, ct, label)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(plaintext), nil
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ func InitDB() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isArangoDB {
|
if isArangoDB {
|
||||||
log.Info("Initializing ArangoDB Driver")
|
log.Info("Initializing ArangoDB Driver")
|
||||||
Provider, err = arangodb.NewProvider()
|
Provider, err = arangodb.NewProvider()
|
||||||
|
|
16
server/db/models/authenticators.go
Normal file
16
server/db/models/authenticators.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
// Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation
|
||||||
|
|
||||||
|
// Authenticators model for db
|
||||||
|
type Authenticator struct {
|
||||||
|
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||||
|
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||||
|
UserID string `gorm:"type:char(36)" json:"user_id" bson:"user_id" cql:"user_id" dynamo:"user_id" index:"user_id,hash"`
|
||||||
|
Method string `json:"method" bson:"method" cql:"method" dynamo:"method"`
|
||||||
|
Secret string `json:"secret" bson:"secret" cql:"secret" dynamo:"secret"`
|
||||||
|
RecoveryCodes *string `json:"recovery_codes" bson:"recovery_codes" cql:"recovery_codes" dynamo:"recovery_codes"`
|
||||||
|
VerifiedAt *int64 `json:"verified_at" bson:"verified_at" cql:"verified_at" dynamo:"verified_at"`
|
||||||
|
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||||
|
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
// Collections / Tables available for authorizer in the database
|
// CollectionList / Tables available for authorizer in the database
|
||||||
type CollectionList struct {
|
type CollectionList struct {
|
||||||
User string
|
User string
|
||||||
VerificationRequest string
|
VerificationRequest string
|
||||||
|
@ -10,6 +10,8 @@ type CollectionList struct {
|
||||||
WebhookLog string
|
WebhookLog string
|
||||||
EmailTemplate string
|
EmailTemplate string
|
||||||
OTP string
|
OTP string
|
||||||
|
SMSVerificationRequest string
|
||||||
|
Authenticators string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -25,5 +27,7 @@ var (
|
||||||
WebhookLog: Prefix + "webhook_logs",
|
WebhookLog: Prefix + "webhook_logs",
|
||||||
EmailTemplate: Prefix + "email_templates",
|
EmailTemplate: Prefix + "email_templates",
|
||||||
OTP: Prefix + "otps",
|
OTP: Prefix + "otps",
|
||||||
|
SMSVerificationRequest: Prefix + "sms_verification_requests",
|
||||||
|
Authenticators: Prefix + "authenticators",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
|
const (
|
||||||
|
// FieldName email is the field name for email
|
||||||
|
FieldNameEmail = "email"
|
||||||
|
// FieldNamePhoneNumber is the field name for phone number
|
||||||
|
FieldNamePhoneNumber = "phone_number"
|
||||||
|
)
|
||||||
|
|
||||||
// OTP model for database
|
// OTP model for database
|
||||||
type OTP struct {
|
type OTP struct {
|
||||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||||
Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
Email string `gorm:"index" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
||||||
|
PhoneNumber string `gorm:"index" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number"`
|
||||||
Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"`
|
Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"`
|
||||||
ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"`
|
ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"`
|
||||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||||
|
|
|
@ -15,7 +15,7 @@ type User struct {
|
||||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||||
|
|
||||||
Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
Email *string `gorm:"index" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
||||||
EmailVerifiedAt *int64 `json:"email_verified_at" bson:"email_verified_at" cql:"email_verified_at" dynamo:"email_verified_at"`
|
EmailVerifiedAt *int64 `json:"email_verified_at" bson:"email_verified_at" cql:"email_verified_at" dynamo:"email_verified_at"`
|
||||||
Password *string `json:"password" bson:"password" cql:"password" dynamo:"password"`
|
Password *string `json:"password" bson:"password" cql:"password" dynamo:"password"`
|
||||||
SignupMethods string `json:"signup_methods" bson:"signup_methods" cql:"signup_methods" dynamo:"signup_methods"`
|
SignupMethods string `json:"signup_methods" bson:"signup_methods" cql:"signup_methods" dynamo:"signup_methods"`
|
||||||
|
@ -33,12 +33,14 @@ type User struct {
|
||||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled" bson:"is_multi_factor_auth_enabled" cql:"is_multi_factor_auth_enabled" dynamo:"is_multi_factor_auth_enabled"`
|
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled" bson:"is_multi_factor_auth_enabled" cql:"is_multi_factor_auth_enabled" dynamo:"is_multi_factor_auth_enabled"`
|
||||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
||||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||||
|
AppData *string `json:"app_data" bson:"app_data" cql:"app_data" dynamo:"app_data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) AsAPIUser() *model.User {
|
func (user *User) AsAPIUser() *model.User {
|
||||||
isEmailVerified := user.EmailVerifiedAt != nil
|
isEmailVerified := user.EmailVerifiedAt != nil
|
||||||
isPhoneVerified := user.PhoneNumberVerifiedAt != nil
|
isPhoneVerified := user.PhoneNumberVerifiedAt != nil
|
||||||
|
appDataMap := make(map[string]interface{})
|
||||||
|
json.Unmarshal([]byte(refs.StringValue(user.AppData)), &appDataMap)
|
||||||
// id := user.ID
|
// id := user.ID
|
||||||
// if strings.Contains(id, Collections.User+"/") {
|
// if strings.Contains(id, Collections.User+"/") {
|
||||||
// id = strings.TrimPrefix(id, Collections.User+"/")
|
// id = strings.TrimPrefix(id, Collections.User+"/")
|
||||||
|
@ -52,7 +54,7 @@ func (user *User) AsAPIUser() *model.User {
|
||||||
FamilyName: user.FamilyName,
|
FamilyName: user.FamilyName,
|
||||||
MiddleName: user.MiddleName,
|
MiddleName: user.MiddleName,
|
||||||
Nickname: user.Nickname,
|
Nickname: user.Nickname,
|
||||||
PreferredUsername: refs.NewStringRef(user.Email),
|
PreferredUsername: user.Email,
|
||||||
Gender: user.Gender,
|
Gender: user.Gender,
|
||||||
Birthdate: user.Birthdate,
|
Birthdate: user.Birthdate,
|
||||||
PhoneNumber: user.PhoneNumber,
|
PhoneNumber: user.PhoneNumber,
|
||||||
|
@ -63,6 +65,7 @@ func (user *User) AsAPIUser() *model.User {
|
||||||
IsMultiFactorAuthEnabled: user.IsMultiFactorAuthEnabled,
|
IsMultiFactorAuthEnabled: user.IsMultiFactorAuthEnabled,
|
||||||
CreatedAt: refs.NewInt64Ref(user.CreatedAt),
|
CreatedAt: refs.NewInt64Ref(user.CreatedAt),
|
||||||
UpdatedAt: refs.NewInt64Ref(user.UpdatedAt),
|
UpdatedAt: refs.NewInt64Ref(user.UpdatedAt),
|
||||||
|
AppData: appDataMap,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,15 @@ import (
|
||||||
|
|
||||||
// Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation
|
// Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation
|
||||||
|
|
||||||
|
// Event name has been kept unique as per initial design. But later on decided that we can have
|
||||||
|
// multiple hooks for same event so will be in a pattern `event_name-TIMESTAMP`
|
||||||
|
|
||||||
// Webhook model for db
|
// Webhook model for db
|
||||||
type Webhook struct {
|
type Webhook struct {
|
||||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||||
EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name" dynamo:"event_name" index:"event_name,hash"`
|
EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name" dynamo:"event_name" index:"event_name,hash"`
|
||||||
|
EventDescription string `json:"event_description" bson:"event_description" cql:"event_description" dynamo:"event_description"`
|
||||||
EndPoint string `json:"endpoint" bson:"endpoint" cql:"endpoint" dynamo:"endpoint"`
|
EndPoint string `json:"endpoint" bson:"endpoint" cql:"endpoint" dynamo:"endpoint"`
|
||||||
Headers string `json:"headers" bson:"headers" cql:"headers" dynamo:"headers"`
|
Headers string `json:"headers" bson:"headers" cql:"headers" dynamo:"headers"`
|
||||||
Enabled bool `json:"enabled" bson:"enabled" cql:"enabled" dynamo:"enabled"`
|
Enabled bool `json:"enabled" bson:"enabled" cql:"enabled" dynamo:"enabled"`
|
||||||
|
@ -26,15 +30,18 @@ type Webhook struct {
|
||||||
func (w *Webhook) AsAPIWebhook() *model.Webhook {
|
func (w *Webhook) AsAPIWebhook() *model.Webhook {
|
||||||
headersMap := make(map[string]interface{})
|
headersMap := make(map[string]interface{})
|
||||||
json.Unmarshal([]byte(w.Headers), &headersMap)
|
json.Unmarshal([]byte(w.Headers), &headersMap)
|
||||||
|
|
||||||
id := w.ID
|
id := w.ID
|
||||||
if strings.Contains(id, Collections.Webhook+"/") {
|
if strings.Contains(id, Collections.Webhook+"/") {
|
||||||
id = strings.TrimPrefix(id, Collections.Webhook+"/")
|
id = strings.TrimPrefix(id, Collections.Webhook+"/")
|
||||||
}
|
}
|
||||||
|
// set default title to event name without dot(.)
|
||||||
|
if w.EventDescription == "" {
|
||||||
|
w.EventDescription = strings.Join(strings.Split(w.EventName, "."), " ")
|
||||||
|
}
|
||||||
return &model.Webhook{
|
return &model.Webhook{
|
||||||
ID: id,
|
ID: id,
|
||||||
EventName: refs.NewStringRef(w.EventName),
|
EventName: refs.NewStringRef(w.EventName),
|
||||||
|
EventDescription: refs.NewStringRef(w.EventDescription),
|
||||||
Endpoint: refs.NewStringRef(w.EndPoint),
|
Endpoint: refs.NewStringRef(w.EndPoint),
|
||||||
Headers: headersMap,
|
Headers: headersMap,
|
||||||
Enabled: refs.NewBoolRef(w.Enabled),
|
Enabled: refs.NewBoolRef(w.Enabled),
|
||||||
|
|
78
server/db/providers/arangodb/authenticator.go
Normal file
78
server/db/providers/arangodb/authenticator.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package arangodb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
arangoDriver "github.com/arangodb/go-driver"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticators.Key = authenticators.ID
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
authenticatorsCollection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
||||||
|
meta, err := authenticatorsCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
authenticators.Key = meta.Key
|
||||||
|
authenticators.ID = meta.ID.String()
|
||||||
|
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
collection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
||||||
|
meta, err := collection.UpdateDocument(ctx, authenticators.Key, authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticators.Key = meta.Key
|
||||||
|
authenticators.ID = meta.ID.String()
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators *models.Authenticator
|
||||||
|
query := fmt.Sprintf("FOR d in %s FILTER d.user_id == @user_id AND d.method == @method LIMIT 1 RETURN d", models.Collections.Authenticators)
|
||||||
|
bindVars := map[string]interface{}{
|
||||||
|
"user_id": userId,
|
||||||
|
"method": authenticatorType,
|
||||||
|
}
|
||||||
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cursor.Close()
|
||||||
|
for {
|
||||||
|
if !cursor.HasMore() {
|
||||||
|
if authenticators == nil {
|
||||||
|
return authenticators, fmt.Errorf("authenticator not found")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_, err := cursor.ReadDocument(ctx, &authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
|
@ -12,16 +12,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEmailTemplate to add EmailTemplate
|
// AddEmailTemplate to add EmailTemplate
|
||||||
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
if emailTemplate.ID == "" {
|
if emailTemplate.ID == "" {
|
||||||
emailTemplate.ID = uuid.New().String()
|
emailTemplate.ID = uuid.New().String()
|
||||||
emailTemplate.Key = emailTemplate.ID
|
emailTemplate.Key = emailTemplate.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
emailTemplate.Key = emailTemplate.ID
|
emailTemplate.Key = emailTemplate.ID
|
||||||
emailTemplate.CreatedAt = time.Now().Unix()
|
emailTemplate.CreatedAt = time.Now().Unix()
|
||||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
emailTemplate.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
emailTemplateCollection, _ := p.db.Collection(ctx, models.Collections.EmailTemplate)
|
emailTemplateCollection, _ := p.db.Collection(ctx, models.Collections.EmailTemplate)
|
||||||
_, err := emailTemplateCollection.CreateDocument(ctx, emailTemplate)
|
_, err := emailTemplateCollection.CreateDocument(ctx, emailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -31,74 +29,63 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEmailTemplate to update EmailTemplate
|
// UpdateEmailTemplate to update EmailTemplate
|
||||||
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
emailTemplate.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
emailTemplateCollection, _ := p.db.Collection(ctx, models.Collections.EmailTemplate)
|
emailTemplateCollection, _ := p.db.Collection(ctx, models.Collections.EmailTemplate)
|
||||||
meta, err := emailTemplateCollection.UpdateDocument(ctx, emailTemplate.Key, emailTemplate)
|
meta, err := emailTemplateCollection.UpdateDocument(ctx, emailTemplate.Key, emailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
emailTemplate.Key = meta.Key
|
emailTemplate.Key = meta.Key
|
||||||
emailTemplate.ID = meta.ID.String()
|
emailTemplate.ID = meta.ID.String()
|
||||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListEmailTemplates to list EmailTemplate
|
// ListEmailTemplates to list EmailTemplate
|
||||||
func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) {
|
func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) {
|
||||||
emailTemplates := []*model.EmailTemplate{}
|
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)
|
query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.EmailTemplate, pagination.Offset, pagination.Limit)
|
||||||
|
|
||||||
sctx := arangoDriver.WithQueryFullCount(ctx)
|
sctx := arangoDriver.WithQueryFullCount(ctx)
|
||||||
cursor, err := p.db.Query(sctx, query, nil)
|
cursor, err := p.db.Query(sctx, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
paginationClone.Total = cursor.Statistics().FullCount()
|
paginationClone.Total = cursor.Statistics().FullCount()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var emailTemplate models.EmailTemplate
|
var emailTemplate *models.EmailTemplate
|
||||||
meta, err := cursor.ReadDocument(ctx, &emailTemplate)
|
meta, err := cursor.ReadDocument(ctx, &emailTemplate)
|
||||||
|
|
||||||
if arangoDriver.IsNoMoreDocuments(err) {
|
if arangoDriver.IsNoMoreDocuments(err) {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if meta.Key != "" {
|
if meta.Key != "" {
|
||||||
emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate())
|
emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.EmailTemplates{
|
return &model.EmailTemplates{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
EmailTemplates: emailTemplates,
|
EmailTemplates: emailTemplates,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEmailTemplateByID to get EmailTemplate by id
|
// GetEmailTemplateByID to get EmailTemplate by id
|
||||||
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
||||||
var emailTemplate models.EmailTemplate
|
var emailTemplate *models.EmailTemplate
|
||||||
query := fmt.Sprintf("FOR d in %s FILTER d._key == @email_template_id RETURN d", models.Collections.EmailTemplate)
|
query := fmt.Sprintf("FOR d in %s FILTER d._key == @email_template_id RETURN d", models.Collections.EmailTemplate)
|
||||||
bindVars := map[string]interface{}{
|
bindVars := map[string]interface{}{
|
||||||
"email_template_id": emailTemplateID,
|
"email_template_id": emailTemplateID,
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if emailTemplate.Key == "" {
|
if emailTemplate == nil {
|
||||||
return nil, fmt.Errorf("email template not found")
|
return nil, fmt.Errorf("email template not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
@ -113,21 +100,19 @@ func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID str
|
||||||
|
|
||||||
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
||||||
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
||||||
var emailTemplate models.EmailTemplate
|
var emailTemplate *models.EmailTemplate
|
||||||
query := fmt.Sprintf("FOR d in %s FILTER d.event_name == @event_name RETURN d", models.Collections.EmailTemplate)
|
query := fmt.Sprintf("FOR d in %s FILTER d.event_name == @event_name RETURN d", models.Collections.EmailTemplate)
|
||||||
bindVars := map[string]interface{}{
|
bindVars := map[string]interface{}{
|
||||||
"event_name": eventName,
|
"event_name": eventName,
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if emailTemplate.Key == "" {
|
if emailTemplate == nil {
|
||||||
return nil, fmt.Errorf("email template not found")
|
return nil, fmt.Errorf("email template not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEnv to save environment information in database
|
// AddEnv to save environment information in database
|
||||||
func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) {
|
||||||
if env.ID == "" {
|
if env.ID == "" {
|
||||||
env.ID = uuid.New().String()
|
env.ID = uuid.New().String()
|
||||||
env.Key = env.ID
|
env.Key = env.ID
|
||||||
|
@ -23,7 +23,7 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro
|
||||||
configCollection, _ := p.db.Collection(ctx, models.Collections.Env)
|
configCollection, _ := p.db.Collection(ctx, models.Collections.Env)
|
||||||
meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), env)
|
meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
env.Key = meta.Key
|
env.Key = meta.Key
|
||||||
env.ID = meta.ID.String()
|
env.ID = meta.ID.String()
|
||||||
|
@ -31,12 +31,12 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEnv to update environment information in database
|
// UpdateEnv to update environment information in database
|
||||||
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) {
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
collection, _ := p.db.Collection(ctx, models.Collections.Env)
|
collection, _ := p.db.Collection(ctx, models.Collections.Env)
|
||||||
meta, err := collection.UpdateDocument(ctx, env.Key, env)
|
meta, err := collection.UpdateDocument(ctx, env.Key, env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
env.Key = meta.Key
|
env.Key = meta.Key
|
||||||
|
@ -45,26 +45,24 @@ func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, e
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEnv to get environment information from database
|
// GetEnv to get environment information from database
|
||||||
func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
|
func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
||||||
var env models.Env
|
var env *models.Env
|
||||||
query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.Env)
|
query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.Env)
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, nil)
|
cursor, err := p.db.Query(ctx, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if env.Key == "" {
|
if env == nil {
|
||||||
return env, fmt.Errorf("config not found")
|
return env, fmt.Errorf("config not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
_, err := cursor.ReadDocument(ctx, &env)
|
_, err := cursor.ReadDocument(ctx, &env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package arangodb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -12,7 +13,20 @@ import (
|
||||||
|
|
||||||
// UpsertOTP to add or update otp
|
// UpsertOTP to add or update otp
|
||||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
|
// check if email or phone number is present
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||||
|
return nil, errors.New("email or phone_number is required")
|
||||||
|
}
|
||||||
|
uniqueField := models.FieldNameEmail
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||||
|
uniqueField = models.FieldNamePhoneNumber
|
||||||
|
}
|
||||||
|
var otp *models.OTP
|
||||||
|
if uniqueField == models.FieldNameEmail {
|
||||||
|
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||||
|
} else {
|
||||||
|
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||||
|
}
|
||||||
shouldCreate := false
|
shouldCreate := false
|
||||||
if otp == nil {
|
if otp == nil {
|
||||||
id := uuid.NewString()
|
id := uuid.NewString()
|
||||||
|
@ -21,6 +35,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
Key: id,
|
Key: id,
|
||||||
Otp: otpParam.Otp,
|
Otp: otpParam.Otp,
|
||||||
Email: otpParam.Email,
|
Email: otpParam.Email,
|
||||||
|
PhoneNumber: otpParam.PhoneNumber,
|
||||||
ExpiresAt: otpParam.ExpiresAt,
|
ExpiresAt: otpParam.ExpiresAt,
|
||||||
CreatedAt: time.Now().Unix(),
|
CreatedAt: time.Now().Unix(),
|
||||||
}
|
}
|
||||||
|
@ -29,10 +44,8 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
otp.Otp = otpParam.Otp
|
otp.Otp = otpParam.Otp
|
||||||
otp.ExpiresAt = otpParam.ExpiresAt
|
otp.ExpiresAt = otpParam.ExpiresAt
|
||||||
}
|
}
|
||||||
|
|
||||||
otp.UpdatedAt = time.Now().Unix()
|
otp.UpdatedAt = time.Now().Unix()
|
||||||
otpCollection, _ := p.db.Collection(ctx, models.Collections.OTP)
|
otpCollection, _ := p.db.Collection(ctx, models.Collections.OTP)
|
||||||
|
|
||||||
var meta driver.DocumentMeta
|
var meta driver.DocumentMeta
|
||||||
var err error
|
var err error
|
||||||
if shouldCreate {
|
if shouldCreate {
|
||||||
|
@ -40,11 +53,9 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
} else {
|
} else {
|
||||||
meta, err = otpCollection.UpdateDocument(ctx, otp.Key, otp)
|
meta, err = otpCollection.UpdateDocument(ctx, otp.Key, otp)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
otp.Key = meta.Key
|
otp.Key = meta.Key
|
||||||
otp.ID = meta.ID.String()
|
otp.ID = meta.ID.String()
|
||||||
return otp, nil
|
return otp, nil
|
||||||
|
@ -52,22 +63,20 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
|
|
||||||
// GetOTPByEmail to get otp for a given email address
|
// GetOTPByEmail to get otp for a given email address
|
||||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||||
var otp models.OTP
|
var otp *models.OTP
|
||||||
query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.OTP)
|
query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.OTP)
|
||||||
bindVars := map[string]interface{}{
|
bindVars := map[string]interface{}{
|
||||||
"email": emailAddress,
|
"email": emailAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if otp.Key == "" {
|
if otp == nil {
|
||||||
return nil, fmt.Errorf("email template not found")
|
return nil, fmt.Errorf("otp with given email not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -76,8 +85,34 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return otp, nil
|
||||||
|
}
|
||||||
|
|
||||||
return &otp, nil
|
// GetOTPByPhoneNumber to get otp for a given phone number
|
||||||
|
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
|
||||||
|
var otp *models.OTP
|
||||||
|
query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.OTP)
|
||||||
|
bindVars := map[string]interface{}{
|
||||||
|
"phone_number": phoneNumber,
|
||||||
|
}
|
||||||
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cursor.Close()
|
||||||
|
for {
|
||||||
|
if !cursor.HasMore() {
|
||||||
|
if otp == nil {
|
||||||
|
return nil, fmt.Errorf("otp with given phone_number not found")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_, err := cursor.ReadDocument(ctx, &otp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return otp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOTP to delete otp
|
// DeleteOTP to delete otp
|
||||||
|
@ -87,6 +122,5 @@ func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,6 @@ func NewProvider() (*provider, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var arangodb arangoDriver.Database
|
var arangodb arangoDriver.Database
|
||||||
dbName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName
|
dbName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName
|
||||||
arangodb_exists, err := arangoClient.DatabaseExists(ctx, dbName)
|
arangodb_exists, err := arangoClient.DatabaseExists(ctx, dbName)
|
||||||
|
@ -79,7 +78,6 @@ func NewProvider() (*provider, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.User)
|
userCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -113,7 +111,6 @@ func NewProvider() (*provider, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verificationRequestCollection, err := arangodb.Collection(ctx, models.Collections.VerificationRequest)
|
verificationRequestCollection, err := arangodb.Collection(ctx, models.Collections.VerificationRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -136,7 +133,6 @@ func NewProvider() (*provider, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionCollection, err := arangodb.Collection(ctx, models.Collections.Session)
|
sessionCollection, err := arangodb.Collection(ctx, models.Collections.Session)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -144,7 +140,6 @@ func NewProvider() (*provider, error) {
|
||||||
sessionCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{
|
sessionCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
envCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Env)
|
envCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -155,7 +150,6 @@ func NewProvider() (*provider, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
webhookCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Webhook)
|
webhookCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Webhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -166,7 +160,6 @@ func NewProvider() (*provider, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
webhookCollection, err := arangodb.Collection(ctx, models.Collections.Webhook)
|
webhookCollection, err := arangodb.Collection(ctx, models.Collections.Webhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -186,7 +179,6 @@ func NewProvider() (*provider, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
webhookLogCollection, err := arangodb.Collection(ctx, models.Collections.WebhookLog)
|
webhookLogCollection, err := arangodb.Collection(ctx, models.Collections.WebhookLog)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -205,7 +197,6 @@ func NewProvider() (*provider, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emailTemplateCollection, err := arangodb.Collection(ctx, models.Collections.EmailTemplate)
|
emailTemplateCollection, err := arangodb.Collection(ctx, models.Collections.EmailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -225,16 +216,34 @@ func NewProvider() (*provider, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
otpCollection, err := arangodb.Collection(ctx, models.Collections.OTP)
|
otpCollection, err := arangodb.Collection(ctx, models.Collections.OTP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
otpCollection.EnsureHashIndex(ctx, []string{"email"}, &arangoDriver.EnsureHashIndexOptions{
|
otpCollection.EnsureHashIndex(ctx, []string{models.FieldNameEmail, models.FieldNamePhoneNumber}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
Unique: true,
|
Unique: true,
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//authenticators table define
|
||||||
|
authenticatorsCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !authenticatorsCollectionExists {
|
||||||
|
_, err = arangodb.CreateCollection(ctx, models.Collections.Authenticators, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
authenticatorsCollection, err := arangodb.Collection(ctx, models.Collections.Authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
authenticatorsCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
|
Sparse: true,
|
||||||
|
})
|
||||||
|
|
||||||
return &provider{
|
return &provider{
|
||||||
db: arangodb,
|
db: arangodb,
|
||||||
}, err
|
}, err
|
||||||
|
|
|
@ -9,12 +9,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddSession to save session information in database
|
// AddSession to save session information in database
|
||||||
func (p *provider) AddSession(ctx context.Context, session models.Session) error {
|
func (p *provider) AddSession(ctx context.Context, session *models.Session) error {
|
||||||
if session.ID == "" {
|
if session.ID == "" {
|
||||||
session.ID = uuid.New().String()
|
session.ID = uuid.New().String()
|
||||||
session.Key = session.ID
|
session.Key = session.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
session.CreatedAt = time.Now().Unix()
|
session.CreatedAt = time.Now().Unix()
|
||||||
session.UpdatedAt = time.Now().Unix()
|
session.UpdatedAt = time.Now().Unix()
|
||||||
sessionCollection, _ := p.db.Collection(ctx, models.Collections.Session)
|
sessionCollection, _ := p.db.Collection(ctx, models.Collections.Session)
|
||||||
|
@ -24,3 +23,8 @@ func (p *provider) AddSession(ctx context.Context, session models.Session) error
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteSession to delete session information from database
|
||||||
|
func (p *provider) DeleteSession(ctx context.Context, userId string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddUser to save user information in database
|
// AddUser to save user information in database
|
||||||
func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) {
|
||||||
if user.ID == "" {
|
if user.ID == "" {
|
||||||
user.ID = uuid.New().String()
|
user.ID = uuid.New().String()
|
||||||
user.Key = user.ID
|
user.Key = user.ID
|
||||||
|
@ -27,7 +27,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
if user.Roles == "" {
|
if user.Roles == "" {
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,10 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||||
return user, fmt.Errorf("user with given phone number already exists")
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
}
|
}
|
||||||
|
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||||
|
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given email already exists")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
|
@ -43,7 +47,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||||
meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), user)
|
meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Key = meta.Key
|
user.Key = meta.Key
|
||||||
user.ID = meta.ID.String()
|
user.ID = meta.ID.String()
|
||||||
|
@ -52,13 +56,13 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUser to update user information in database
|
// UpdateUser to update user information in database
|
||||||
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) {
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||||
meta, err := collection.UpdateDocument(ctx, user.Key, user)
|
meta, err := collection.UpdateDocument(ctx, user.Key, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Key = meta.Key
|
user.Key = meta.Key
|
||||||
|
@ -67,13 +71,12 @@ func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.Use
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUser to delete user information from database
|
// DeleteUser to delete user information from database
|
||||||
func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
func (p *provider) DeleteUser(ctx context.Context, user *models.User) error {
|
||||||
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||||
_, err := collection.RemoveDocument(ctx, user.Key)
|
_, err := collection.RemoveDocument(ctx, user.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
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{}{
|
bindVars := map[string]interface{}{
|
||||||
"user_id": user.Key,
|
"user_id": user.Key,
|
||||||
|
@ -83,106 +86,91 @@ func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListUsers to get list of users from database
|
// ListUsers to get list of users from database
|
||||||
func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
|
func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) {
|
||||||
var users []*model.User
|
var users []*model.User
|
||||||
sctx := arangoDriver.WithQueryFullCount(ctx)
|
sctx := arangoDriver.WithQueryFullCount(ctx)
|
||||||
|
|
||||||
query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.User, pagination.Offset, pagination.Limit)
|
query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.User, pagination.Offset, pagination.Limit)
|
||||||
|
|
||||||
cursor, err := p.db.Query(sctx, query, nil)
|
cursor, err := p.db.Query(sctx, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
paginationClone.Total = cursor.Statistics().FullCount()
|
paginationClone.Total = cursor.Statistics().FullCount()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var user models.User
|
var user *models.User
|
||||||
meta, err := cursor.ReadDocument(ctx, &user)
|
meta, err := cursor.ReadDocument(ctx, &user)
|
||||||
|
|
||||||
if arangoDriver.IsNoMoreDocuments(err) {
|
if arangoDriver.IsNoMoreDocuments(err) {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if meta.Key != "" {
|
if meta.Key != "" {
|
||||||
users = append(users, user.AsAPIUser())
|
users = append(users, user.AsAPIUser())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.Users{
|
return &model.Users{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
Users: users,
|
Users: users,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByEmail to get user information from database using email address
|
// GetUserByEmail to get user information from database using email address
|
||||||
func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
|
func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) {
|
||||||
var user models.User
|
var user *models.User
|
||||||
|
|
||||||
query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.User)
|
query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.User)
|
||||||
bindVars := map[string]interface{}{
|
bindVars := map[string]interface{}{
|
||||||
"email": email,
|
"email": email,
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if user.Key == "" {
|
if user == nil {
|
||||||
return user, fmt.Errorf("user not found")
|
return nil, fmt.Errorf("user not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
_, err := cursor.ReadDocument(ctx, &user)
|
_, err := cursor.ReadDocument(ctx, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByID to get user information from database using user ID
|
// GetUserByID to get user information from database using user ID
|
||||||
func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
|
func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) {
|
||||||
var user models.User
|
var user *models.User
|
||||||
|
|
||||||
query := fmt.Sprintf("FOR d in %s FILTER d._id == @id LIMIT 1 RETURN d", models.Collections.User)
|
query := fmt.Sprintf("FOR d in %s FILTER d._id == @id LIMIT 1 RETURN d", models.Collections.User)
|
||||||
bindVars := map[string]interface{}{
|
bindVars := map[string]interface{}{
|
||||||
"id": id,
|
"id": id,
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if user.Key == "" {
|
if user == nil {
|
||||||
return user, fmt.Errorf("user not found")
|
return nil, fmt.Errorf("user not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
_, err := cursor.ReadDocument(ctx, &user)
|
_, err := cursor.ReadDocument(ctx, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,12 +179,10 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, err
|
||||||
func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error {
|
func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error {
|
||||||
// set updated_at time for all users
|
// set updated_at time for all users
|
||||||
data["updated_at"] = time.Now().Unix()
|
data["updated_at"] = time.Now().Unix()
|
||||||
|
|
||||||
userInfoBytes, err := json.Marshal(data)
|
userInfoBytes, err := json.Marshal(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
query := ""
|
query := ""
|
||||||
if len(ids) > 0 {
|
if len(ids) > 0 {
|
||||||
keysArray := ""
|
keysArray := ""
|
||||||
|
@ -209,33 +195,28 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
} else {
|
} else {
|
||||||
query = fmt.Sprintf("FOR u IN %s UPDATE u._key with %s IN %s", models.Collections.User, string(userInfoBytes), models.Collections.User)
|
query = fmt.Sprintf("FOR u IN %s UPDATE u._key with %s IN %s", models.Collections.User, string(userInfoBytes), models.Collections.User)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = p.db.Query(ctx, query, nil)
|
_, err = p.db.Query(ctx, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByPhoneNumber to get user information from database using phone number
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
var user models.User
|
var user *models.User
|
||||||
|
|
||||||
query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.User)
|
query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.User)
|
||||||
bindVars := map[string]interface{}{
|
bindVars := map[string]interface{}{
|
||||||
"phone_number": phoneNumber,
|
"phone_number": phoneNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if user.Key == "" {
|
if user == nil {
|
||||||
return nil, fmt.Errorf("user not found")
|
return nil, fmt.Errorf("user not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
@ -245,6 +226,5 @@ func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return user, nil
|
||||||
return &user, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,104 +12,92 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddVerification to save verification request in database
|
// AddVerification to save verification request in database
|
||||||
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
|
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) {
|
||||||
if verificationRequest.ID == "" {
|
if verificationRequest.ID == "" {
|
||||||
verificationRequest.ID = uuid.New().String()
|
verificationRequest.ID = uuid.New().String()
|
||||||
verificationRequest.Key = verificationRequest.ID
|
verificationRequest.Key = verificationRequest.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
verificationRequest.CreatedAt = time.Now().Unix()
|
verificationRequest.CreatedAt = time.Now().Unix()
|
||||||
verificationRequest.UpdatedAt = time.Now().Unix()
|
verificationRequest.UpdatedAt = time.Now().Unix()
|
||||||
verificationRequestRequestCollection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
|
verificationRequestRequestCollection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
|
||||||
meta, err := verificationRequestRequestCollection.CreateDocument(ctx, verificationRequest)
|
meta, err := verificationRequestRequestCollection.CreateDocument(ctx, verificationRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
verificationRequest.Key = meta.Key
|
verificationRequest.Key = meta.Key
|
||||||
verificationRequest.ID = meta.ID.String()
|
verificationRequest.ID = meta.ID.String()
|
||||||
|
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVerificationRequestByToken to get verification request from database using token
|
// GetVerificationRequestByToken to get verification request from database using token
|
||||||
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
|
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) {
|
||||||
var verificationRequest models.VerificationRequest
|
var verificationRequest *models.VerificationRequest
|
||||||
query := fmt.Sprintf("FOR d in %s FILTER d.token == @token LIMIT 1 RETURN d", models.Collections.VerificationRequest)
|
query := fmt.Sprintf("FOR d in %s FILTER d.token == @token LIMIT 1 RETURN d", models.Collections.VerificationRequest)
|
||||||
bindVars := map[string]interface{}{
|
bindVars := map[string]interface{}{
|
||||||
"token": token,
|
"token": token,
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if verificationRequest.Key == "" {
|
if verificationRequest == nil {
|
||||||
return verificationRequest, fmt.Errorf("verification request not found")
|
return verificationRequest, fmt.Errorf("verification request not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVerificationRequestByEmail to get verification request by email from database
|
// GetVerificationRequestByEmail to get verification request by email from database
|
||||||
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
|
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) {
|
||||||
var verificationRequest models.VerificationRequest
|
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)
|
query := fmt.Sprintf("FOR d in %s FILTER d.email == @email FILTER d.identifier == @identifier LIMIT 1 RETURN d", models.Collections.VerificationRequest)
|
||||||
bindVars := map[string]interface{}{
|
bindVars := map[string]interface{}{
|
||||||
"email": email,
|
"email": email,
|
||||||
"identifier": identifier,
|
"identifier": identifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if verificationRequest.Key == "" {
|
if verificationRequest == nil {
|
||||||
return verificationRequest, fmt.Errorf("verification request not found")
|
return verificationRequest, fmt.Errorf("verification request not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListVerificationRequests to get list of verification requests from database
|
// ListVerificationRequests to get list of verification requests from database
|
||||||
func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
|
func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) {
|
||||||
var verificationRequests []*model.VerificationRequest
|
var verificationRequests []*model.VerificationRequest
|
||||||
sctx := arangoDriver.WithQueryFullCount(ctx)
|
sctx := arangoDriver.WithQueryFullCount(ctx)
|
||||||
query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.VerificationRequest, pagination.Offset, pagination.Limit)
|
query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.VerificationRequest, pagination.Offset, pagination.Limit)
|
||||||
|
|
||||||
cursor, err := p.db.Query(sctx, query, nil)
|
cursor, err := p.db.Query(sctx, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
paginationClone.Total = cursor.Statistics().FullCount()
|
paginationClone.Total = cursor.Statistics().FullCount()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var verificationRequest models.VerificationRequest
|
var verificationRequest *models.VerificationRequest
|
||||||
meta, err := cursor.ReadDocument(ctx, &verificationRequest)
|
meta, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||||
|
|
||||||
if arangoDriver.IsNoMoreDocuments(err) {
|
if arangoDriver.IsNoMoreDocuments(err) {
|
||||||
|
@ -123,15 +111,14 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.VerificationRequests{
|
return &model.VerificationRequests{
|
||||||
VerificationRequests: verificationRequests,
|
VerificationRequests: verificationRequests,
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteVerificationRequest to delete verification request from database
|
// DeleteVerificationRequest to delete verification request from database
|
||||||
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error {
|
||||||
collection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
|
collection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
|
||||||
_, err := collection.RemoveDocument(ctx, verificationRequest.Key)
|
_, err := collection.RemoveDocument(ctx, verificationRequest.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -3,8 +3,10 @@ package arangodb
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/arangodb/go-driver"
|
||||||
arangoDriver "github.com/arangodb/go-driver"
|
arangoDriver "github.com/arangodb/go-driver"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
@ -12,13 +14,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddWebhook to add webhook
|
// AddWebhook to add webhook
|
||||||
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) {
|
||||||
if webhook.ID == "" {
|
if webhook.ID == "" {
|
||||||
webhook.ID = uuid.New().String()
|
webhook.ID = uuid.New().String()
|
||||||
webhook.Key = webhook.ID
|
webhook.Key = webhook.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
webhook.Key = webhook.ID
|
webhook.Key = webhook.ID
|
||||||
|
// Add timestamp to make event name unique for legacy version
|
||||||
|
webhook.EventName = fmt.Sprintf("%s-%d", webhook.EventName, time.Now().Unix())
|
||||||
webhook.CreatedAt = time.Now().Unix()
|
webhook.CreatedAt = time.Now().Unix()
|
||||||
webhook.UpdatedAt = time.Now().Unix()
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook)
|
webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook)
|
||||||
|
@ -30,39 +33,37 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateWebhook to update webhook
|
// UpdateWebhook to update webhook
|
||||||
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) {
|
||||||
webhook.UpdatedAt = time.Now().Unix()
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
|
// Event is changed
|
||||||
|
if !strings.Contains(webhook.EventName, "-") {
|
||||||
|
webhook.EventName = fmt.Sprintf("%s-%d", webhook.EventName, time.Now().Unix())
|
||||||
|
}
|
||||||
webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook)
|
webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook)
|
||||||
meta, err := webhookCollection.UpdateDocument(ctx, webhook.Key, webhook)
|
meta, err := webhookCollection.UpdateDocument(ctx, webhook.Key, webhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
webhook.Key = meta.Key
|
webhook.Key = meta.Key
|
||||||
webhook.ID = meta.ID.String()
|
webhook.ID = meta.ID.String()
|
||||||
return webhook.AsAPIWebhook(), nil
|
return webhook.AsAPIWebhook(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListWebhooks to list webhook
|
// ListWebhooks to list webhook
|
||||||
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
|
func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) {
|
||||||
webhooks := []*model.Webhook{}
|
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)
|
query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.Webhook, pagination.Offset, pagination.Limit)
|
||||||
|
|
||||||
sctx := arangoDriver.WithQueryFullCount(ctx)
|
sctx := arangoDriver.WithQueryFullCount(ctx)
|
||||||
cursor, err := p.db.Query(sctx, query, nil)
|
cursor, err := p.db.Query(sctx, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
paginationClone.Total = cursor.Statistics().FullCount()
|
paginationClone.Total = cursor.Statistics().FullCount()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var webhook models.Webhook
|
var webhook *models.Webhook
|
||||||
meta, err := cursor.ReadDocument(ctx, &webhook)
|
meta, err := cursor.ReadDocument(ctx, &webhook)
|
||||||
|
|
||||||
if arangoDriver.IsNoMoreDocuments(err) {
|
if arangoDriver.IsNoMoreDocuments(err) {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -75,28 +76,26 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.Webhooks{
|
return &model.Webhooks{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
Webhooks: webhooks,
|
Webhooks: webhooks,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhookByID to get webhook by id
|
// GetWebhookByID to get webhook by id
|
||||||
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
||||||
var webhook models.Webhook
|
var webhook *models.Webhook
|
||||||
query := fmt.Sprintf("FOR d in %s FILTER d._key == @webhook_id RETURN d", models.Collections.Webhook)
|
query := fmt.Sprintf("FOR d in %s FILTER d._key == @webhook_id RETURN d", models.Collections.Webhook)
|
||||||
bindVars := map[string]interface{}{
|
bindVars := map[string]interface{}{
|
||||||
"webhook_id": webhookID,
|
"webhook_id": webhookID,
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if webhook.Key == "" {
|
if webhook == nil {
|
||||||
return nil, fmt.Errorf("webhook not found")
|
return nil, fmt.Errorf("webhook not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
@ -110,32 +109,28 @@ func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhookByEventName to get webhook by event_name
|
// GetWebhookByEventName to get webhook by event_name
|
||||||
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
|
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 LIKE @event_name RETURN d", models.Collections.Webhook)
|
||||||
query := fmt.Sprintf("FOR d in %s FILTER d.event_name == @event_name RETURN d", models.Collections.Webhook)
|
|
||||||
bindVars := map[string]interface{}{
|
bindVars := map[string]interface{}{
|
||||||
"event_name": eventName,
|
"event_name": eventName + "%",
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
webhooks := []*model.Webhook{}
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
var webhook *models.Webhook
|
||||||
if webhook.Key == "" {
|
if _, err := cursor.ReadDocument(ctx, &webhook); driver.IsNoMoreDocuments(err) {
|
||||||
return nil, fmt.Errorf("webhook not found")
|
// We're done
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
} else if err != nil {
|
||||||
_, err := cursor.ReadDocument(ctx, &webhook)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||||
}
|
}
|
||||||
return webhook.AsAPIWebhook(), nil
|
return webhooks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWebhook to delete webhook
|
// DeleteWebhook to delete webhook
|
||||||
|
@ -145,17 +140,14 @@ func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) er
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
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{}{
|
bindVars := map[string]interface{}{
|
||||||
"webhook_id": webhook.ID,
|
"webhook_id": webhook.ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddWebhookLog to add webhook log
|
// AddWebhookLog to add webhook log
|
||||||
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
|
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) {
|
||||||
if webhookLog.ID == "" {
|
if webhookLog.ID == "" {
|
||||||
webhookLog.ID = uuid.New().String()
|
webhookLog.ID = uuid.New().String()
|
||||||
webhookLog.Key = webhookLog.ID
|
webhookLog.Key = webhookLog.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
webhookLog.Key = webhookLog.ID
|
webhookLog.Key = webhookLog.ID
|
||||||
webhookLog.CreatedAt = time.Now().Unix()
|
webhookLog.CreatedAt = time.Now().Unix()
|
||||||
webhookLog.UpdatedAt = time.Now().Unix()
|
webhookLog.UpdatedAt = time.Now().Unix()
|
||||||
|
@ -30,46 +29,38 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookL
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListWebhookLogs to list webhook logs
|
// ListWebhookLogs to list webhook logs
|
||||||
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
|
func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) {
|
||||||
webhookLogs := []*model.WebhookLog{}
|
webhookLogs := []*model.WebhookLog{}
|
||||||
bindVariables := map[string]interface{}{}
|
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)
|
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 != "" {
|
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)
|
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{}{
|
bindVariables = map[string]interface{}{
|
||||||
"webhook_id": webhookID,
|
"webhook_id": webhookID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sctx := arangoDriver.WithQueryFullCount(ctx)
|
sctx := arangoDriver.WithQueryFullCount(ctx)
|
||||||
cursor, err := p.db.Query(sctx, query, bindVariables)
|
cursor, err := p.db.Query(sctx, query, bindVariables)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
|
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
paginationClone.Total = cursor.Statistics().FullCount()
|
paginationClone.Total = cursor.Statistics().FullCount()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var webhookLog models.WebhookLog
|
var webhookLog *models.WebhookLog
|
||||||
meta, err := cursor.ReadDocument(ctx, &webhookLog)
|
meta, err := cursor.ReadDocument(ctx, &webhookLog)
|
||||||
|
|
||||||
if arangoDriver.IsNoMoreDocuments(err) {
|
if arangoDriver.IsNoMoreDocuments(err) {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if meta.Key != "" {
|
if meta.Key != "" {
|
||||||
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
|
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.WebhookLogs{
|
return &model.WebhookLogs{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
WebhookLogs: webhookLogs,
|
WebhookLogs: webhookLogs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
133
server/db/providers/cassandradb/authenticator.go
Normal file
133
server/db/providers/cassandradb/authenticator.go
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
package cassandradb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gocql/gocql"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
bytes, err := json.Marshal(authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
|
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||||
|
decoder.UseNumber()
|
||||||
|
authenticatorsMap := map[string]interface{}{}
|
||||||
|
err = decoder.Decode(&authenticatorsMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := "("
|
||||||
|
values := "("
|
||||||
|
for key, value := range authenticatorsMap {
|
||||||
|
if value != nil {
|
||||||
|
if key == "_id" {
|
||||||
|
fields += "id,"
|
||||||
|
} else {
|
||||||
|
fields += key + ","
|
||||||
|
}
|
||||||
|
|
||||||
|
valueType := reflect.TypeOf(value)
|
||||||
|
if valueType.Name() == "string" {
|
||||||
|
values += fmt.Sprintf("'%s',", value.(string))
|
||||||
|
} else {
|
||||||
|
values += fmt.Sprintf("%v,", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fields = fields[:len(fields)-1] + ")"
|
||||||
|
values = values[:len(values)-1] + ")"
|
||||||
|
|
||||||
|
query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.Authenticators, fields, values)
|
||||||
|
err = p.db.Query(query).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
bytes, err := json.Marshal(authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
|
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||||
|
decoder.UseNumber()
|
||||||
|
authenticatorsMap := map[string]interface{}{}
|
||||||
|
err = decoder.Decode(&authenticatorsMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFields := ""
|
||||||
|
for key, value := range authenticatorsMap {
|
||||||
|
if key == "_id" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == "_key" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if value == nil {
|
||||||
|
updateFields += fmt.Sprintf("%s = null, ", key)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
valueType := reflect.TypeOf(value)
|
||||||
|
if valueType.Name() == "string" {
|
||||||
|
updateFields += fmt.Sprintf("%s = '%s', ", key, value.(string))
|
||||||
|
} else {
|
||||||
|
updateFields += fmt.Sprintf("%s = %v, ", key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateFields = strings.Trim(updateFields, " ")
|
||||||
|
updateFields = strings.TrimSuffix(updateFields, ",")
|
||||||
|
|
||||||
|
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Authenticators, updateFields, authenticators.ID)
|
||||||
|
err = p.db.Query(query).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators models.Authenticator
|
||||||
|
query := fmt.Sprintf("SELECT id, user_id, method, secret, recovery_codes, verified_at, created_at, updated_at FROM %s WHERE user_id = '%s' AND method = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.Authenticators, userId, authenticatorType)
|
||||||
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&authenticators.ID, &authenticators.UserID, &authenticators.Method, &authenticators.Secret, &authenticators.RecoveryCodes, &authenticators.VerifiedAt, &authenticators.CreatedAt, &authenticators.UpdatedAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &authenticators, nil
|
||||||
|
}
|
|
@ -15,33 +15,28 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEmailTemplate to add EmailTemplate
|
// AddEmailTemplate to add EmailTemplate
|
||||||
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
if emailTemplate.ID == "" {
|
if emailTemplate.ID == "" {
|
||||||
emailTemplate.ID = uuid.New().String()
|
emailTemplate.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
emailTemplate.Key = emailTemplate.ID
|
emailTemplate.Key = emailTemplate.ID
|
||||||
emailTemplate.CreatedAt = time.Now().Unix()
|
emailTemplate.CreatedAt = time.Now().Unix()
|
||||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
emailTemplate.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
existingEmailTemplate, _ := p.GetEmailTemplateByEventName(ctx, emailTemplate.EventName)
|
existingEmailTemplate, _ := p.GetEmailTemplateByEventName(ctx, emailTemplate.EventName)
|
||||||
if existingEmailTemplate != nil {
|
if existingEmailTemplate != nil {
|
||||||
return nil, fmt.Errorf("Email template with %s event_name already exists", emailTemplate.EventName)
|
return nil, fmt.Errorf("Email template with %s event_name already exists", emailTemplate.EventName)
|
||||||
}
|
}
|
||||||
|
|
||||||
insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_name, subject, design, template, created_at, updated_at) VALUES ('%s', '%s', '%s','%s','%s', %d, %d)", KeySpace+"."+models.Collections.EmailTemplate, emailTemplate.ID, emailTemplate.EventName, emailTemplate.Subject, emailTemplate.Design, emailTemplate.Template, emailTemplate.CreatedAt, emailTemplate.UpdatedAt)
|
insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_name, subject, design, template, created_at, updated_at) VALUES ('%s', '%s', '%s','%s','%s', %d, %d)", KeySpace+"."+models.Collections.EmailTemplate, emailTemplate.ID, emailTemplate.EventName, emailTemplate.Subject, emailTemplate.Design, emailTemplate.Template, emailTemplate.CreatedAt, emailTemplate.UpdatedAt)
|
||||||
err := p.db.Query(insertQuery).Exec()
|
err := p.db.Query(insertQuery).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEmailTemplate to update EmailTemplate
|
// UpdateEmailTemplate to update EmailTemplate
|
||||||
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
emailTemplate.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
bytes, err := json.Marshal(emailTemplate)
|
bytes, err := json.Marshal(emailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -54,22 +49,18 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFields := ""
|
updateFields := ""
|
||||||
for key, value := range emailTemplateMap {
|
for key, value := range emailTemplateMap {
|
||||||
if key == "_id" {
|
if key == "_id" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if key == "_key" {
|
if key == "_key" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if value == nil {
|
if value == nil {
|
||||||
updateFields += fmt.Sprintf("%s = null,", key)
|
updateFields += fmt.Sprintf("%s = null,", key)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
valueType := reflect.TypeOf(value)
|
valueType := reflect.TypeOf(value)
|
||||||
if valueType.Name() == "string" {
|
if valueType.Name() == "string" {
|
||||||
updateFields += fmt.Sprintf("%s = '%s', ", key, value.(string))
|
updateFields += fmt.Sprintf("%s = '%s', ", key, value.(string))
|
||||||
|
@ -90,7 +81,7 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListEmailTemplates to list EmailTemplate
|
// ListEmailTemplates to list EmailTemplate
|
||||||
func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) {
|
func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) {
|
||||||
emailTemplates := []*model.EmailTemplate{}
|
emailTemplates := []*model.EmailTemplate{}
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
|
|
||||||
|
@ -120,7 +111,7 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.EmailTemplates{
|
return &model.EmailTemplates{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
EmailTemplates: emailTemplates,
|
EmailTemplates: emailTemplates,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,43 +11,39 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEnv to save environment information in database
|
// AddEnv to save environment information in database
|
||||||
func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) {
|
||||||
if env.ID == "" {
|
if env.ID == "" {
|
||||||
env.ID = uuid.New().String()
|
env.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
env.CreatedAt = time.Now().Unix()
|
env.CreatedAt = time.Now().Unix()
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
insertEnvQuery := fmt.Sprintf("INSERT INTO %s (id, env, hash, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.Env, env.ID, env.EnvData, env.Hash, env.CreatedAt, env.UpdatedAt)
|
insertEnvQuery := fmt.Sprintf("INSERT INTO %s (id, env, hash, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.Env, env.ID, env.EnvData, env.Hash, env.CreatedAt, env.UpdatedAt)
|
||||||
err := p.db.Query(insertEnvQuery).Exec()
|
err := p.db.Query(insertEnvQuery).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEnv to update environment information in database
|
// UpdateEnv to update environment information in database
|
||||||
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) {
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.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)
|
updateEnvQuery := fmt.Sprintf("UPDATE %s SET env = '%s', updated_at = %d WHERE id = '%s'", KeySpace+"."+models.Collections.Env, env.EnvData, env.UpdatedAt, env.ID)
|
||||||
err := p.db.Query(updateEnvQuery).Exec()
|
err := p.db.Query(updateEnvQuery).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEnv to get environment information from database
|
// GetEnv to get environment information from database
|
||||||
func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
|
func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
||||||
var env models.Env
|
var env models.Env
|
||||||
|
|
||||||
query := fmt.Sprintf("SELECT id, env, hash, created_at, updated_at FROM %s LIMIT 1", KeySpace+"."+models.Collections.Env)
|
query := fmt.Sprintf("SELECT id, env, hash, created_at, updated_at FROM %s LIMIT 1", KeySpace+"."+models.Collections.Env)
|
||||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&env.ID, &env.EnvData, &env.Hash, &env.CreatedAt, &env.UpdatedAt)
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&env.ID, &env.EnvData, &env.Hash, &env.CreatedAt, &env.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return &env, nil
|
||||||
return env, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cassandradb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -12,7 +13,20 @@ import (
|
||||||
|
|
||||||
// UpsertOTP to add or update otp
|
// UpsertOTP to add or update otp
|
||||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
|
// check if email or phone number is present
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||||
|
return nil, errors.New("email or phone_number is required")
|
||||||
|
}
|
||||||
|
uniqueField := models.FieldNameEmail
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||||
|
uniqueField = models.FieldNamePhoneNumber
|
||||||
|
}
|
||||||
|
var otp *models.OTP
|
||||||
|
if uniqueField == models.FieldNameEmail {
|
||||||
|
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||||
|
} else {
|
||||||
|
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||||
|
}
|
||||||
shouldCreate := false
|
shouldCreate := false
|
||||||
if otp == nil {
|
if otp == nil {
|
||||||
shouldCreate = true
|
shouldCreate = true
|
||||||
|
@ -20,6 +34,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
ID: uuid.NewString(),
|
ID: uuid.NewString(),
|
||||||
Otp: otpParam.Otp,
|
Otp: otpParam.Otp,
|
||||||
Email: otpParam.Email,
|
Email: otpParam.Email,
|
||||||
|
PhoneNumber: otpParam.PhoneNumber,
|
||||||
ExpiresAt: otpParam.ExpiresAt,
|
ExpiresAt: otpParam.ExpiresAt,
|
||||||
CreatedAt: time.Now().Unix(),
|
CreatedAt: time.Now().Unix(),
|
||||||
UpdatedAt: time.Now().Unix(),
|
UpdatedAt: time.Now().Unix(),
|
||||||
|
@ -32,7 +47,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
otp.UpdatedAt = time.Now().Unix()
|
otp.UpdatedAt = time.Now().Unix()
|
||||||
query := ""
|
query := ""
|
||||||
if shouldCreate {
|
if shouldCreate {
|
||||||
query = fmt.Sprintf(`INSERT INTO %s (id, email, otp, expires_at, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d, %d)`, KeySpace+"."+models.Collections.OTP, otp.ID, otp.Email, otp.Otp, otp.ExpiresAt, otp.CreatedAt, otp.UpdatedAt)
|
query = fmt.Sprintf(`INSERT INTO %s (id, email, phone_number, otp, expires_at, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)`, KeySpace+"."+models.Collections.OTP, otp.ID, otp.Email, otp.PhoneNumber, otp.Otp, otp.ExpiresAt, otp.CreatedAt, otp.UpdatedAt)
|
||||||
} else {
|
} else {
|
||||||
query = fmt.Sprintf(`UPDATE %s SET otp = '%s', expires_at = %d, updated_at = %d WHERE id = '%s'`, KeySpace+"."+models.Collections.OTP, otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID)
|
query = fmt.Sprintf(`UPDATE %s SET otp = '%s', expires_at = %d, updated_at = %d WHERE id = '%s'`, KeySpace+"."+models.Collections.OTP, otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID)
|
||||||
}
|
}
|
||||||
|
@ -48,8 +63,19 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
// GetOTPByEmail to get otp for a given email address
|
// GetOTPByEmail to get otp for a given email address
|
||||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||||
var otp models.OTP
|
var otp models.OTP
|
||||||
query := fmt.Sprintf(`SELECT id, email, otp, expires_at, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.OTP, emailAddress)
|
query := fmt.Sprintf(`SELECT id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.OTP, emailAddress)
|
||||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt)
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.PhoneNumber, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &otp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOTPByPhoneNumber to get otp for a given phone number
|
||||||
|
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
|
||||||
|
var otp models.OTP
|
||||||
|
query := fmt.Sprintf(`SELECT id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.OTP, phoneNumber)
|
||||||
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.PhoneNumber, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,6 +207,13 @@ func NewProvider() (*provider, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// add event_description to webhook table
|
||||||
|
webhookAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (event_description text);`, KeySpace, models.Collections.Webhook)
|
||||||
|
err = session.Query(webhookAlterQuery).Exec()
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to alter table as column exists: ", err)
|
||||||
|
// continue
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
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()
|
err = session.Query(webhookLogCollectionQuery).Exec()
|
||||||
|
@ -247,6 +254,32 @@ func NewProvider() (*provider, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// Add phone_number column to otp table
|
||||||
|
otpAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (phone_number text);`, KeySpace, models.Collections.OTP)
|
||||||
|
err = session.Query(otpAlterQuery).Exec()
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to alter table as column exists: ", err)
|
||||||
|
// continue
|
||||||
|
}
|
||||||
|
// Add app_data column to users table
|
||||||
|
appDataAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (app_data text);`, KeySpace, models.Collections.User)
|
||||||
|
err = session.Query(appDataAlterQuery).Exec()
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to alter user table as app_data column exists: ", err)
|
||||||
|
// continue
|
||||||
|
}
|
||||||
|
// Add phone number index
|
||||||
|
otpIndexQueryPhoneNumber := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_otp_phone_number ON %s.%s (phone_number)", KeySpace, models.Collections.OTP)
|
||||||
|
err = session.Query(otpIndexQueryPhoneNumber).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// add authenticators table
|
||||||
|
totpCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, user_id text, method text, secret text, recovery_codes text, verified_at bigint, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.Authenticators)
|
||||||
|
err = session.Query(totpCollectionQuery).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &provider{
|
return &provider{
|
||||||
db: session,
|
db: session,
|
||||||
|
|
|
@ -10,14 +10,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddSession to save session information in database
|
// AddSession to save session information in database
|
||||||
func (p *provider) AddSession(ctx context.Context, session models.Session) error {
|
func (p *provider) AddSession(ctx context.Context, session *models.Session) error {
|
||||||
if session.ID == "" {
|
if session.ID == "" {
|
||||||
session.ID = uuid.New().String()
|
session.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
session.CreatedAt = time.Now().Unix()
|
session.CreatedAt = time.Now().Unix()
|
||||||
session.UpdatedAt = time.Now().Unix()
|
session.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
insertSessionQuery := fmt.Sprintf("INSERT INTO %s (id, user_id, user_agent, ip, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.Session, session.ID, session.UserID, session.UserAgent, session.IP, session.CreatedAt, session.UpdatedAt)
|
insertSessionQuery := fmt.Sprintf("INSERT INTO %s (id, user_id, user_agent, ip, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.Session, session.ID, session.UserID, session.UserAgent, session.IP, session.CreatedAt, session.UpdatedAt)
|
||||||
err := p.db.Query(insertSessionQuery).Exec()
|
err := p.db.Query(insertSessionQuery).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -25,3 +23,8 @@ func (p *provider) AddSession(ctx context.Context, session models.Session) error
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteSession to delete session information from database
|
||||||
|
func (p *provider) DeleteSession(ctx context.Context, userId string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddUser to save user information in database
|
// AddUser to save user information in database
|
||||||
func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) {
|
||||||
if user.ID == "" {
|
if user.ID == "" {
|
||||||
user.ID = uuid.New().String()
|
user.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
if user.Roles == "" {
|
if user.Roles == "" {
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,10 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||||
return user, fmt.Errorf("user with given phone number already exists")
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
}
|
}
|
||||||
|
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||||
|
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given email already exists")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
|
@ -42,7 +46,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
|
|
||||||
bytes, err := json.Marshal(user)
|
bytes, err := json.Marshal(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
|
@ -51,7 +55,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
userMap := map[string]interface{}{}
|
userMap := map[string]interface{}{}
|
||||||
err = decoder.Decode(&userMap)
|
err = decoder.Decode(&userMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := "("
|
fields := "("
|
||||||
|
@ -77,22 +81,22 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
values = values[:len(values)-1] + ")"
|
values = values[:len(values)-1] + ")"
|
||||||
|
|
||||||
query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.User, fields, values)
|
query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.User, fields, values)
|
||||||
|
|
||||||
err = p.db.Query(query).Exec()
|
err = p.db.Query(query).Exec()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUser to update user information in database
|
// UpdateUser to update user information in database
|
||||||
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) {
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
bytes, err := json.Marshal(user)
|
bytes, err := json.Marshal(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||||
|
@ -100,7 +104,7 @@ func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.Use
|
||||||
userMap := map[string]interface{}{}
|
userMap := map[string]interface{}{}
|
||||||
err = decoder.Decode(&userMap)
|
err = decoder.Decode(&userMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFields := ""
|
updateFields := ""
|
||||||
|
@ -131,20 +135,19 @@ func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.Use
|
||||||
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, updateFields, user.ID)
|
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, updateFields, user.ID)
|
||||||
err = p.db.Query(query).Exec()
|
err = p.db.Query(query).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUser to delete user information from database
|
// DeleteUser to delete user information from database
|
||||||
func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
func (p *provider) DeleteUser(ctx context.Context, user *models.User) error {
|
||||||
query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, user.ID)
|
query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, user.ID)
|
||||||
err := p.db.Query(query).Exec()
|
err := p.db.Query(query).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
getSessionsQuery := fmt.Sprintf("SELECT id FROM %s WHERE user_id = '%s' ALLOW FILTERING", KeySpace+"."+models.Collections.Session, user.ID)
|
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()
|
scanner := p.db.Query(getSessionsQuery).Iter().Scanner()
|
||||||
sessionIDs := ""
|
sessionIDs := ""
|
||||||
|
@ -167,7 +170,7 @@ func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListUsers to get list of users from database
|
// ListUsers to get list of users from database
|
||||||
func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
|
func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) {
|
||||||
responseUsers := []*model.User{}
|
responseUsers := []*model.User{}
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.User)
|
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.User)
|
||||||
|
@ -179,14 +182,17 @@ func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (
|
||||||
// there is no offset in cassandra
|
// there is no offset in cassandra
|
||||||
// so we fetch till limit + offset
|
// so we fetch till limit + offset
|
||||||
// and return the results from offset to limit
|
// and return the results from offset to limit
|
||||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.User, pagination.Limit+pagination.Offset)
|
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.User,
|
||||||
|
pagination.Limit+pagination.Offset)
|
||||||
scanner := p.db.Query(query).Iter().Scanner()
|
scanner := p.db.Query(query).Iter().Scanner()
|
||||||
counter := int64(0)
|
counter := int64(0)
|
||||||
for scanner.Next() {
|
for scanner.Next() {
|
||||||
if counter >= pagination.Offset {
|
if counter >= pagination.Offset {
|
||||||
var user models.User
|
var user models.User
|
||||||
err := scanner.Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.CreatedAt, &user.UpdatedAt)
|
err := scanner.Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods,
|
||||||
|
&user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber,
|
||||||
|
&user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled,
|
||||||
|
&user.AppData, &user.CreatedAt, &user.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -195,31 +201,31 @@ func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (
|
||||||
counter++
|
counter++
|
||||||
}
|
}
|
||||||
return &model.Users{
|
return &model.Users{
|
||||||
|
Pagination: paginationClone,
|
||||||
Users: responseUsers,
|
Users: responseUsers,
|
||||||
Pagination: &paginationClone,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByEmail to get user information from database using email address
|
// GetUserByEmail to get user information from database using email address
|
||||||
func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
|
func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) {
|
||||||
var user models.User
|
var user models.User
|
||||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, email)
|
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, email)
|
||||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.CreatedAt, &user.UpdatedAt)
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.AppData, &user.CreatedAt, &user.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return &user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByID to get user information from database using user ID
|
// GetUserByID to get user information from database using user ID
|
||||||
func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
|
func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) {
|
||||||
var user models.User
|
var user models.User
|
||||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1", KeySpace+"."+models.Collections.User, id)
|
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1", KeySpace+"."+models.Collections.User, id)
|
||||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.CreatedAt, &user.UpdatedAt)
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.AppData, &user.CreatedAt, &user.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return &user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
||||||
|
@ -252,9 +258,8 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
}
|
}
|
||||||
updateFields = strings.Trim(updateFields, " ")
|
updateFields = strings.Trim(updateFields, " ")
|
||||||
updateFields = strings.TrimSuffix(updateFields, ",")
|
updateFields = strings.TrimSuffix(updateFields, ",")
|
||||||
|
|
||||||
query := ""
|
query := ""
|
||||||
if ids != nil && len(ids) > 0 {
|
if len(ids) > 0 {
|
||||||
idsString := ""
|
idsString := ""
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
idsString += fmt.Sprintf("'%s', ", id)
|
idsString += fmt.Sprintf("'%s', ", id)
|
||||||
|
@ -301,17 +306,15 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByPhoneNumber to get user information from database using phone number
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
var user models.User
|
var user models.User
|
||||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, phoneNumber)
|
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, phoneNumber)
|
||||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.CreatedAt, &user.UpdatedAt)
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.AppData, &user.CreatedAt, &user.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddVerification to save verification request in database
|
// AddVerification to save verification request in database
|
||||||
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
|
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) {
|
||||||
if verificationRequest.ID == "" {
|
if verificationRequest.ID == "" {
|
||||||
verificationRequest.ID = uuid.New().String()
|
verificationRequest.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
@ -23,47 +23,45 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
||||||
query := fmt.Sprintf("INSERT INTO %s (id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, '%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.VerificationRequest, verificationRequest.ID, verificationRequest.Token, verificationRequest.Identifier, verificationRequest.ExpiresAt, verificationRequest.Email, verificationRequest.Nonce, verificationRequest.RedirectURI, verificationRequest.CreatedAt, verificationRequest.UpdatedAt)
|
query := fmt.Sprintf("INSERT INTO %s (id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, '%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.VerificationRequest, verificationRequest.ID, verificationRequest.Token, verificationRequest.Identifier, verificationRequest.ExpiresAt, verificationRequest.Email, verificationRequest.Nonce, verificationRequest.RedirectURI, verificationRequest.CreatedAt, verificationRequest.UpdatedAt)
|
||||||
err := p.db.Query(query).Exec()
|
err := p.db.Query(query).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVerificationRequestByToken to get verification request from database using token
|
// GetVerificationRequestByToken to get verification request from database using token
|
||||||
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
|
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) {
|
||||||
var verificationRequest models.VerificationRequest
|
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)
|
query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE jwt_token = '%s' LIMIT 1`, KeySpace+"."+models.Collections.VerificationRequest, token)
|
||||||
|
|
||||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&verificationRequest.ID, &verificationRequest.Token, &verificationRequest.Identifier, &verificationRequest.ExpiresAt, &verificationRequest.Email, &verificationRequest.Nonce, &verificationRequest.RedirectURI, &verificationRequest.CreatedAt, &verificationRequest.UpdatedAt)
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&verificationRequest.ID, &verificationRequest.Token, &verificationRequest.Identifier, &verificationRequest.ExpiresAt, &verificationRequest.Email, &verificationRequest.Nonce, &verificationRequest.RedirectURI, &verificationRequest.CreatedAt, &verificationRequest.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return &verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVerificationRequestByEmail to get verification request by email from database
|
// GetVerificationRequestByEmail to get verification request by email from database
|
||||||
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
|
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) {
|
||||||
var verificationRequest models.VerificationRequest
|
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)
|
query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE email = '%s' AND identifier = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.VerificationRequest, email, identifier)
|
||||||
|
|
||||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&verificationRequest.ID, &verificationRequest.Token, &verificationRequest.Identifier, &verificationRequest.ExpiresAt, &verificationRequest.Email, &verificationRequest.Nonce, &verificationRequest.RedirectURI, &verificationRequest.CreatedAt, &verificationRequest.UpdatedAt)
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&verificationRequest.ID, &verificationRequest.Token, &verificationRequest.Identifier, &verificationRequest.ExpiresAt, &verificationRequest.Email, &verificationRequest.Nonce, &verificationRequest.RedirectURI, &verificationRequest.CreatedAt, &verificationRequest.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return verificationRequest, nil
|
return &verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListVerificationRequests to get list of verification requests from database
|
// ListVerificationRequests to get list of verification requests from database
|
||||||
func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
|
func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) {
|
||||||
var verificationRequests []*model.VerificationRequest
|
var verificationRequests []*model.VerificationRequest
|
||||||
|
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.VerificationRequest)
|
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.VerificationRequest)
|
||||||
err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total)
|
err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// there is no offset in cassandra
|
// there is no offset in cassandra
|
||||||
// so we fetch till limit + offset
|
// so we fetch till limit + offset
|
||||||
// and return the results from offset to limit
|
// and return the results from offset to limit
|
||||||
|
@ -85,12 +83,12 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode
|
||||||
|
|
||||||
return &model.VerificationRequests{
|
return &model.VerificationRequests{
|
||||||
VerificationRequests: verificationRequests,
|
VerificationRequests: verificationRequests,
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteVerificationRequest to delete verification request from database
|
// DeleteVerificationRequest to delete verification request from database
|
||||||
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error {
|
||||||
query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.VerificationRequest, verificationRequest.ID)
|
query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.VerificationRequest, verificationRequest.ID)
|
||||||
err := p.db.Query(query).Exec()
|
err := p.db.Query(query).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -15,33 +15,30 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddWebhook to add webhook
|
// AddWebhook to add webhook
|
||||||
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) {
|
||||||
if webhook.ID == "" {
|
if webhook.ID == "" {
|
||||||
webhook.ID = uuid.New().String()
|
webhook.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
webhook.Key = webhook.ID
|
webhook.Key = webhook.ID
|
||||||
webhook.CreatedAt = time.Now().Unix()
|
webhook.CreatedAt = time.Now().Unix()
|
||||||
webhook.UpdatedAt = time.Now().Unix()
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
|
// Add timestamp to make event name unique for legacy version
|
||||||
existingHook, _ := p.GetWebhookByEventName(ctx, webhook.EventName)
|
webhook.EventName = fmt.Sprintf("%s-%d", webhook.EventName, time.Now().Unix())
|
||||||
if existingHook != nil {
|
insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_description, event_name, endpoint, headers, enabled, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', '%s', %t, %d, %d)", KeySpace+"."+models.Collections.Webhook, webhook.ID, webhook.EventDescription, webhook.EventName, webhook.EndPoint, webhook.Headers, webhook.Enabled, webhook.CreatedAt, webhook.UpdatedAt)
|
||||||
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()
|
err := p.db.Query(insertQuery).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return webhook.AsAPIWebhook(), nil
|
return webhook.AsAPIWebhook(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateWebhook to update webhook
|
// UpdateWebhook to update webhook
|
||||||
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) {
|
||||||
webhook.UpdatedAt = time.Now().Unix()
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
|
// Event is changed
|
||||||
|
if !strings.Contains(webhook.EventName, "-") {
|
||||||
|
webhook.EventName = fmt.Sprintf("%s-%d", webhook.EventName, time.Now().Unix())
|
||||||
|
}
|
||||||
bytes, err := json.Marshal(webhook)
|
bytes, err := json.Marshal(webhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -54,22 +51,18 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFields := ""
|
updateFields := ""
|
||||||
for key, value := range webhookMap {
|
for key, value := range webhookMap {
|
||||||
if key == "_id" {
|
if key == "_id" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if key == "_key" {
|
if key == "_key" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if value == nil {
|
if value == nil {
|
||||||
updateFields += fmt.Sprintf("%s = null,", key)
|
updateFields += fmt.Sprintf("%s = null,", key)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
valueType := reflect.TypeOf(value)
|
valueType := reflect.TypeOf(value)
|
||||||
if valueType.Name() == "string" {
|
if valueType.Name() == "string" {
|
||||||
updateFields += fmt.Sprintf("%s = '%s', ", key, value.(string))
|
updateFields += fmt.Sprintf("%s = '%s', ", key, value.(string))
|
||||||
|
@ -79,7 +72,6 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*
|
||||||
}
|
}
|
||||||
updateFields = strings.Trim(updateFields, " ")
|
updateFields = strings.Trim(updateFields, " ")
|
||||||
updateFields = strings.TrimSuffix(updateFields, ",")
|
updateFields = strings.TrimSuffix(updateFields, ",")
|
||||||
|
|
||||||
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Webhook, updateFields, webhook.ID)
|
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Webhook, updateFields, webhook.ID)
|
||||||
err = p.db.Query(query).Exec()
|
err = p.db.Query(query).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -89,27 +81,24 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListWebhooks to list webhook
|
// ListWebhooks to list webhook
|
||||||
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
|
func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) {
|
||||||
webhooks := []*model.Webhook{}
|
webhooks := []*model.Webhook{}
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
|
|
||||||
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.Webhook)
|
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.Webhook)
|
||||||
err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total)
|
err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// there is no offset in cassandra
|
// there is no offset in cassandra
|
||||||
// so we fetch till limit + offset
|
// so we fetch till limit + offset
|
||||||
// and return the results from offset to limit
|
// and return the results from offset to limit
|
||||||
query := fmt.Sprintf("SELECT id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.Webhook, pagination.Limit+pagination.Offset)
|
query := fmt.Sprintf("SELECT id, event_description, 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()
|
scanner := p.db.Query(query).Iter().Scanner()
|
||||||
counter := int64(0)
|
counter := int64(0)
|
||||||
for scanner.Next() {
|
for scanner.Next() {
|
||||||
if counter >= pagination.Offset {
|
if counter >= pagination.Offset {
|
||||||
var webhook models.Webhook
|
var webhook models.Webhook
|
||||||
err := scanner.Scan(&webhook.ID, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
|
err := scanner.Scan(&webhook.ID, &webhook.EventDescription, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -119,7 +108,7 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.Webhooks{
|
return &model.Webhooks{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
Webhooks: webhooks,
|
Webhooks: webhooks,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -127,8 +116,8 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
||||||
// GetWebhookByID to get webhook by id
|
// GetWebhookByID to get webhook by id
|
||||||
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
||||||
var webhook models.Webhook
|
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)
|
query := fmt.Sprintf(`SELECT id, event_description, 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)
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&webhook.ID, &webhook.EventDescription, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -136,14 +125,19 @@ func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhookByEventName to get webhook by event_name
|
// GetWebhookByEventName to get webhook by event_name
|
||||||
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
|
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*model.Webhook, error) {
|
||||||
|
query := fmt.Sprintf(`SELECT id, event_description, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s WHERE event_name LIKE '%s' ALLOW FILTERING`, KeySpace+"."+models.Collections.Webhook, eventName+"%")
|
||||||
|
scanner := p.db.Query(query).Iter().Scanner()
|
||||||
|
webhooks := []*model.Webhook{}
|
||||||
|
for scanner.Next() {
|
||||||
var webhook models.Webhook
|
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 := scanner.Scan(&webhook.ID, &webhook.EventDescription, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
|
||||||
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return webhook.AsAPIWebhook(), nil
|
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||||
|
}
|
||||||
|
return webhooks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWebhook to delete webhook
|
// DeleteWebhook to delete webhook
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddWebhookLog to add webhook log
|
// AddWebhookLog to add webhook log
|
||||||
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
|
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) {
|
||||||
if webhookLog.ID == "" {
|
if webhookLog.ID == "" {
|
||||||
webhookLog.ID = uuid.New().String()
|
webhookLog.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookL
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListWebhookLogs to list webhook logs
|
// ListWebhookLogs to list webhook logs
|
||||||
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
|
func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) {
|
||||||
webhookLogs := []*model.WebhookLog{}
|
webhookLogs := []*model.WebhookLog{}
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.WebhookLog)
|
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.WebhookLog)
|
||||||
|
@ -38,7 +38,6 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat
|
||||||
// so we fetch till limit + offset
|
// so we fetch till limit + offset
|
||||||
// and return the results from offset to limit
|
// and return the results from offset to limit
|
||||||
query := fmt.Sprintf("SELECT id, http_status, response, request, webhook_id, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.WebhookLog, pagination.Limit+pagination.Offset)
|
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 != "" {
|
if webhookID != "" {
|
||||||
totalCountQuery = fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE webhook_id='%s' ALLOW FILTERING`, KeySpace+"."+models.Collections.WebhookLog, 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)
|
query = fmt.Sprintf("SELECT id, http_status, response, request, webhook_id, created_at, updated_at FROM %s WHERE webhook_id = '%s' LIMIT %d ALLOW FILTERING", KeySpace+"."+models.Collections.WebhookLog, webhookID, pagination.Limit+pagination.Offset)
|
||||||
|
@ -64,7 +63,7 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.WebhookLogs{
|
return &model.WebhookLogs{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
WebhookLogs: webhookLogs,
|
WebhookLogs: webhookLogs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
81
server/db/providers/couchbase/authenticator.go
Normal file
81
server/db/providers/couchbase/authenticator.go
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
authenticators.Key = authenticators.ID
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.Authenticators).Insert(authenticators.ID, authenticators, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
bytes, err := json.Marshal(authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
|
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||||
|
decoder.UseNumber()
|
||||||
|
authenticator := map[string]interface{}{}
|
||||||
|
err = decoder.Decode(&authenticator)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
updateFields, params := GetSetFields(authenticator)
|
||||||
|
query := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = '%s'", p.scopeName, models.Collections.Authenticators, updateFields, authenticators.ID)
|
||||||
|
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators *models.Authenticator
|
||||||
|
query := fmt.Sprintf("SELECT _id, user_id, method, secret, recovery_code, verified_at, created_at, updated_at FROM %s.%s WHERE user_id = $1 AND method = $2 LIMIT 1", p.scopeName, models.Collections.Authenticators)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{userId, authenticatorType},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = q.One(&authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEmailTemplate to add EmailTemplate
|
// AddEmailTemplate to add EmailTemplate
|
||||||
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
|
|
||||||
if emailTemplate.ID == "" {
|
if emailTemplate.ID == "" {
|
||||||
emailTemplate.ID = uuid.New().String()
|
emailTemplate.ID = uuid.New().String()
|
||||||
|
@ -37,7 +37,7 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEmailTemplate to update EmailTemplate
|
// UpdateEmailTemplate to update EmailTemplate
|
||||||
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
bytes, err := json.Marshal(emailTemplate)
|
bytes, err := json.Marshal(emailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -67,7 +67,7 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListEmailTemplates to list EmailTemplate
|
// ListEmailTemplates to list EmailTemplate
|
||||||
func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) {
|
func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) {
|
||||||
emailTemplates := []*model.EmailTemplate{}
|
emailTemplates := []*model.EmailTemplate{}
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
total, err := p.GetTotalDocs(ctx, models.Collections.EmailTemplate)
|
total, err := p.GetTotalDocs(ctx, models.Collections.EmailTemplate)
|
||||||
|
@ -88,7 +88,7 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin
|
||||||
}
|
}
|
||||||
|
|
||||||
for queryResult.Next() {
|
for queryResult.Next() {
|
||||||
emailTemplate := models.EmailTemplate{}
|
var emailTemplate *models.EmailTemplate
|
||||||
err := queryResult.Row(&emailTemplate)
|
err := queryResult.Row(&emailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
@ -102,54 +102,46 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.EmailTemplates{
|
return &model.EmailTemplates{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
EmailTemplates: emailTemplates,
|
EmailTemplates: emailTemplates,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEmailTemplateByID to get EmailTemplate by id
|
// GetEmailTemplateByID to get EmailTemplate by id
|
||||||
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
||||||
emailTemplate := models.EmailTemplate{}
|
var emailTemplate *models.EmailTemplate
|
||||||
|
|
||||||
query := fmt.Sprintf(`SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1`, p.scopeName, models.Collections.EmailTemplate)
|
query := fmt.Sprintf(`SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1`, p.scopeName, models.Collections.EmailTemplate)
|
||||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
PositionalParameters: []interface{}{emailTemplateID},
|
PositionalParameters: []interface{}{emailTemplateID},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&emailTemplate)
|
err = q.One(&emailTemplate)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
||||||
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
||||||
emailTemplate := models.EmailTemplate{}
|
var emailTemplate models.EmailTemplate
|
||||||
|
|
||||||
query := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE event_name=$1 LIMIT 1", p.scopeName, models.Collections.EmailTemplate)
|
query := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE event_name=$1 LIMIT 1", p.scopeName, models.Collections.EmailTemplate)
|
||||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
PositionalParameters: []interface{}{eventName},
|
PositionalParameters: []interface{}{eventName},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&emailTemplate)
|
err = q.One(&emailTemplate)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEnv to save environment information in database
|
// AddEnv to save environment information in database
|
||||||
func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) {
|
||||||
if env.ID == "" {
|
if env.ID == "" {
|
||||||
env.ID = uuid.New().String()
|
env.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
@ -19,19 +19,18 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
env.Key = env.ID
|
env.Key = env.ID
|
||||||
env.EncryptionKey = env.Hash
|
env.EncryptionKey = env.Hash
|
||||||
|
|
||||||
insertOpt := gocb.InsertOptions{
|
insertOpt := gocb.InsertOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
}
|
}
|
||||||
_, err := p.db.Collection(models.Collections.Env).Insert(env.ID, env, &insertOpt)
|
_, err := p.db.Collection(models.Collections.Env).Insert(env.ID, env, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEnv to update environment information in database
|
// UpdateEnv to update environment information in database
|
||||||
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) {
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
env.EncryptionKey = env.Hash
|
env.EncryptionKey = env.Hash
|
||||||
|
|
||||||
|
@ -40,17 +39,15 @@ func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, e
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
PositionalParameters: []interface{}{env.EnvData, env.UpdatedAt, env.UpdatedAt, env.ID},
|
PositionalParameters: []interface{}{env.EnvData, env.UpdatedAt, env.UpdatedAt, env.ID},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEnv to get environment information from database
|
// GetEnv to get environment information from database
|
||||||
func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
|
func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
||||||
var env models.Env
|
var env *models.Env
|
||||||
|
|
||||||
query := fmt.Sprintf("SELECT _id, env, encryption_key, created_at, updated_at FROM %s.%s LIMIT 1", p.scopeName, models.Collections.Env)
|
query := fmt.Sprintf("SELECT _id, env, encryption_key, created_at, updated_at FROM %s.%s LIMIT 1", p.scopeName, models.Collections.Env)
|
||||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
@ -58,12 +55,11 @@ func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&env)
|
err = q.One(&env)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
env.Hash = env.EncryptionKey
|
env.Hash = env.EncryptionKey
|
||||||
return env, nil
|
return env, nil
|
||||||
|
|
|
@ -2,6 +2,7 @@ package couchbase
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -12,8 +13,20 @@ import (
|
||||||
|
|
||||||
// UpsertOTP to add or update otp
|
// UpsertOTP to add or update otp
|
||||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
|
// check if email or phone number is present
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||||
|
return nil, errors.New("email or phone_number is required")
|
||||||
|
}
|
||||||
|
uniqueField := models.FieldNameEmail
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||||
|
uniqueField = models.FieldNamePhoneNumber
|
||||||
|
}
|
||||||
|
var otp *models.OTP
|
||||||
|
if uniqueField == models.FieldNameEmail {
|
||||||
|
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||||
|
} else {
|
||||||
|
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||||
|
}
|
||||||
shouldCreate := false
|
shouldCreate := false
|
||||||
if otp == nil {
|
if otp == nil {
|
||||||
shouldCreate = true
|
shouldCreate = true
|
||||||
|
@ -21,6 +34,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
ID: uuid.NewString(),
|
ID: uuid.NewString(),
|
||||||
Otp: otpParam.Otp,
|
Otp: otpParam.Otp,
|
||||||
Email: otpParam.Email,
|
Email: otpParam.Email,
|
||||||
|
PhoneNumber: otpParam.PhoneNumber,
|
||||||
ExpiresAt: otpParam.ExpiresAt,
|
ExpiresAt: otpParam.ExpiresAt,
|
||||||
CreatedAt: time.Now().Unix(),
|
CreatedAt: time.Now().Unix(),
|
||||||
UpdatedAt: time.Now().Unix(),
|
UpdatedAt: time.Now().Unix(),
|
||||||
|
@ -29,7 +43,6 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
otp.Otp = otpParam.Otp
|
otp.Otp = otpParam.Otp
|
||||||
otp.ExpiresAt = otpParam.ExpiresAt
|
otp.ExpiresAt = otpParam.ExpiresAt
|
||||||
}
|
}
|
||||||
|
|
||||||
otp.UpdatedAt = time.Now().Unix()
|
otp.UpdatedAt = time.Now().Unix()
|
||||||
if shouldCreate {
|
if shouldCreate {
|
||||||
insertOpt := gocb.InsertOptions{
|
insertOpt := gocb.InsertOptions{
|
||||||
|
@ -37,7 +50,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
}
|
}
|
||||||
_, err := p.db.Collection(models.Collections.OTP).Insert(otp.ID, otp, &insertOpt)
|
_, err := p.db.Collection(models.Collections.OTP).Insert(otp.ID, otp, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return otp, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
query := fmt.Sprintf(`UPDATE %s.%s SET otp=$1, expires_at=$2, updated_at=$3 WHERE _id=$4`, p.scopeName, models.Collections.OTP)
|
query := fmt.Sprintf(`UPDATE %s.%s SET otp=$1, expires_at=$2, updated_at=$3 WHERE _id=$4`, p.scopeName, models.Collections.OTP)
|
||||||
|
@ -45,7 +58,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
PositionalParameters: []interface{}{otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID},
|
PositionalParameters: []interface{}{otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return otp, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return otp, nil
|
return otp, nil
|
||||||
|
@ -54,7 +67,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
// GetOTPByEmail to get otp for a given email address
|
// GetOTPByEmail to get otp for a given email address
|
||||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||||
otp := models.OTP{}
|
otp := models.OTP{}
|
||||||
query := fmt.Sprintf(`SELECT _id, email, otp, expires_at, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1`, p.scopeName, models.Collections.OTP)
|
query := fmt.Sprintf(`SELECT _id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1`, p.scopeName, models.Collections.OTP)
|
||||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
PositionalParameters: []interface{}{emailAddress},
|
PositionalParameters: []interface{}{emailAddress},
|
||||||
|
@ -63,11 +76,27 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&otp)
|
err = q.One(&otp)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return &otp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOTPByPhoneNumber to get otp for a given phone number
|
||||||
|
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
|
||||||
|
otp := models.OTP{}
|
||||||
|
query := fmt.Sprintf(`SELECT _id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1`, p.scopeName, models.Collections.OTP)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{phoneNumber},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = q.One(&otp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return &otp, nil
|
return &otp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ func CreateBucketAndScope(cluster *gocb.Cluster, bucketName string, scopeName st
|
||||||
if scopeName != defaultScope {
|
if scopeName != defaultScope {
|
||||||
err = bucket.Collections().CreateScope(scopeName, nil)
|
err = bucket.Collections().CreateScope(scopeName, nil)
|
||||||
if err != nil && !errors.Is(err, gocb.ErrScopeExists) {
|
if err != nil && !errors.Is(err, gocb.ErrScopeExists) {
|
||||||
return bucket, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bucket, nil
|
return bucket, nil
|
||||||
|
@ -166,5 +166,9 @@ func GetIndex(scopeName string) map[string][]string {
|
||||||
otpIndex1 := fmt.Sprintf("CREATE INDEX OTPEmailIndex ON %s.%s(email)", scopeName, models.Collections.OTP)
|
otpIndex1 := fmt.Sprintf("CREATE INDEX OTPEmailIndex ON %s.%s(email)", scopeName, models.Collections.OTP)
|
||||||
indices[models.Collections.OTP] = []string{otpIndex1}
|
indices[models.Collections.OTP] = []string{otpIndex1}
|
||||||
|
|
||||||
|
// OTP index
|
||||||
|
otpIndex2 := fmt.Sprintf("CREATE INDEX OTPPhoneNumberIndex ON %s.%s(phone_number)", scopeName, models.Collections.OTP)
|
||||||
|
indices[models.Collections.OTP] = []string{otpIndex2}
|
||||||
|
|
||||||
return indices
|
return indices
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddSession to save session information in database
|
// AddSession to save session information in database
|
||||||
func (p *provider) AddSession(ctx context.Context, session models.Session) error {
|
func (p *provider) AddSession(ctx context.Context, session *models.Session) error {
|
||||||
if session.ID == "" {
|
if session.ID == "" {
|
||||||
session.ID = uuid.New().String()
|
session.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
session.CreatedAt = time.Now().Unix()
|
session.CreatedAt = time.Now().Unix()
|
||||||
session.UpdatedAt = time.Now().Unix()
|
session.UpdatedAt = time.Now().Unix()
|
||||||
insertOpt := gocb.InsertOptions{
|
insertOpt := gocb.InsertOptions{
|
||||||
|
@ -24,7 +23,6 @@ func (p *provider) AddSession(ctx context.Context, session models.Session) error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,24 +11,19 @@ import (
|
||||||
|
|
||||||
func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interface{}) {
|
func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interface{}) {
|
||||||
params := make(map[string]interface{}, 1)
|
params := make(map[string]interface{}, 1)
|
||||||
|
|
||||||
updateFields := ""
|
updateFields := ""
|
||||||
|
|
||||||
for key, value := range webhookMap {
|
for key, value := range webhookMap {
|
||||||
if key == "_id" {
|
if key == "_id" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if key == "_key" {
|
if key == "_key" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if value == nil {
|
if value == nil {
|
||||||
updateFields += fmt.Sprintf("%s=$%s,", key, key)
|
updateFields += fmt.Sprintf("%s=$%s,", key, key)
|
||||||
params[key] = "null"
|
params[key] = "null"
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
valueType := reflect.TypeOf(value)
|
valueType := reflect.TypeOf(value)
|
||||||
if valueType.Name() == "string" {
|
if valueType.Name() == "string" {
|
||||||
updateFields += fmt.Sprintf("%s = $%s, ", key, key)
|
updateFields += fmt.Sprintf("%s = $%s, ", key, key)
|
||||||
|
@ -46,16 +41,13 @@ func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interfa
|
||||||
|
|
||||||
func (p *provider) GetTotalDocs(ctx context.Context, collection string) (int64, error) {
|
func (p *provider) GetTotalDocs(ctx context.Context, collection string) (int64, error) {
|
||||||
totalDocs := TotalDocs{}
|
totalDocs := TotalDocs{}
|
||||||
|
|
||||||
countQuery := fmt.Sprintf("SELECT COUNT(*) as Total FROM %s.%s", p.scopeName, collection)
|
countQuery := fmt.Sprintf("SELECT COUNT(*) as Total FROM %s.%s", p.scopeName, collection)
|
||||||
queryRes, err := p.db.Query(countQuery, &gocb.QueryOptions{
|
queryRes, err := p.db.Query(countQuery, &gocb.QueryOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
})
|
})
|
||||||
|
|
||||||
queryRes.One(&totalDocs)
|
queryRes.One(&totalDocs)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return totalDocs.Total, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return totalDocs.Total, nil
|
return totalDocs.Total, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,20 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
"github.com/couchbase/gocb/v2"
|
"github.com/couchbase/gocb/v2"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddUser to save user information in database
|
// AddUser to save user information in database
|
||||||
func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) {
|
||||||
if user.ID == "" {
|
if user.ID == "" {
|
||||||
user.ID = uuid.New().String()
|
user.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
@ -23,11 +25,21 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
if user.Roles == "" {
|
if user.Roles == "" {
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
|
}
|
||||||
|
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||||
|
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given email already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
insertOpt := gocb.InsertOptions{
|
insertOpt := gocb.InsertOptions{
|
||||||
|
@ -35,26 +47,26 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
}
|
}
|
||||||
_, err := p.db.Collection(models.Collections.User).Insert(user.ID, user, &insertOpt)
|
_, err := p.db.Collection(models.Collections.User).Insert(user.ID, user, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUser to update user information in database
|
// UpdateUser to update user information in database
|
||||||
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) {
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
unsertOpt := gocb.UpsertOptions{
|
upsertOpt := gocb.UpsertOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
}
|
}
|
||||||
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &unsertOpt)
|
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &upsertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUser to delete user information from database
|
// DeleteUser to delete user information from database
|
||||||
func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
func (p *provider) DeleteUser(ctx context.Context, user *models.User) error {
|
||||||
removeOpt := gocb.RemoveOptions{
|
removeOpt := gocb.RemoveOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
}
|
}
|
||||||
|
@ -66,12 +78,10 @@ func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListUsers to get list of users from database
|
// ListUsers to get list of users from database
|
||||||
func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
|
func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) {
|
||||||
users := []*model.User{}
|
users := []*model.User{}
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
|
userQuery := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s ORDER BY id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.User)
|
||||||
userQuery := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s ORDER BY id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.User)
|
|
||||||
|
|
||||||
queryResult, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
queryResult, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
|
@ -97,49 +107,46 @@ func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &model.Users{
|
return &model.Users{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
Users: users,
|
Users: users,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByEmail to get user information from database using email address
|
// GetUserByEmail to get user information from database using email address
|
||||||
func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
|
func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) {
|
||||||
user := models.User{}
|
var user *models.User
|
||||||
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
PositionalParameters: []interface{}{email},
|
PositionalParameters: []interface{}{email},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&user)
|
err = q.One(&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByID to get user information from database using user ID
|
// GetUserByID to get user information from database using user ID
|
||||||
func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
|
func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) {
|
||||||
user := models.User{}
|
var user *models.User
|
||||||
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
PositionalParameters: []interface{}{id},
|
PositionalParameters: []interface{}{id},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&user)
|
err = q.One(&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,26 +181,24 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByPhoneNumber to get user information from database using phone number
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
var user *models.User
|
var user *models.User
|
||||||
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
PositionalParameters: []interface{}{phoneNumber},
|
PositionalParameters: []interface{}{phoneNumber},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&user)
|
err = q.One(&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddVerification to save verification request in database
|
// AddVerification to save verification request in database
|
||||||
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
|
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) {
|
||||||
if verificationRequest.ID == "" {
|
if verificationRequest.ID == "" {
|
||||||
verificationRequest.ID = uuid.New().String()
|
verificationRequest.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
verificationRequest.Key = verificationRequest.ID
|
verificationRequest.Key = verificationRequest.ID
|
||||||
verificationRequest.CreatedAt = time.Now().Unix()
|
verificationRequest.CreatedAt = time.Now().Unix()
|
||||||
verificationRequest.UpdatedAt = time.Now().Unix()
|
verificationRequest.UpdatedAt = time.Now().Unix()
|
||||||
|
@ -26,15 +25,14 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
||||||
}
|
}
|
||||||
_, err := p.db.Collection(models.Collections.VerificationRequest).Insert(verificationRequest.ID, verificationRequest, &insertOpt)
|
_, err := p.db.Collection(models.Collections.VerificationRequest).Insert(verificationRequest.ID, verificationRequest, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVerificationRequestByToken to get verification request from database using token
|
// GetVerificationRequestByToken to get verification request from database using token
|
||||||
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
|
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) {
|
||||||
verificationRequest := models.VerificationRequest{}
|
var verificationRequest *models.VerificationRequest
|
||||||
params := make(map[string]interface{}, 1)
|
params := make(map[string]interface{}, 1)
|
||||||
params["token"] = token
|
params["token"] = token
|
||||||
query := fmt.Sprintf("SELECT _id, token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE token=$1 LIMIT 1", p.scopeName, models.Collections.VerificationRequest)
|
query := fmt.Sprintf("SELECT _id, token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE token=$1 LIMIT 1", p.scopeName, models.Collections.VerificationRequest)
|
||||||
|
@ -46,18 +44,18 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = queryResult.One(&verificationRequest)
|
err = queryResult.One(&verificationRequest)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVerificationRequestByEmail to get verification request by email from database
|
// GetVerificationRequestByEmail to get verification request by email from database
|
||||||
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
|
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) {
|
||||||
|
|
||||||
query := fmt.Sprintf("SELECT _id, identifier, token, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE email=$1 AND identifier=$2 LIMIT 1", p.scopeName, models.Collections.VerificationRequest)
|
query := fmt.Sprintf("SELECT _id, identifier, token, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE email=$1 AND identifier=$2 LIMIT 1", p.scopeName, models.Collections.VerificationRequest)
|
||||||
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
@ -65,22 +63,19 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
||||||
PositionalParameters: []interface{}{email, identifier},
|
PositionalParameters: []interface{}{email, identifier},
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
})
|
})
|
||||||
verificationRequest := models.VerificationRequest{}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
var verificationRequest *models.VerificationRequest
|
||||||
err = queryResult.One(&verificationRequest)
|
err = queryResult.One(&verificationRequest)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListVerificationRequests to get list of verification requests from database
|
// ListVerificationRequests to get list of verification requests from database
|
||||||
func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
|
func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) {
|
||||||
var verificationRequests []*model.VerificationRequest
|
var verificationRequests []*model.VerificationRequest
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
total, err := p.GetTotalDocs(ctx, models.Collections.VerificationRequest)
|
total, err := p.GetTotalDocs(ctx, models.Collections.VerificationRequest)
|
||||||
|
@ -111,12 +106,12 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode
|
||||||
}
|
}
|
||||||
return &model.VerificationRequests{
|
return &model.VerificationRequests{
|
||||||
VerificationRequests: verificationRequests,
|
VerificationRequests: verificationRequests,
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteVerificationRequest to delete verification request from database
|
// DeleteVerificationRequest to delete verification request from database
|
||||||
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error {
|
||||||
removeOpt := gocb.RemoveOptions{
|
removeOpt := gocb.RemoveOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,29 +15,32 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddWebhook to add webhook
|
// AddWebhook to add webhook
|
||||||
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) {
|
||||||
if webhook.ID == "" {
|
if webhook.ID == "" {
|
||||||
webhook.ID = uuid.New().String()
|
webhook.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
webhook.Key = webhook.ID
|
webhook.Key = webhook.ID
|
||||||
webhook.CreatedAt = time.Now().Unix()
|
webhook.CreatedAt = time.Now().Unix()
|
||||||
webhook.UpdatedAt = time.Now().Unix()
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
|
// Add timestamp to make event name unique for legacy version
|
||||||
|
webhook.EventName = fmt.Sprintf("%s-%d", webhook.EventName, time.Now().Unix())
|
||||||
insertOpt := gocb.InsertOptions{
|
insertOpt := gocb.InsertOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
}
|
}
|
||||||
_, err := p.db.Collection(models.Collections.Webhook).Insert(webhook.ID, webhook, &insertOpt)
|
_, err := p.db.Collection(models.Collections.Webhook).Insert(webhook.ID, webhook, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return webhook.AsAPIWebhook(), err
|
return nil, err
|
||||||
}
|
}
|
||||||
return webhook.AsAPIWebhook(), nil
|
return webhook.AsAPIWebhook(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateWebhook to update webhook
|
// UpdateWebhook to update webhook
|
||||||
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) {
|
||||||
webhook.UpdatedAt = time.Now().Unix()
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
|
// Event is changed
|
||||||
|
if !strings.Contains(webhook.EventName, "-") {
|
||||||
|
webhook.EventName = fmt.Sprintf("%s-%d", webhook.EventName, time.Now().Unix())
|
||||||
|
}
|
||||||
bytes, err := json.Marshal(webhook)
|
bytes, err := json.Marshal(webhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -50,17 +53,13 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFields, params := GetSetFields(webhookMap)
|
updateFields, params := GetSetFields(webhookMap)
|
||||||
|
|
||||||
query := fmt.Sprintf(`UPDATE %s.%s SET %s WHERE _id='%s'`, p.scopeName, models.Collections.Webhook, updateFields, webhook.ID)
|
query := fmt.Sprintf(`UPDATE %s.%s SET %s WHERE _id='%s'`, p.scopeName, models.Collections.Webhook, updateFields, webhook.ID)
|
||||||
|
|
||||||
_, err = p.db.Query(query, &gocb.QueryOptions{
|
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
NamedParameters: params,
|
NamedParameters: params,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -69,10 +68,9 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListWebhooks to list webhook
|
// ListWebhooks to list webhook
|
||||||
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
|
func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) {
|
||||||
webhooks := []*model.Webhook{}
|
webhooks := []*model.Webhook{}
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
|
|
||||||
params := make(map[string]interface{}, 1)
|
params := make(map[string]interface{}, 1)
|
||||||
params["offset"] = paginationClone.Offset
|
params["offset"] = paginationClone.Offset
|
||||||
params["limit"] = paginationClone.Limit
|
params["limit"] = paginationClone.Limit
|
||||||
|
@ -81,7 +79,7 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
paginationClone.Total = total
|
paginationClone.Total = total
|
||||||
query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM %s.%s OFFSET $offset LIMIT $limit", p.scopeName, models.Collections.Webhook)
|
query := fmt.Sprintf("SELECT _id, event_description, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s.%s OFFSET $offset LIMIT $limit", p.scopeName, models.Collections.Webhook)
|
||||||
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
@ -102,19 +100,17 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &model.Webhooks{
|
return &model.Webhooks{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
Webhooks: webhooks,
|
Webhooks: webhooks,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhookByID to get webhook by id
|
// GetWebhookByID to get webhook by id
|
||||||
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
||||||
var webhook models.Webhook
|
var webhook *models.Webhook
|
||||||
|
|
||||||
params := make(map[string]interface{}, 1)
|
params := make(map[string]interface{}, 1)
|
||||||
params["_id"] = webhookID
|
params["_id"] = webhookID
|
||||||
|
query := fmt.Sprintf(`SELECT _id, event_description, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s.%s WHERE _id=$_id LIMIT 1`, p.scopeName, models.Collections.Webhook)
|
||||||
query := fmt.Sprintf(`SELECT _id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s.%s WHERE _id=$_id LIMIT 1`, p.scopeName, models.Collections.Webhook)
|
|
||||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
@ -124,53 +120,51 @@ func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&webhook)
|
err = q.One(&webhook)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return webhook.AsAPIWebhook(), nil
|
return webhook.AsAPIWebhook(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhookByEventName to get webhook by event_name
|
// GetWebhookByEventName to get webhook by event_name
|
||||||
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
|
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*model.Webhook, error) {
|
||||||
var webhook models.Webhook
|
|
||||||
params := make(map[string]interface{}, 1)
|
params := make(map[string]interface{}, 1)
|
||||||
params["event_name"] = eventName
|
// params["event_name"] = eventName + "%"
|
||||||
|
query := fmt.Sprintf(`SELECT _id, event_description, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s.%s WHERE event_name LIKE '%s'`, p.scopeName, models.Collections.Webhook, eventName+"%")
|
||||||
query := fmt.Sprintf(`SELECT _id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s.%s WHERE event_name=$event_name LIMIT 1`, p.scopeName, models.Collections.Webhook)
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
NamedParameters: params,
|
NamedParameters: params,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&webhook)
|
webhooks := []*model.Webhook{}
|
||||||
|
for queryResult.Next() {
|
||||||
|
var webhook *models.Webhook
|
||||||
|
err := queryResult.Row(&webhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||||
|
}
|
||||||
|
if err := queryResult.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return webhooks, nil
|
||||||
return webhook.AsAPIWebhook(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWebhook to delete webhook
|
// DeleteWebhook to delete webhook
|
||||||
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
||||||
|
|
||||||
params := make(map[string]interface{}, 1)
|
params := make(map[string]interface{}, 1)
|
||||||
params["webhook_id"] = webhook.ID
|
params["webhook_id"] = webhook.ID
|
||||||
removeOpt := gocb.RemoveOptions{
|
removeOpt := gocb.RemoveOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
}
|
}
|
||||||
_, err := p.db.Collection(models.Collections.Webhook).Remove(webhook.ID, &removeOpt)
|
_, err := p.db.Collection(models.Collections.Webhook).Remove(webhook.ID, &removeOpt)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
query := fmt.Sprintf(`DELETE FROM %s.%s WHERE webhook_id=$webhook_id`, p.scopeName, models.Collections.WebhookLog)
|
query := fmt.Sprintf(`DELETE FROM %s.%s WHERE webhook_id=$webhook_id`, p.scopeName, models.Collections.WebhookLog)
|
||||||
_, err = p.db.Query(query, &gocb.QueryOptions{
|
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
|
@ -180,6 +174,5 @@ func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) er
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,35 +13,30 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddWebhookLog to add webhook log
|
// AddWebhookLog to add webhook log
|
||||||
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
|
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) {
|
||||||
if webhookLog.ID == "" {
|
if webhookLog.ID == "" {
|
||||||
webhookLog.ID = uuid.New().String()
|
webhookLog.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
webhookLog.Key = webhookLog.ID
|
webhookLog.Key = webhookLog.ID
|
||||||
webhookLog.CreatedAt = time.Now().Unix()
|
webhookLog.CreatedAt = time.Now().Unix()
|
||||||
webhookLog.UpdatedAt = time.Now().Unix()
|
webhookLog.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
insertOpt := gocb.InsertOptions{
|
insertOpt := gocb.InsertOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
}
|
}
|
||||||
_, err := p.db.Collection(models.Collections.WebhookLog).Insert(webhookLog.ID, webhookLog, &insertOpt)
|
_, err := p.db.Collection(models.Collections.WebhookLog).Insert(webhookLog.ID, webhookLog, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return webhookLog.AsAPIWebhookLog(), err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return webhookLog.AsAPIWebhookLog(), nil
|
return webhookLog.AsAPIWebhookLog(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListWebhookLogs to list webhook logs
|
// ListWebhookLogs to list webhook logs
|
||||||
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
|
func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) {
|
||||||
var query string
|
var query string
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
webhookLogs := []*model.WebhookLog{}
|
webhookLogs := []*model.WebhookLog{}
|
||||||
params := make(map[string]interface{}, 1)
|
params := make(map[string]interface{}, 1)
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
|
|
||||||
params["webhookID"] = webhookID
|
params["webhookID"] = webhookID
|
||||||
params["offset"] = paginationClone.Offset
|
params["offset"] = paginationClone.Offset
|
||||||
params["limit"] = paginationClone.Limit
|
params["limit"] = paginationClone.Limit
|
||||||
|
@ -55,13 +50,11 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat
|
||||||
} else {
|
} else {
|
||||||
query = fmt.Sprintf("SELECT _id, http_status, response, request, webhook_id, created_at, updated_at FROM %s.%s OFFSET $offset LIMIT $limit", p.scopeName, models.Collections.WebhookLog)
|
query = fmt.Sprintf("SELECT _id, http_status, response, request, webhook_id, created_at, updated_at FROM %s.%s OFFSET $offset LIMIT $limit", p.scopeName, models.Collections.WebhookLog)
|
||||||
}
|
}
|
||||||
|
|
||||||
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
NamedParameters: params,
|
NamedParameters: params,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -73,13 +66,12 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat
|
||||||
}
|
}
|
||||||
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
|
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := queryResult.Err(); err != nil {
|
if err := queryResult.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
||||||
}
|
}
|
||||||
return &model.WebhookLogs{
|
return &model.WebhookLogs{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
WebhookLogs: webhookLogs,
|
WebhookLogs: webhookLogs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
57
server/db/providers/dynamodb/authenticator.go
Normal file
57
server/db/providers/dynamodb/authenticator.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package dynamodb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
collection := p.db.Table(models.Collections.Authenticators)
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
err := collection.Put(authenticators).RunWithContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
collection := p.db.Table(models.Collections.Authenticators)
|
||||||
|
if authenticators.ID != "" {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
err := UpdateByHashKey(collection, "id", authenticators.ID, authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators *models.Authenticator
|
||||||
|
collection := p.db.Table(models.Collections.Authenticators)
|
||||||
|
iter := collection.Scan().Filter("'user_id' = ?", userId).Filter("'method' = ?", authenticatorType).Iter()
|
||||||
|
for iter.NextWithContext(ctx, &authenticators) {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
err := iter.Err()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEmailTemplate to add EmailTemplate
|
// AddEmailTemplate to add EmailTemplate
|
||||||
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
collection := p.db.Table(models.Collections.EmailTemplate)
|
collection := p.db.Table(models.Collections.EmailTemplate)
|
||||||
if emailTemplate.ID == "" {
|
if emailTemplate.ID == "" {
|
||||||
emailTemplate.ID = uuid.New().String()
|
emailTemplate.ID = uuid.New().String()
|
||||||
|
@ -31,7 +31,7 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEmailTemplate to update EmailTemplate
|
// UpdateEmailTemplate to update EmailTemplate
|
||||||
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
collection := p.db.Table(models.Collections.EmailTemplate)
|
collection := p.db.Table(models.Collections.EmailTemplate)
|
||||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
emailTemplate.UpdatedAt = time.Now().Unix()
|
||||||
err := UpdateByHashKey(collection, "id", emailTemplate.ID, emailTemplate)
|
err := UpdateByHashKey(collection, "id", emailTemplate.ID, emailTemplate)
|
||||||
|
@ -42,23 +42,19 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListEmailTemplates to list EmailTemplate
|
// ListEmailTemplates to list EmailTemplate
|
||||||
func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) {
|
func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) {
|
||||||
|
var emailTemplate *models.EmailTemplate
|
||||||
var emailTemplate models.EmailTemplate
|
|
||||||
var iter dynamo.PagingIter
|
var iter dynamo.PagingIter
|
||||||
var lastEval dynamo.PagingKey
|
var lastEval dynamo.PagingKey
|
||||||
var iteration int64 = 0
|
var iteration int64 = 0
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.EmailTemplate)
|
collection := p.db.Table(models.Collections.EmailTemplate)
|
||||||
emailTemplates := []*model.EmailTemplate{}
|
emailTemplates := []*model.EmailTemplate{}
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
scanner := collection.Scan()
|
scanner := collection.Scan()
|
||||||
count, err := scanner.Count()
|
count, err := scanner.Count()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for (paginationClone.Offset + paginationClone.Limit) > iteration {
|
for (paginationClone.Offset + paginationClone.Limit) > iteration {
|
||||||
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
|
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
|
||||||
for iter.NextWithContext(ctx, &emailTemplate) {
|
for iter.NextWithContext(ctx, &emailTemplate) {
|
||||||
|
@ -69,11 +65,9 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin
|
||||||
lastEval = iter.LastEvaluatedKey()
|
lastEval = iter.LastEvaluatedKey()
|
||||||
iteration += paginationClone.Limit
|
iteration += paginationClone.Limit
|
||||||
}
|
}
|
||||||
|
|
||||||
paginationClone.Total = count
|
paginationClone.Total = count
|
||||||
|
|
||||||
return &model.EmailTemplates{
|
return &model.EmailTemplates{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
EmailTemplates: emailTemplates,
|
EmailTemplates: emailTemplates,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -81,7 +75,7 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin
|
||||||
// GetEmailTemplateByID to get EmailTemplate by id
|
// GetEmailTemplateByID to get EmailTemplate by id
|
||||||
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
||||||
collection := p.db.Table(models.Collections.EmailTemplate)
|
collection := p.db.Table(models.Collections.EmailTemplate)
|
||||||
var emailTemplate models.EmailTemplate
|
var emailTemplate *models.EmailTemplate
|
||||||
err := collection.Get("id", emailTemplateID).OneWithContext(ctx, &emailTemplate)
|
err := collection.Get("id", emailTemplateID).OneWithContext(ctx, &emailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -92,9 +86,8 @@ func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID str
|
||||||
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
||||||
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
||||||
collection := p.db.Table(models.Collections.EmailTemplate)
|
collection := p.db.Table(models.Collections.EmailTemplate)
|
||||||
var emailTemplates []models.EmailTemplate
|
var emailTemplates []*models.EmailTemplate
|
||||||
var emailTemplate models.EmailTemplate
|
var emailTemplate *models.EmailTemplate
|
||||||
|
|
||||||
err := collection.Scan().Index("event_name").Filter("'event_name' = ?", eventName).Limit(1).AllWithContext(ctx, &emailTemplates)
|
err := collection.Scan().Index("event_name").Filter("'event_name' = ?", eventName).Limit(1).AllWithContext(ctx, &emailTemplates)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -112,7 +105,6 @@ func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName st
|
||||||
func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error {
|
func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error {
|
||||||
collection := p.db.Table(models.Collections.EmailTemplate)
|
collection := p.db.Table(models.Collections.EmailTemplate)
|
||||||
err := collection.Delete("id", emailTemplate.ID).RunWithContext(ctx)
|
err := collection.Delete("id", emailTemplate.ID).RunWithContext(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,61 +11,48 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEnv to save environment information in database
|
// AddEnv to save environment information in database
|
||||||
func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) {
|
||||||
collection := p.db.Table(models.Collections.Env)
|
collection := p.db.Table(models.Collections.Env)
|
||||||
|
|
||||||
if env.ID == "" {
|
if env.ID == "" {
|
||||||
env.ID = uuid.New().String()
|
env.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
env.Key = env.ID
|
env.Key = env.ID
|
||||||
|
|
||||||
env.CreatedAt = time.Now().Unix()
|
env.CreatedAt = time.Now().Unix()
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
err := collection.Put(env).RunWithContext(ctx)
|
err := collection.Put(env).RunWithContext(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEnv to update environment information in database
|
// UpdateEnv to update environment information in database
|
||||||
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) {
|
||||||
collection := p.db.Table(models.Collections.Env)
|
collection := p.db.Table(models.Collections.Env)
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
err := UpdateByHashKey(collection, "id", env.ID, env)
|
err := UpdateByHashKey(collection, "id", env.ID, env)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEnv to get environment information from database
|
// GetEnv to get environment information from database
|
||||||
func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
|
func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
||||||
var env models.Env
|
var env *models.Env
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.Env)
|
collection := p.db.Table(models.Collections.Env)
|
||||||
// As there is no Findone supported.
|
// As there is no Findone supported.
|
||||||
iter := collection.Scan().Limit(1).Iter()
|
iter := collection.Scan().Limit(1).Iter()
|
||||||
|
|
||||||
for iter.NextWithContext(ctx, &env) {
|
for iter.NextWithContext(ctx, &env) {
|
||||||
if env.ID == "" {
|
if env == nil {
|
||||||
return env, errors.New("no documets found")
|
return nil, errors.New("no documets found")
|
||||||
} else {
|
} else {
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := iter.Err()
|
err := iter.Err()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, fmt.Errorf("config not found")
|
return env, fmt.Errorf("config not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,20 @@ import (
|
||||||
|
|
||||||
// UpsertOTP to add or update otp
|
// UpsertOTP to add or update otp
|
||||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
|
// check if email or phone number is present
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||||
|
return nil, errors.New("email or phone_number is required")
|
||||||
|
}
|
||||||
|
uniqueField := models.FieldNameEmail
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||||
|
uniqueField = models.FieldNamePhoneNumber
|
||||||
|
}
|
||||||
|
var otp *models.OTP
|
||||||
|
if uniqueField == models.FieldNameEmail {
|
||||||
|
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||||
|
} else {
|
||||||
|
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||||
|
}
|
||||||
shouldCreate := false
|
shouldCreate := false
|
||||||
if otp == nil {
|
if otp == nil {
|
||||||
id := uuid.NewString()
|
id := uuid.NewString()
|
||||||
|
@ -20,6 +33,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
Key: id,
|
Key: id,
|
||||||
Otp: otpParam.Otp,
|
Otp: otpParam.Otp,
|
||||||
Email: otpParam.Email,
|
Email: otpParam.Email,
|
||||||
|
PhoneNumber: otpParam.PhoneNumber,
|
||||||
ExpiresAt: otpParam.ExpiresAt,
|
ExpiresAt: otpParam.ExpiresAt,
|
||||||
CreatedAt: time.Now().Unix(),
|
CreatedAt: time.Now().Unix(),
|
||||||
}
|
}
|
||||||
|
@ -28,10 +42,8 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
otp.Otp = otpParam.Otp
|
otp.Otp = otpParam.Otp
|
||||||
otp.ExpiresAt = otpParam.ExpiresAt
|
otp.ExpiresAt = otpParam.ExpiresAt
|
||||||
}
|
}
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.OTP)
|
collection := p.db.Table(models.Collections.OTP)
|
||||||
otp.UpdatedAt = time.Now().Unix()
|
otp.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if shouldCreate {
|
if shouldCreate {
|
||||||
err = collection.Put(otp).RunWithContext(ctx)
|
err = collection.Put(otp).RunWithContext(ctx)
|
||||||
|
@ -41,7 +53,6 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return otp, nil
|
return otp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,32 +60,42 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||||
var otps []models.OTP
|
var otps []models.OTP
|
||||||
var otp models.OTP
|
var otp models.OTP
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.OTP)
|
collection := p.db.Table(models.Collections.OTP)
|
||||||
|
|
||||||
err := collection.Scan().Index("email").Filter("'email' = ?", emailAddress).Limit(1).AllWithContext(ctx, &otps)
|
err := collection.Scan().Index("email").Filter("'email' = ?", emailAddress).Limit(1).AllWithContext(ctx, &otps)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(otps) > 0 {
|
if len(otps) > 0 {
|
||||||
otp = otps[0]
|
otp = otps[0]
|
||||||
return &otp, nil
|
return &otp, nil
|
||||||
} else {
|
}
|
||||||
return nil, errors.New("no docuemnt found")
|
return nil, errors.New("no docuemnt found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOTPByPhoneNumber to get otp for a given phone number
|
||||||
|
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
|
||||||
|
var otps []models.OTP
|
||||||
|
var otp models.OTP
|
||||||
|
collection := p.db.Table(models.Collections.OTP)
|
||||||
|
err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).Limit(1).AllWithContext(ctx, &otps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(otps) > 0 {
|
||||||
|
otp = otps[0]
|
||||||
|
return &otp, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("no docuemnt found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOTP to delete otp
|
// DeleteOTP to delete otp
|
||||||
func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error {
|
func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error {
|
||||||
collection := p.db.Table(models.Collections.OTP)
|
collection := p.db.Table(models.Collections.OTP)
|
||||||
|
|
||||||
if otp.ID != "" {
|
if otp.ID != "" {
|
||||||
err := collection.Delete("id", otp.ID).RunWithContext(ctx)
|
err := collection.Delete("id", otp.ID).RunWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,21 +31,19 @@ func NewProvider() (*provider, error) {
|
||||||
if awsRegion != "" {
|
if awsRegion != "" {
|
||||||
config.Region = aws.String(awsRegion)
|
config.Region = aws.String(awsRegion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// custom awsAccessKeyID, awsSecretAccessKey took first priority, if not then fetch config from aws credentials
|
// custom awsAccessKeyID, awsSecretAccessKey took first priority, if not then fetch config from aws credentials
|
||||||
if awsAccessKeyID != "" && awsSecretAccessKey != "" {
|
if awsAccessKeyID != "" && awsSecretAccessKey != "" {
|
||||||
config.Credentials = credentials.NewStaticCredentials(awsAccessKeyID, awsSecretAccessKey, "")
|
config.Credentials = credentials.NewStaticCredentials(awsAccessKeyID, awsSecretAccessKey, "")
|
||||||
} else if dbURL != "" {
|
} else if dbURL != "" {
|
||||||
|
log.Debug("Tring to use database url for dynamodb")
|
||||||
// static config in case of testing or local-setup
|
// static config in case of testing or local-setup
|
||||||
config.Credentials = credentials.NewStaticCredentials("key", "key", "")
|
config.Credentials = credentials.NewStaticCredentials("key", "key", "")
|
||||||
config.Endpoint = aws.String(dbURL)
|
config.Endpoint = aws.String(dbURL)
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("%s or %s or %s not found. Trying to load default credentials from aws config", constants.EnvAwsRegion, constants.EnvAwsAccessKeyID, constants.EnvAwsSecretAccessKey)
|
log.Debugf("%s or %s or %s not found. Trying to load default credentials from aws config", constants.EnvAwsRegion, constants.EnvAwsAccessKeyID, constants.EnvAwsSecretAccessKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
session := session.Must(session.NewSession(&config))
|
session := session.Must(session.NewSession(&config))
|
||||||
db := dynamo.New(session)
|
db := dynamo.New(session)
|
||||||
|
|
||||||
db.CreateTable(models.Collections.User, models.User{}).Wait()
|
db.CreateTable(models.Collections.User, models.User{}).Wait()
|
||||||
db.CreateTable(models.Collections.Session, models.Session{}).Wait()
|
db.CreateTable(models.Collections.Session, models.Session{}).Wait()
|
||||||
db.CreateTable(models.Collections.EmailTemplate, models.EmailTemplate{}).Wait()
|
db.CreateTable(models.Collections.EmailTemplate, models.EmailTemplate{}).Wait()
|
||||||
|
@ -54,7 +52,7 @@ func NewProvider() (*provider, error) {
|
||||||
db.CreateTable(models.Collections.VerificationRequest, models.VerificationRequest{}).Wait()
|
db.CreateTable(models.Collections.VerificationRequest, models.VerificationRequest{}).Wait()
|
||||||
db.CreateTable(models.Collections.Webhook, models.Webhook{}).Wait()
|
db.CreateTable(models.Collections.Webhook, models.Webhook{}).Wait()
|
||||||
db.CreateTable(models.Collections.WebhookLog, models.WebhookLog{}).Wait()
|
db.CreateTable(models.Collections.WebhookLog, models.WebhookLog{}).Wait()
|
||||||
|
db.CreateTable(models.Collections.Authenticators, models.Authenticator{}).Wait()
|
||||||
return &provider{
|
return &provider{
|
||||||
db: db,
|
db: db,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
|
@ -9,13 +9,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddSession to save session information in database
|
// AddSession to save session information in database
|
||||||
func (p *provider) AddSession(ctx context.Context, session models.Session) error {
|
func (p *provider) AddSession(ctx context.Context, session *models.Session) error {
|
||||||
collection := p.db.Table(models.Collections.Session)
|
collection := p.db.Table(models.Collections.Session)
|
||||||
|
|
||||||
if session.ID == "" {
|
if session.ID == "" {
|
||||||
session.ID = uuid.New().String()
|
session.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
session.CreatedAt = time.Now().Unix()
|
session.CreatedAt = time.Now().Unix()
|
||||||
session.UpdatedAt = time.Now().Unix()
|
session.UpdatedAt = time.Now().Unix()
|
||||||
err := collection.Put(session).RunWithContext(ctx)
|
err := collection.Put(session).RunWithContext(ctx)
|
||||||
|
|
|
@ -9,16 +9,13 @@ import (
|
||||||
func UpdateByHashKey(table dynamo.Table, hashKey string, hashValue string, item interface{}) error {
|
func UpdateByHashKey(table dynamo.Table, hashKey string, hashValue string, item interface{}) error {
|
||||||
existingValue, err := dynamo.MarshalItem(item)
|
existingValue, err := dynamo.MarshalItem(item)
|
||||||
var i interface{}
|
var i interface{}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
nullableValue, err := dynamodbattribute.MarshalMap(item)
|
nullableValue, err := dynamodbattribute.MarshalMap(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
u := table.Update(hashKey, hashValue)
|
u := table.Update(hashKey, hashValue)
|
||||||
for k, v := range existingValue {
|
for k, v := range existingValue {
|
||||||
if k == hashKey {
|
if k == hashKey {
|
||||||
|
@ -26,7 +23,6 @@ func UpdateByHashKey(table dynamo.Table, hashKey string, hashValue string, item
|
||||||
}
|
}
|
||||||
u = u.Set(k, v)
|
u = u.Set(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range nullableValue {
|
for k, v := range nullableValue {
|
||||||
if k == hashKey {
|
if k == hashKey {
|
||||||
continue
|
continue
|
||||||
|
@ -36,11 +32,9 @@ func UpdateByHashKey(table dynamo.Table, hashKey string, hashValue string, item
|
||||||
u = u.SetNullable(k, v)
|
u = u.SetNullable(k, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = u.Run()
|
err = u.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,72 +18,59 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddUser to save user information in database
|
// AddUser to save user information in database
|
||||||
func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) {
|
||||||
collection := p.db.Table(models.Collections.User)
|
collection := p.db.Table(models.Collections.User)
|
||||||
|
|
||||||
if user.ID == "" {
|
if user.ID == "" {
|
||||||
user.ID = uuid.New().String()
|
user.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.Roles == "" {
|
if user.Roles == "" {
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||||
return user, fmt.Errorf("user with given phone number already exists")
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
}
|
}
|
||||||
|
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||||
|
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given email already exists")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
err := collection.Put(user).RunWithContext(ctx)
|
err := collection.Put(user).RunWithContext(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUser to update user information in database
|
// UpdateUser to update user information in database
|
||||||
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) {
|
||||||
collection := p.db.Table(models.Collections.User)
|
collection := p.db.Table(models.Collections.User)
|
||||||
|
|
||||||
if user.ID != "" {
|
if user.ID != "" {
|
||||||
|
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
err := UpdateByHashKey(collection, "id", user.ID, user)
|
err := UpdateByHashKey(collection, "id", user.ID, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return user, err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUser to delete user information from database
|
// DeleteUser to delete user information from database
|
||||||
func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
func (p *provider) DeleteUser(ctx context.Context, user *models.User) error {
|
||||||
collection := p.db.Table(models.Collections.User)
|
collection := p.db.Table(models.Collections.User)
|
||||||
sessionCollection := p.db.Table(models.Collections.Session)
|
sessionCollection := p.db.Table(models.Collections.Session)
|
||||||
|
|
||||||
if user.ID != "" {
|
if user.ID != "" {
|
||||||
err := collection.Delete("id", user.ID).Run()
|
err := collection.Delete("id", user.ID).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = sessionCollection.Batch("id").Write().Delete(dynamo.Keys{"user_id", user.ID}).RunWithContext(ctx)
|
_, err = sessionCollection.Batch("id").Write().Delete(dynamo.Keys{"user_id", user.ID}).RunWithContext(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -92,23 +79,19 @@ func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListUsers to get list of users from database
|
// ListUsers to get list of users from database
|
||||||
func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
|
func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) {
|
||||||
var user models.User
|
var user *models.User
|
||||||
var lastEval dynamo.PagingKey
|
var lastEval dynamo.PagingKey
|
||||||
var iter dynamo.PagingIter
|
var iter dynamo.PagingIter
|
||||||
var iteration int64 = 0
|
var iteration int64 = 0
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.User)
|
collection := p.db.Table(models.Collections.User)
|
||||||
users := []*model.User{}
|
users := []*model.User{}
|
||||||
|
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
scanner := collection.Scan()
|
scanner := collection.Scan()
|
||||||
count, err := scanner.Count()
|
count, err := scanner.Count()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for (paginationClone.Offset + paginationClone.Limit) > iteration {
|
for (paginationClone.Offset + paginationClone.Limit) > iteration {
|
||||||
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
|
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
|
||||||
for iter.NextWithContext(ctx, &user) {
|
for iter.NextWithContext(ctx, &user) {
|
||||||
|
@ -119,51 +102,42 @@ func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (
|
||||||
lastEval = iter.LastEvaluatedKey()
|
lastEval = iter.LastEvaluatedKey()
|
||||||
iteration += paginationClone.Limit
|
iteration += paginationClone.Limit
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iter.Err()
|
err = iter.Err()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paginationClone.Total = count
|
paginationClone.Total = count
|
||||||
|
|
||||||
return &model.Users{
|
return &model.Users{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
Users: users,
|
Users: users,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByEmail to get user information from database using email address
|
// GetUserByEmail to get user information from database using email address
|
||||||
func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
|
func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) {
|
||||||
var users []models.User
|
var users []*models.User
|
||||||
var user models.User
|
var user *models.User
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.User)
|
collection := p.db.Table(models.Collections.User)
|
||||||
err := collection.Scan().Index("email").Filter("'email' = ?", email).AllWithContext(ctx, &users)
|
err := collection.Scan().Index("email").Filter("'email' = ?", email).AllWithContext(ctx, &users)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(users) > 0 {
|
if len(users) > 0 {
|
||||||
user = users[0]
|
user = users[0]
|
||||||
return user, nil
|
return user, nil
|
||||||
} else {
|
} else {
|
||||||
return user, errors.New("no record found")
|
return nil, errors.New("no record found")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByID to get user information from database using user ID
|
// GetUserByID to get user information from database using user ID
|
||||||
func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
|
func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) {
|
||||||
collection := p.db.Table(models.Collections.User)
|
collection := p.db.Table(models.Collections.User)
|
||||||
var user models.User
|
var user *models.User
|
||||||
err := collection.Get("id", id).OneWithContext(ctx, &user)
|
err := collection.Get("id", id).OneWithContext(ctx, &user)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if user.Email == "" {
|
if refs.StringValue(user.Email) == "" {
|
||||||
return user, errors.New("no documets found")
|
return nil, errors.New("no documets found")
|
||||||
} else {
|
} else {
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -186,7 +160,6 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
} else {
|
} else {
|
||||||
// as there is no facility to update all doc - https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SQLtoNoSQL.UpdateData.html
|
// as there is no facility to update all doc - https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SQLtoNoSQL.UpdateData.html
|
||||||
userCollection.Scan().All(&allUsers)
|
userCollection.Scan().All(&allUsers)
|
||||||
|
|
||||||
for _, user := range allUsers {
|
for _, user := range allUsers {
|
||||||
err = UpdateByHashKey(userCollection, "id", user.ID, data)
|
err = UpdateByHashKey(userCollection, "id", user.ID, data)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -194,7 +167,6 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
|
@ -205,19 +177,16 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
|
|
||||||
// GetUserByPhoneNumber to get user information from database using phone number
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
var users []models.User
|
var users []*models.User
|
||||||
var user models.User
|
var user *models.User
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.User)
|
collection := p.db.Table(models.Collections.User)
|
||||||
err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).AllWithContext(ctx, &users)
|
err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).AllWithContext(ctx, &users)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(users) > 0 {
|
if len(users) > 0 {
|
||||||
user = users[0]
|
user = users[0]
|
||||||
return &user, nil
|
return user, nil
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("no record found")
|
return nil, errors.New("no record found")
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,73 +11,64 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddVerification to save verification request in database
|
// AddVerification to save verification request in database
|
||||||
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
|
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) {
|
||||||
collection := p.db.Table(models.Collections.VerificationRequest)
|
collection := p.db.Table(models.Collections.VerificationRequest)
|
||||||
|
|
||||||
if verificationRequest.ID == "" {
|
if verificationRequest.ID == "" {
|
||||||
verificationRequest.ID = uuid.New().String()
|
verificationRequest.ID = uuid.New().String()
|
||||||
verificationRequest.CreatedAt = time.Now().Unix()
|
verificationRequest.CreatedAt = time.Now().Unix()
|
||||||
verificationRequest.UpdatedAt = time.Now().Unix()
|
verificationRequest.UpdatedAt = time.Now().Unix()
|
||||||
err := collection.Put(verificationRequest).RunWithContext(ctx)
|
err := collection.Put(verificationRequest).RunWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVerificationRequestByToken to get verification request from database using token
|
// GetVerificationRequestByToken to get verification request from database using token
|
||||||
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
|
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) {
|
||||||
collection := p.db.Table(models.Collections.VerificationRequest)
|
collection := p.db.Table(models.Collections.VerificationRequest)
|
||||||
var verificationRequest models.VerificationRequest
|
var verificationRequest *models.VerificationRequest
|
||||||
|
|
||||||
iter := collection.Scan().Filter("'token' = ?", token).Iter()
|
iter := collection.Scan().Filter("'token' = ?", token).Iter()
|
||||||
for iter.NextWithContext(ctx, &verificationRequest) {
|
for iter.NextWithContext(ctx, &verificationRequest) {
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := iter.Err()
|
err := iter.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVerificationRequestByEmail to get verification request by email from database
|
// GetVerificationRequestByEmail to get verification request by email from database
|
||||||
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
|
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) {
|
||||||
var verificationRequest models.VerificationRequest
|
var verificationRequest *models.VerificationRequest
|
||||||
collection := p.db.Table(models.Collections.VerificationRequest)
|
collection := p.db.Table(models.Collections.VerificationRequest)
|
||||||
iter := collection.Scan().Filter("'email' = ?", email).Filter("'identifier' = ?", identifier).Iter()
|
iter := collection.Scan().Filter("'email' = ?", email).Filter("'identifier' = ?", identifier).Iter()
|
||||||
for iter.NextWithContext(ctx, &verificationRequest) {
|
for iter.NextWithContext(ctx, &verificationRequest) {
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := iter.Err()
|
err := iter.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListVerificationRequests to get list of verification requests from database
|
// ListVerificationRequests to get list of verification requests from database
|
||||||
func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
|
func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) {
|
||||||
verificationRequests := []*model.VerificationRequest{}
|
verificationRequests := []*model.VerificationRequest{}
|
||||||
var verificationRequest models.VerificationRequest
|
var verificationRequest *models.VerificationRequest
|
||||||
var lastEval dynamo.PagingKey
|
var lastEval dynamo.PagingKey
|
||||||
var iter dynamo.PagingIter
|
var iter dynamo.PagingIter
|
||||||
var iteration int64 = 0
|
var iteration int64 = 0
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.VerificationRequest)
|
collection := p.db.Table(models.Collections.VerificationRequest)
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
|
|
||||||
scanner := collection.Scan()
|
scanner := collection.Scan()
|
||||||
count, err := scanner.Count()
|
count, err := scanner.Count()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for (paginationClone.Offset + paginationClone.Limit) > iteration {
|
for (paginationClone.Offset + paginationClone.Limit) > iteration {
|
||||||
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
|
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
|
||||||
for iter.NextWithContext(ctx, &verificationRequest) {
|
for iter.NextWithContext(ctx, &verificationRequest) {
|
||||||
|
@ -92,20 +83,17 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode
|
||||||
lastEval = iter.LastEvaluatedKey()
|
lastEval = iter.LastEvaluatedKey()
|
||||||
iteration += paginationClone.Limit
|
iteration += paginationClone.Limit
|
||||||
}
|
}
|
||||||
|
|
||||||
paginationClone.Total = count
|
paginationClone.Total = count
|
||||||
|
|
||||||
return &model.VerificationRequests{
|
return &model.VerificationRequests{
|
||||||
VerificationRequests: verificationRequests,
|
VerificationRequests: verificationRequests,
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteVerificationRequest to delete verification request from database
|
// DeleteVerificationRequest to delete verification request from database
|
||||||
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error {
|
||||||
collection := p.db.Table(models.Collections.VerificationRequest)
|
collection := p.db.Table(models.Collections.VerificationRequest)
|
||||||
|
if verificationRequest != nil {
|
||||||
if verificationRequest.ID != "" {
|
|
||||||
err := collection.Delete("id", verificationRequest.ID).RunWithContext(ctx)
|
err := collection.Delete("id", verificationRequest.ID).RunWithContext(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -3,28 +3,29 @@ package dynamodb
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/guregu/dynamo"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/guregu/dynamo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddWebhook to add webhook
|
// AddWebhook to add webhook
|
||||||
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) {
|
||||||
collection := p.db.Table(models.Collections.Webhook)
|
collection := p.db.Table(models.Collections.Webhook)
|
||||||
|
|
||||||
if webhook.ID == "" {
|
if webhook.ID == "" {
|
||||||
webhook.ID = uuid.New().String()
|
webhook.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
webhook.Key = webhook.ID
|
webhook.Key = webhook.ID
|
||||||
webhook.CreatedAt = time.Now().Unix()
|
webhook.CreatedAt = time.Now().Unix()
|
||||||
webhook.UpdatedAt = time.Now().Unix()
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
|
// Add timestamp to make event name unique for legacy version
|
||||||
|
webhook.EventName = fmt.Sprintf("%s-%d", webhook.EventName, time.Now().Unix())
|
||||||
err := collection.Put(webhook).RunWithContext(ctx)
|
err := collection.Put(webhook).RunWithContext(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -32,12 +33,14 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateWebhook to update webhook
|
// UpdateWebhook to update webhook
|
||||||
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) {
|
||||||
collection := p.db.Table(models.Collections.Webhook)
|
|
||||||
|
|
||||||
webhook.UpdatedAt = time.Now().Unix()
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
|
// Event is changed
|
||||||
|
if !strings.Contains(webhook.EventName, "-") {
|
||||||
|
webhook.EventName = fmt.Sprintf("%s-%d", webhook.EventName, time.Now().Unix())
|
||||||
|
}
|
||||||
|
collection := p.db.Table(models.Collections.Webhook)
|
||||||
err := UpdateByHashKey(collection, "id", webhook.ID, webhook)
|
err := UpdateByHashKey(collection, "id", webhook.ID, webhook)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -45,22 +48,19 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListWebhooks to list webhook
|
// ListWebhooks to list webhook
|
||||||
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
|
func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) {
|
||||||
webhooks := []*model.Webhook{}
|
webhooks := []*model.Webhook{}
|
||||||
var webhook models.Webhook
|
var webhook *models.Webhook
|
||||||
var lastEval dynamo.PagingKey
|
var lastEval dynamo.PagingKey
|
||||||
var iter dynamo.PagingIter
|
var iter dynamo.PagingIter
|
||||||
var iteration int64 = 0
|
var iteration int64 = 0
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.Webhook)
|
collection := p.db.Table(models.Collections.Webhook)
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
scanner := collection.Scan()
|
scanner := collection.Scan()
|
||||||
count, err := scanner.Count()
|
count, err := scanner.Count()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for (paginationClone.Offset + paginationClone.Limit) > iteration {
|
for (paginationClone.Offset + paginationClone.Limit) > iteration {
|
||||||
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
|
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
|
||||||
for iter.NextWithContext(ctx, &webhook) {
|
for iter.NextWithContext(ctx, &webhook) {
|
||||||
|
@ -75,11 +75,9 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
||||||
lastEval = iter.LastEvaluatedKey()
|
lastEval = iter.LastEvaluatedKey()
|
||||||
iteration += paginationClone.Limit
|
iteration += paginationClone.Limit
|
||||||
}
|
}
|
||||||
|
|
||||||
paginationClone.Total = count
|
paginationClone.Total = count
|
||||||
|
|
||||||
return &model.Webhooks{
|
return &model.Webhooks{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
Webhooks: webhooks,
|
Webhooks: webhooks,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -87,53 +85,44 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
||||||
// GetWebhookByID to get webhook by id
|
// GetWebhookByID to get webhook by id
|
||||||
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
||||||
collection := p.db.Table(models.Collections.Webhook)
|
collection := p.db.Table(models.Collections.Webhook)
|
||||||
var webhook models.Webhook
|
var webhook *models.Webhook
|
||||||
|
|
||||||
err := collection.Get("id", webhookID).OneWithContext(ctx, &webhook)
|
err := collection.Get("id", webhookID).OneWithContext(ctx, &webhook)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if webhook.ID == "" {
|
if webhook.ID == "" {
|
||||||
return webhook.AsAPIWebhook(), errors.New("no documets found")
|
return nil, errors.New("no documets found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return webhook.AsAPIWebhook(), nil
|
return webhook.AsAPIWebhook(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhookByEventName to get webhook by event_name
|
// GetWebhookByEventName to get webhook by event_name
|
||||||
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
|
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*model.Webhook, error) {
|
||||||
var webhook models.Webhook
|
webhooks := []models.Webhook{}
|
||||||
collection := p.db.Table(models.Collections.Webhook)
|
collection := p.db.Table(models.Collections.Webhook)
|
||||||
|
err := collection.Scan().Index("event_name").Filter("contains(event_name, ?)", eventName).AllWithContext(ctx, &webhooks)
|
||||||
iter := collection.Scan().Index("event_name").Filter("'event_name' = ?", eventName).Iter()
|
|
||||||
|
|
||||||
for iter.NextWithContext(ctx, &webhook) {
|
|
||||||
return webhook.AsAPIWebhook(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err := iter.Err()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return webhook.AsAPIWebhook(), err
|
return nil, err
|
||||||
}
|
}
|
||||||
return webhook.AsAPIWebhook(), nil
|
resWebhooks := []*model.Webhook{}
|
||||||
|
for _, w := range webhooks {
|
||||||
|
resWebhooks = append(resWebhooks, w.AsAPIWebhook())
|
||||||
|
}
|
||||||
|
return resWebhooks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWebhook to delete webhook
|
// DeleteWebhook to delete webhook
|
||||||
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
||||||
// Also delete webhook logs for given webhook id
|
// Also delete webhook logs for given webhook id
|
||||||
if webhook.ID != "" {
|
if webhook != nil {
|
||||||
webhookCollection := p.db.Table(models.Collections.Webhook)
|
webhookCollection := p.db.Table(models.Collections.Webhook)
|
||||||
pagination := model.Pagination{}
|
|
||||||
webhookLogCollection := p.db.Table(models.Collections.WebhookLog)
|
webhookLogCollection := p.db.Table(models.Collections.WebhookLog)
|
||||||
err := webhookCollection.Delete("id", webhook.ID).RunWithContext(ctx)
|
err := webhookCollection.Delete("id", webhook.ID).RunWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
pagination := &model.Pagination{}
|
||||||
webhookLogs, errIs := p.ListWebhookLogs(ctx, pagination, webhook.ID)
|
webhookLogs, errIs := p.ListWebhookLogs(ctx, pagination, webhook.ID)
|
||||||
|
|
||||||
for _, webhookLog := range webhookLogs.WebhookLogs {
|
for _, webhookLog := range webhookLogs.WebhookLogs {
|
||||||
err = webhookLogCollection.Delete("id", webhookLog.ID).RunWithContext(ctx)
|
err = webhookLogCollection.Delete("id", webhookLog.ID).RunWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -11,18 +11,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddWebhookLog to add webhook log
|
// AddWebhookLog to add webhook log
|
||||||
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
|
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) {
|
||||||
collection := p.db.Table(models.Collections.WebhookLog)
|
collection := p.db.Table(models.Collections.WebhookLog)
|
||||||
|
|
||||||
if webhookLog.ID == "" {
|
if webhookLog.ID == "" {
|
||||||
webhookLog.ID = uuid.New().String()
|
webhookLog.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
webhookLog.Key = webhookLog.ID
|
webhookLog.Key = webhookLog.ID
|
||||||
webhookLog.CreatedAt = time.Now().Unix()
|
webhookLog.CreatedAt = time.Now().Unix()
|
||||||
webhookLog.UpdatedAt = time.Now().Unix()
|
webhookLog.UpdatedAt = time.Now().Unix()
|
||||||
err := collection.Put(webhookLog).RunWithContext(ctx)
|
err := collection.Put(webhookLog).RunWithContext(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -30,9 +27,9 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookL
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListWebhookLogs to list webhook logs
|
// ListWebhookLogs to list webhook logs
|
||||||
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
|
func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) {
|
||||||
webhookLogs := []*model.WebhookLog{}
|
webhookLogs := []*model.WebhookLog{}
|
||||||
var webhookLog models.WebhookLog
|
var webhookLog *models.WebhookLog
|
||||||
var lastEval dynamo.PagingKey
|
var lastEval dynamo.PagingKey
|
||||||
var iter dynamo.PagingIter
|
var iter dynamo.PagingIter
|
||||||
var iteration int64 = 0
|
var iteration int64 = 0
|
||||||
|
@ -42,7 +39,6 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat
|
||||||
collection := p.db.Table(models.Collections.WebhookLog)
|
collection := p.db.Table(models.Collections.WebhookLog)
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
scanner := collection.Scan()
|
scanner := collection.Scan()
|
||||||
|
|
||||||
if webhookID != "" {
|
if webhookID != "" {
|
||||||
iter = scanner.Index("webhook_id").Filter("'webhook_id' = ?", webhookID).Iter()
|
iter = scanner.Index("webhook_id").Filter("'webhook_id' = ?", webhookID).Iter()
|
||||||
for iter.NextWithContext(ctx, &webhookLog) {
|
for iter.NextWithContext(ctx, &webhookLog) {
|
||||||
|
@ -68,11 +64,10 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat
|
||||||
iteration += paginationClone.Limit
|
iteration += paginationClone.Limit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
paginationClone.Total = count
|
paginationClone.Total = count
|
||||||
// paginationClone.Cursor = iter.LastEvaluatedKey()
|
// paginationClone.Cursor = iter.LastEvaluatedKey()
|
||||||
return &model.WebhookLogs{
|
return &model.WebhookLogs{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
WebhookLogs: webhookLogs,
|
WebhookLogs: webhookLogs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
52
server/db/providers/mongodb/authenticator.go
Normal file
52
server/db/providers/mongodb/authenticator.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package mongodb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||||
|
if exists != nil {
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if authenticators.ID == "" {
|
||||||
|
authenticators.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
authenticators.CreatedAt = time.Now().Unix()
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
authenticators.Key = authenticators.ID
|
||||||
|
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||||
|
_, err := authenticatorsCollection.InsertOne(ctx, authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||||
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
|
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||||
|
_, err := authenticatorsCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": authenticators.ID}}, bson.M{"$set": authenticators})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||||
|
var authenticators *models.Authenticator
|
||||||
|
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||||
|
err := authenticatorsCollection.FindOne(ctx, bson.M{"user_id": userId, "method": authenticatorType}).Decode(&authenticators)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return authenticators, nil
|
||||||
|
}
|
|
@ -12,15 +12,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEmailTemplate to add EmailTemplate
|
// AddEmailTemplate to add EmailTemplate
|
||||||
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
if emailTemplate.ID == "" {
|
if emailTemplate.ID == "" {
|
||||||
emailTemplate.ID = uuid.New().String()
|
emailTemplate.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
emailTemplate.Key = emailTemplate.ID
|
emailTemplate.Key = emailTemplate.ID
|
||||||
emailTemplate.CreatedAt = time.Now().Unix()
|
emailTemplate.CreatedAt = time.Now().Unix()
|
||||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
emailTemplate.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection())
|
emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection())
|
||||||
_, err := emailTemplateCollection.InsertOne(ctx, emailTemplate)
|
_, err := emailTemplateCollection.InsertOne(ctx, emailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -30,60 +28,52 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEmailTemplate to update EmailTemplate
|
// UpdateEmailTemplate to update EmailTemplate
|
||||||
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
emailTemplate.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection())
|
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())
|
_, err := emailTemplateCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": emailTemplate.ID}}, bson.M{"$set": emailTemplate}, options.MergeUpdateOptions())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListEmailTemplates to list EmailTemplate
|
// ListEmailTemplates to list EmailTemplate
|
||||||
func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) {
|
func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) {
|
||||||
var emailTemplates []*model.EmailTemplate
|
var emailTemplates []*model.EmailTemplate
|
||||||
opts := options.Find()
|
opts := options.Find()
|
||||||
opts.SetLimit(pagination.Limit)
|
opts.SetLimit(pagination.Limit)
|
||||||
opts.SetSkip(pagination.Offset)
|
opts.SetSkip(pagination.Offset)
|
||||||
opts.SetSort(bson.M{"created_at": -1})
|
opts.SetSort(bson.M{"created_at": -1})
|
||||||
|
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
|
|
||||||
emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection())
|
emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection())
|
||||||
count, err := emailTemplateCollection.CountDocuments(ctx, bson.M{}, options.Count())
|
count, err := emailTemplateCollection.CountDocuments(ctx, bson.M{}, options.Count())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paginationClone.Total = count
|
paginationClone.Total = count
|
||||||
|
|
||||||
cursor, err := emailTemplateCollection.Find(ctx, bson.M{}, opts)
|
cursor, err := emailTemplateCollection.Find(ctx, bson.M{}, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close(ctx)
|
defer cursor.Close(ctx)
|
||||||
|
|
||||||
for cursor.Next(ctx) {
|
for cursor.Next(ctx) {
|
||||||
var emailTemplate models.EmailTemplate
|
var emailTemplate *models.EmailTemplate
|
||||||
err := cursor.Decode(&emailTemplate)
|
err := cursor.Decode(&emailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate())
|
emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate())
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.EmailTemplates{
|
return &model.EmailTemplates{
|
||||||
Pagination: &paginationClone,
|
Pagination: paginationClone,
|
||||||
EmailTemplates: emailTemplates,
|
EmailTemplates: emailTemplates,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEmailTemplateByID to get EmailTemplate by id
|
// GetEmailTemplateByID to get EmailTemplate by id
|
||||||
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
||||||
var emailTemplate models.EmailTemplate
|
var emailTemplate *models.EmailTemplate
|
||||||
emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection())
|
emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection())
|
||||||
err := emailTemplateCollection.FindOne(ctx, bson.M{"_id": emailTemplateID}).Decode(&emailTemplate)
|
err := emailTemplateCollection.FindOne(ctx, bson.M{"_id": emailTemplateID}).Decode(&emailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -94,7 +84,7 @@ func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID str
|
||||||
|
|
||||||
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
||||||
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
||||||
var emailTemplate models.EmailTemplate
|
var emailTemplate *models.EmailTemplate
|
||||||
emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection())
|
emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection())
|
||||||
err := emailTemplateCollection.FindOne(ctx, bson.M{"event_name": eventName}).Decode(&emailTemplate)
|
err := emailTemplateCollection.FindOne(ctx, bson.M{"event_name": eventName}).Decode(&emailTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -110,6 +100,5 @@ func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,53 +12,49 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEnv to save environment information in database
|
// AddEnv to save environment information in database
|
||||||
func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) {
|
||||||
if env.ID == "" {
|
if env.ID == "" {
|
||||||
env.ID = uuid.New().String()
|
env.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
env.CreatedAt = time.Now().Unix()
|
env.CreatedAt = time.Now().Unix()
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
env.Key = env.ID
|
env.Key = env.ID
|
||||||
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||||
_, err := configCollection.InsertOne(ctx, env)
|
_, err := configCollection.InsertOne(ctx, env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEnv to update environment information in database
|
// UpdateEnv to update environment information in database
|
||||||
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) {
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||||
_, err := configCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions())
|
_, err := configCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEnv to get environment information from database
|
// GetEnv to get environment information from database
|
||||||
func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
|
func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
||||||
var env models.Env
|
var env *models.Env
|
||||||
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||||
cursor, err := configCollection.Find(ctx, bson.M{}, options.Find())
|
cursor, err := configCollection.Find(ctx, bson.M{}, options.Find())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close(ctx)
|
defer cursor.Close(ctx)
|
||||||
|
|
||||||
for cursor.Next(nil) {
|
for cursor.Next(nil) {
|
||||||
err := cursor.Decode(&env)
|
err := cursor.Decode(&env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if env == nil {
|
||||||
if env.ID == "" {
|
|
||||||
return env, fmt.Errorf("config not found")
|
return env, fmt.Errorf("config not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user