Compare commits
83 Commits
feat/surre
...
1.1.47
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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 | ||
![]() |
19f5ff61c0 | ||
![]() |
146707d062 | ||
![]() |
0810c4a201 | ||
![]() |
3603af9f84 | ||
![]() |
1ac8ba4ce0 | ||
![]() |
cdcdc444b2 | ||
![]() |
330f35f2fc | ||
![]() |
70242debe1 | ||
![]() |
4018da6697 | ||
![]() |
a73c6ee49e | ||
![]() |
c23fb1bb32 | ||
![]() |
270853a6a3 | ||
![]() |
2d0346ff23 | ||
![]() |
4b26e1ce85 | ||
![]() |
8212e81023 | ||
![]() |
642581eefd | ||
![]() |
b7357dde21 | ||
![]() |
a1df2ce31f | ||
![]() |
748761926d | ||
![]() |
d632195ba5 | ||
![]() |
25970f80e1 | ||
![]() |
a52b7c86e7 | ||
![]() |
504d0f34d7 | ||
![]() |
44879f1a8f | ||
![]() |
b39f0b87fd | ||
![]() |
b2423140e2 | ||
![]() |
4f810d2f8b | ||
![]() |
313b510ba1 | ||
![]() |
105d9be685 | ||
![]() |
bc68b61879 | ||
![]() |
2847300bf6 | ||
![]() |
d438480f37 | ||
![]() |
da29f9d055 | ||
![]() |
f29256a8f5 | ||
![]() |
1eb8965f98 | ||
![]() |
1c4e29fa7c | ||
![]() |
7a28795fa0 | ||
![]() |
f5db00beb0 | ||
![]() |
d515a1f41d | ||
![]() |
c948c98e94 | ||
![]() |
e985e096bc |
230
.github/CONTRIBUTING.md
vendored
230
.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
|
||||||
|
|
||||||
@@ -87,145 +105,145 @@ For manually testing using graphql playground, you can paste following queries a
|
|||||||
|
|
||||||
```gql
|
```gql
|
||||||
mutation Signup {
|
mutation Signup {
|
||||||
signup(
|
signup(
|
||||||
params: {
|
params: {
|
||||||
email: "lakhan@yopmail.com"
|
email: "lakhan@yopmail.com"
|
||||||
password: "test"
|
password: "test"
|
||||||
confirm_password: "test"
|
confirm_password: "test"
|
||||||
given_name: "lakhan"
|
given_name: "lakhan"
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
message
|
message
|
||||||
user {
|
user {
|
||||||
id
|
id
|
||||||
family_name
|
family_name
|
||||||
given_name
|
given_name
|
||||||
email
|
email
|
||||||
email_verified
|
email_verified
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation ResendEamil {
|
mutation ResendEamil {
|
||||||
resend_verify_email(
|
resend_verify_email(
|
||||||
params: { email: "lakhan@yopmail.com", identifier: "basic_auth_signup" }
|
params: { email: "lakhan@yopmail.com", identifier: "basic_auth_signup" }
|
||||||
) {
|
) {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query GetVerifyRequests {
|
query GetVerifyRequests {
|
||||||
_verification_requests {
|
_verification_requests {
|
||||||
id
|
id
|
||||||
token
|
token
|
||||||
expires
|
expires
|
||||||
identifier
|
identifier
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation VerifyEmail {
|
mutation VerifyEmail {
|
||||||
verify_email(params: { token: "" }) {
|
verify_email(params: { token: "" }) {
|
||||||
access_token
|
access_token
|
||||||
expires_at
|
expires_at
|
||||||
user {
|
user {
|
||||||
id
|
id
|
||||||
email
|
email
|
||||||
given_name
|
given_name
|
||||||
email_verified
|
email_verified
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation Login {
|
mutation Login {
|
||||||
login(params: { email: "lakhan@yopmail.com", password: "test" }) {
|
login(params: { email: "lakhan@yopmail.com", password: "test" }) {
|
||||||
access_token
|
access_token
|
||||||
expires_at
|
expires_at
|
||||||
user {
|
user {
|
||||||
id
|
id
|
||||||
family_name
|
family_name
|
||||||
given_name
|
given_name
|
||||||
email
|
email
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query GetSession {
|
query GetSession {
|
||||||
session {
|
session {
|
||||||
access_token
|
access_token
|
||||||
expires_at
|
expires_at
|
||||||
user {
|
user {
|
||||||
id
|
id
|
||||||
given_name
|
given_name
|
||||||
family_name
|
family_name
|
||||||
email
|
email
|
||||||
email_verified
|
email_verified
|
||||||
signup_methods
|
signup_methods
|
||||||
created_at
|
created_at
|
||||||
updated_at
|
updated_at
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation ForgotPassword {
|
mutation ForgotPassword {
|
||||||
forgot_password(params: { email: "lakhan@yopmail.com" }) {
|
forgot_password(params: { email: "lakhan@yopmail.com" }) {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation ResetPassword {
|
mutation ResetPassword {
|
||||||
reset_password(
|
reset_password(
|
||||||
params: { token: "", password: "test", confirm_password: "test" }
|
params: { token: "", password: "test", confirm_password: "test" }
|
||||||
) {
|
) {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation UpdateProfile {
|
mutation UpdateProfile {
|
||||||
update_profile(params: { family_name: "samani" }) {
|
update_profile(params: { family_name: "samani" }) {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query GetUsers {
|
query GetUsers {
|
||||||
_users {
|
_users {
|
||||||
id
|
id
|
||||||
email
|
email
|
||||||
email_verified
|
email_verified
|
||||||
given_name
|
given_name
|
||||||
family_name
|
family_name
|
||||||
picture
|
picture
|
||||||
signup_methods
|
signup_methods
|
||||||
phone_number
|
phone_number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation MagicLinkLogin {
|
mutation MagicLinkLogin {
|
||||||
magic_link_login(params: { email: "test@yopmail.com" }) {
|
magic_link_login(params: { email: "test@yopmail.com" }) {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation Logout {
|
mutation Logout {
|
||||||
logout {
|
logout {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation UpdateUser {
|
mutation UpdateUser {
|
||||||
_update_user(
|
_update_user(
|
||||||
params: {
|
params: {
|
||||||
id: "dafc9400-d603-4ade-997c-83fcd54bbd67"
|
id: "dafc9400-d603-4ade-997c-83fcd54bbd67"
|
||||||
roles: ["user", "admin"]
|
roles: ["user", "admin"]
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
email
|
email
|
||||||
roles
|
roles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation DeleteUser {
|
mutation DeleteUser {
|
||||||
_delete_user(params: { email: "signup.test134523@yopmail.com" }) {
|
_delete_user(params: { email: "signup.test134523@yopmail.com" }) {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
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
|
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.19.1-alpine as go-builder
|
FROM golang:1.19.5-alpine as go-builder
|
||||||
WORKDIR /authorizer
|
WORKDIR /authorizer
|
||||||
COPY server server
|
COPY server server
|
||||||
COPY Makefile .
|
COPY Makefile .
|
||||||
|
19
Makefile
19
Makefile
@@ -26,23 +26,34 @@ test-scylladb:
|
|||||||
cd server && go clean --testcache && TEST_DBS="scylladb" go test -p 1 -v ./test
|
cd server && go clean --testcache && TEST_DBS="scylladb" go test -p 1 -v ./test
|
||||||
docker rm -vf authorizer_scylla_db
|
docker rm -vf authorizer_scylla_db
|
||||||
test-arangodb:
|
test-arangodb:
|
||||||
docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.8.4
|
docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.10.3
|
||||||
cd server && go clean --testcache && TEST_DBS="arangodb" go test -p 1 -v ./test
|
cd server && go clean --testcache && TEST_DBS="arangodb" go test -p 1 -v ./test
|
||||||
docker rm -vf authorizer_arangodb
|
docker rm -vf authorizer_arangodb
|
||||||
test-dynamodb:
|
test-dynamodb:
|
||||||
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
|
||||||
cd server && go clean --testcache && TEST_DBS="dynamodb" go test -p 1 -v ./test
|
cd server && go clean --testcache && TEST_DBS="dynamodb" go test -p 1 -v ./test
|
||||||
docker rm -vf dynamodb-local-test
|
docker rm -vf dynamodb-local-test
|
||||||
|
test-couchbase:
|
||||||
|
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
|
||||||
|
cd server && go clean --testcache && TEST_DBS="couchbase" go test -p 1 -v ./test
|
||||||
|
docker rm -vf couchbase-local-test
|
||||||
test-all-db:
|
test-all-db:
|
||||||
rm -rf server/test/test.db server/test/test.db-shm server/test/test.db-wal && rm -rf test.db test.db-shm test.db-wal
|
rm -rf server/test/test.db server/test/test.db-shm server/test/test.db-wal && rm -rf test.db test.db-shm test.db-wal
|
||||||
docker run -d --name authorizer_scylla_db -p 9042:9042 scylladb/scylla
|
docker run -d --name authorizer_scylla_db -p 9042:9042 scylladb/scylla
|
||||||
docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15
|
docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15
|
||||||
docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.8.4
|
docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.10.3
|
||||||
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
|
||||||
|
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" 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
|
||||||
generate:
|
docker rm -vf couchbase-local-test
|
||||||
|
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' {} \;
|
106
app/package-lock.json
generated
106
app/package-lock.json
generated
@@ -9,7 +9,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^1.1.3-beta.1",
|
"@authorizerdev/authorizer-react": "^1.1.11",
|
||||||
"@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",
|
||||||
@@ -27,25 +27,25 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@authorizerdev/authorizer-js": {
|
"node_modules/@authorizerdev/authorizer-js": {
|
||||||
"version": "1.1.2-beta.1",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.1.2-beta.1.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.3.tgz",
|
||||||
"integrity": "sha512-u+O2iB3tqF1HtdJ6LfBXL9iMycqlCCL3othBQkqitGP1ldhASWLJ2pcXZAcHgyoeczKdj2XKZKdIcWB3GYR0IQ==",
|
"integrity": "sha512-rk/fMRIsqbp+fsy2y09etVjf7CY9/4mG6hf0RKgXgRRfxtAQa1jdkt/De23hBTNeEwAWu6hP/9BQZjcrln6KtA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-fetch": "^3.1.5"
|
"cross-fetch": "^3.1.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/authorizerdev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@authorizerdev/authorizer-react": {
|
"node_modules/@authorizerdev/authorizer-react": {
|
||||||
"version": "1.1.3-beta.1",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.3-beta.1.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.11.tgz",
|
||||||
"integrity": "sha512-+ZsOBp6XjZVnDyeJCXgaqZ8xzFO7ygpHB6v2cblCKIA3wX5pg/Dsg1oumHGrSHIEK8No/GOtCjSx4Rv6/CweBQ==",
|
"integrity": "sha512-tSI/yjsoeK/RvCOMiHSf1QGOeSpaLYQZEM864LFLndKoJwk7UWCJ86qg1w6ge7B00PmZSNWqST/w5JTcQaVNpw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-js": "^1.1.2-beta.1",
|
"@authorizerdev/authorizer-js": "^1.2.3"
|
||||||
"final-form": "^4.20.2",
|
|
||||||
"react-final-form": "^6.5.3",
|
|
||||||
"styled-components": "^5.3.0"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
@@ -469,18 +469,6 @@
|
|||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/final-form": {
|
|
||||||
"version": "4.20.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/final-form/-/final-form-4.20.4.tgz",
|
|
||||||
"integrity": "sha512-hyoOVVilPLpkTvgi+FSJkFZrh0Yhy4BhE6lk/NiBwrF4aRV8/ykKEyXYvQH/pfUbRkOosvpESYouFb+FscsLrw==",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/runtime": "^7.10.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/final-form"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/globals": {
|
"node_modules/globals": {
|
||||||
"version": "11.12.0",
|
"version": "11.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
||||||
@@ -673,33 +661,6 @@
|
|||||||
"react": "17.0.2"
|
"react": "17.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-final-form": {
|
|
||||||
"version": "6.5.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-final-form/-/react-final-form-6.5.7.tgz",
|
|
||||||
"integrity": "sha512-o7tvJXB+McGiXOILqIC8lnOcX4aLhIBiF/Xi9Qet35b7XOS8R7KL8HLRKTfnZWQJm6MCE15v1U0SFive0NcxyA==",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/runtime": "^7.15.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/final-form"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"final-form": "4.20.4",
|
|
||||||
"react": "^16.8.0 || ^17.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-final-form/node_modules/@babel/runtime": {
|
|
||||||
"version": "7.16.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
|
|
||||||
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"regenerator-runtime": "^0.13.4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
@@ -876,22 +837,19 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-js": {
|
"@authorizerdev/authorizer-js": {
|
||||||
"version": "1.1.2-beta.1",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.1.2-beta.1.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.3.tgz",
|
||||||
"integrity": "sha512-u+O2iB3tqF1HtdJ6LfBXL9iMycqlCCL3othBQkqitGP1ldhASWLJ2pcXZAcHgyoeczKdj2XKZKdIcWB3GYR0IQ==",
|
"integrity": "sha512-rk/fMRIsqbp+fsy2y09etVjf7CY9/4mG6hf0RKgXgRRfxtAQa1jdkt/De23hBTNeEwAWu6hP/9BQZjcrln6KtA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"cross-fetch": "^3.1.5"
|
"cross-fetch": "^3.1.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@authorizerdev/authorizer-react": {
|
"@authorizerdev/authorizer-react": {
|
||||||
"version": "1.1.3-beta.1",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.3-beta.1.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.11.tgz",
|
||||||
"integrity": "sha512-+ZsOBp6XjZVnDyeJCXgaqZ8xzFO7ygpHB6v2cblCKIA3wX5pg/Dsg1oumHGrSHIEK8No/GOtCjSx4Rv6/CweBQ==",
|
"integrity": "sha512-tSI/yjsoeK/RvCOMiHSf1QGOeSpaLYQZEM864LFLndKoJwk7UWCJ86qg1w6ge7B00PmZSNWqST/w5JTcQaVNpw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@authorizerdev/authorizer-js": "^1.1.2-beta.1",
|
"@authorizerdev/authorizer-js": "^1.2.3"
|
||||||
"final-form": "^4.20.2",
|
|
||||||
"react-final-form": "^6.5.3",
|
|
||||||
"styled-components": "^5.3.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/code-frame": {
|
"@babel/code-frame": {
|
||||||
@@ -1231,14 +1189,6 @@
|
|||||||
"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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||||
},
|
},
|
||||||
"final-form": {
|
|
||||||
"version": "4.20.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/final-form/-/final-form-4.20.4.tgz",
|
|
||||||
"integrity": "sha512-hyoOVVilPLpkTvgi+FSJkFZrh0Yhy4BhE6lk/NiBwrF4aRV8/ykKEyXYvQH/pfUbRkOosvpESYouFb+FscsLrw==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"globals": {
|
"globals": {
|
||||||
"version": "11.12.0",
|
"version": "11.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
||||||
@@ -1387,24 +1337,6 @@
|
|||||||
"scheduler": "^0.20.2"
|
"scheduler": "^0.20.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-final-form": {
|
|
||||||
"version": "6.5.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-final-form/-/react-final-form-6.5.7.tgz",
|
|
||||||
"integrity": "sha512-o7tvJXB+McGiXOILqIC8lnOcX4aLhIBiF/Xi9Qet35b7XOS8R7KL8HLRKTfnZWQJm6MCE15v1U0SFive0NcxyA==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.15.4"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/runtime": {
|
|
||||||
"version": "7.16.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
|
|
||||||
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
|
|
||||||
"requires": {
|
|
||||||
"regenerator-runtime": "^0.13.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
"author": "Lakhan Samani",
|
"author": "Lakhan Samani",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^1.1.3",
|
"@authorizerdev/authorizer-react": "^1.1.11",
|
||||||
"@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
generated
Normal file
626
app/pnpm-lock.yaml
generated
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
|
588
app/yarn.lock
Normal file
588
app/yarn.lock
Normal file
@@ -0,0 +1,588 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@authorizerdev/authorizer-js@^1.2.3":
|
||||||
|
"integrity" "sha512-rk/fMRIsqbp+fsy2y09etVjf7CY9/4mG6hf0RKgXgRRfxtAQa1jdkt/De23hBTNeEwAWu6hP/9BQZjcrln6KtA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.3.tgz"
|
||||||
|
"version" "1.2.3"
|
||||||
|
dependencies:
|
||||||
|
"cross-fetch" "^3.1.5"
|
||||||
|
|
||||||
|
"@authorizerdev/authorizer-react@^1.1.11":
|
||||||
|
"integrity" "sha512-tSI/yjsoeK/RvCOMiHSf1QGOeSpaLYQZEM864LFLndKoJwk7UWCJ86qg1w6ge7B00PmZSNWqST/w5JTcQaVNpw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.11.tgz"
|
||||||
|
"version" "1.1.11"
|
||||||
|
dependencies:
|
||||||
|
"@authorizerdev/authorizer-js" "^1.2.3"
|
||||||
|
|
||||||
|
"@babel/code-frame@^7.16.7":
|
||||||
|
"integrity" "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz"
|
||||||
|
"version" "7.16.7"
|
||||||
|
dependencies:
|
||||||
|
"@babel/highlight" "^7.16.7"
|
||||||
|
|
||||||
|
"@babel/generator@^7.16.8":
|
||||||
|
"integrity" "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz"
|
||||||
|
"version" "7.16.8"
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.16.8"
|
||||||
|
"jsesc" "^2.5.1"
|
||||||
|
"source-map" "^0.5.0"
|
||||||
|
|
||||||
|
"@babel/helper-annotate-as-pure@^7.16.0":
|
||||||
|
"integrity" "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz"
|
||||||
|
"version" "7.16.7"
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
|
"@babel/helper-environment-visitor@^7.16.7":
|
||||||
|
"integrity" "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz"
|
||||||
|
"version" "7.16.7"
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
|
"@babel/helper-function-name@^7.16.7":
|
||||||
|
"integrity" "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz"
|
||||||
|
"version" "7.16.7"
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-get-function-arity" "^7.16.7"
|
||||||
|
"@babel/template" "^7.16.7"
|
||||||
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
|
"@babel/helper-get-function-arity@^7.16.7":
|
||||||
|
"integrity" "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz"
|
||||||
|
"version" "7.16.7"
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
|
"@babel/helper-hoist-variables@^7.16.7":
|
||||||
|
"integrity" "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz"
|
||||||
|
"version" "7.16.7"
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
|
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.0":
|
||||||
|
"integrity" "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz"
|
||||||
|
"version" "7.16.7"
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
|
"@babel/helper-split-export-declaration@^7.16.7":
|
||||||
|
"integrity" "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz"
|
||||||
|
"version" "7.16.7"
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
|
"@babel/helper-validator-identifier@^7.16.7":
|
||||||
|
"integrity" "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz"
|
||||||
|
"version" "7.16.7"
|
||||||
|
|
||||||
|
"@babel/highlight@^7.16.7":
|
||||||
|
"integrity" "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz"
|
||||||
|
"version" "7.16.10"
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-validator-identifier" "^7.16.7"
|
||||||
|
"chalk" "^2.0.0"
|
||||||
|
"js-tokens" "^4.0.0"
|
||||||
|
|
||||||
|
"@babel/parser@^7.16.10", "@babel/parser@^7.16.7":
|
||||||
|
"integrity" "sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.16.12.tgz"
|
||||||
|
"version" "7.16.12"
|
||||||
|
|
||||||
|
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1":
|
||||||
|
"integrity" "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz"
|
||||||
|
"version" "7.14.8"
|
||||||
|
dependencies:
|
||||||
|
"regenerator-runtime" "^0.13.4"
|
||||||
|
|
||||||
|
"@babel/template@^7.16.7":
|
||||||
|
"integrity" "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz"
|
||||||
|
"version" "7.16.7"
|
||||||
|
dependencies:
|
||||||
|
"@babel/code-frame" "^7.16.7"
|
||||||
|
"@babel/parser" "^7.16.7"
|
||||||
|
"@babel/types" "^7.16.7"
|
||||||
|
|
||||||
|
"@babel/traverse@^7.4.5":
|
||||||
|
"integrity" "sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.10.tgz"
|
||||||
|
"version" "7.16.10"
|
||||||
|
dependencies:
|
||||||
|
"@babel/code-frame" "^7.16.7"
|
||||||
|
"@babel/generator" "^7.16.8"
|
||||||
|
"@babel/helper-environment-visitor" "^7.16.7"
|
||||||
|
"@babel/helper-function-name" "^7.16.7"
|
||||||
|
"@babel/helper-hoist-variables" "^7.16.7"
|
||||||
|
"@babel/helper-split-export-declaration" "^7.16.7"
|
||||||
|
"@babel/parser" "^7.16.10"
|
||||||
|
"@babel/types" "^7.16.8"
|
||||||
|
"debug" "^4.1.0"
|
||||||
|
"globals" "^11.1.0"
|
||||||
|
|
||||||
|
"@babel/types@^7.16.7", "@babel/types@^7.16.8":
|
||||||
|
"integrity" "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz"
|
||||||
|
"version" "7.16.8"
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-validator-identifier" "^7.16.7"
|
||||||
|
"to-fast-properties" "^2.0.0"
|
||||||
|
|
||||||
|
"@emotion/is-prop-valid@^0.8.8":
|
||||||
|
"integrity" "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz"
|
||||||
|
"version" "0.8.8"
|
||||||
|
dependencies:
|
||||||
|
"@emotion/memoize" "0.7.4"
|
||||||
|
|
||||||
|
"@emotion/memoize@0.7.4":
|
||||||
|
"integrity" "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz"
|
||||||
|
"version" "0.7.4"
|
||||||
|
|
||||||
|
"@emotion/stylis@^0.8.4":
|
||||||
|
"integrity" "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz"
|
||||||
|
"version" "0.8.5"
|
||||||
|
|
||||||
|
"@emotion/unitless@^0.7.4":
|
||||||
|
"integrity" "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz"
|
||||||
|
"version" "0.7.5"
|
||||||
|
|
||||||
|
"@types/history@*":
|
||||||
|
"integrity" "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz"
|
||||||
|
"version" "4.7.9"
|
||||||
|
|
||||||
|
"@types/hoist-non-react-statics@*":
|
||||||
|
"integrity" "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz"
|
||||||
|
"version" "3.3.1"
|
||||||
|
dependencies:
|
||||||
|
"@types/react" "*"
|
||||||
|
"hoist-non-react-statics" "^3.3.0"
|
||||||
|
|
||||||
|
"@types/prop-types@*":
|
||||||
|
"integrity" "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz"
|
||||||
|
"version" "15.7.4"
|
||||||
|
|
||||||
|
"@types/react-dom@^17.0.9":
|
||||||
|
"integrity" "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz"
|
||||||
|
"version" "17.0.9"
|
||||||
|
dependencies:
|
||||||
|
"@types/react" "*"
|
||||||
|
|
||||||
|
"@types/react-router-dom@^5.1.8":
|
||||||
|
"integrity" "sha512-03xHyncBzG0PmDmf8pf3rehtjY0NpUj7TIN46FrT5n1ZWHPZvXz32gUyNboJ+xsL8cpg8bQVLcllptcQHvocrw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.8.tgz"
|
||||||
|
"version" "5.1.8"
|
||||||
|
dependencies:
|
||||||
|
"@types/history" "*"
|
||||||
|
"@types/react" "*"
|
||||||
|
"@types/react-router" "*"
|
||||||
|
|
||||||
|
"@types/react-router@*":
|
||||||
|
"integrity" "sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz"
|
||||||
|
"version" "5.1.16"
|
||||||
|
dependencies:
|
||||||
|
"@types/history" "*"
|
||||||
|
"@types/react" "*"
|
||||||
|
|
||||||
|
"@types/react@*", "@types/react@^17.0.15":
|
||||||
|
"integrity" "sha512-uTKHDK9STXFHLaKv6IMnwp52fm0hwU+N89w/p9grdUqcFA6WuqDyPhaWopbNyE1k/VhgzmHl8pu1L4wITtmlLw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@types/react/-/react-17.0.15.tgz"
|
||||||
|
"version" "17.0.15"
|
||||||
|
dependencies:
|
||||||
|
"@types/prop-types" "*"
|
||||||
|
"@types/scheduler" "*"
|
||||||
|
"csstype" "^3.0.2"
|
||||||
|
|
||||||
|
"@types/scheduler@*":
|
||||||
|
"integrity" "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz"
|
||||||
|
"version" "0.16.2"
|
||||||
|
|
||||||
|
"@types/styled-components@^5.1.11":
|
||||||
|
"integrity" "sha512-fgwl+0Pa8pdkwXRoVPP9JbqF0Ivo9llnmsm+7TCI330kbPIFd9qv1Lrhr37shf4tnxCOSu+/IgqM7uJXLWZZNQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.25.tgz"
|
||||||
|
"version" "5.1.25"
|
||||||
|
dependencies:
|
||||||
|
"@types/hoist-non-react-statics" "*"
|
||||||
|
"@types/react" "*"
|
||||||
|
"csstype" "^3.0.2"
|
||||||
|
|
||||||
|
"ansi-styles@^3.2.1":
|
||||||
|
"integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz"
|
||||||
|
"version" "3.2.1"
|
||||||
|
dependencies:
|
||||||
|
"color-convert" "^1.9.0"
|
||||||
|
|
||||||
|
"babel-plugin-styled-components@>= 1.12.0":
|
||||||
|
"integrity" "sha512-7eG5NE8rChnNTDxa6LQfynwgHTVOYYaHJbUYSlOhk8QBXIQiMBKq4gyfHBBKPrxUcVBXVJL61ihduCpCQbuNbw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.2.tgz"
|
||||||
|
"version" "2.0.2"
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-annotate-as-pure" "^7.16.0"
|
||||||
|
"@babel/helper-module-imports" "^7.16.0"
|
||||||
|
"babel-plugin-syntax-jsx" "^6.18.0"
|
||||||
|
"lodash" "^4.17.11"
|
||||||
|
|
||||||
|
"babel-plugin-syntax-jsx@^6.18.0":
|
||||||
|
"integrity" "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
|
||||||
|
"resolved" "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz"
|
||||||
|
"version" "6.18.0"
|
||||||
|
|
||||||
|
"camelize@^1.0.0":
|
||||||
|
"integrity" "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs="
|
||||||
|
"resolved" "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz"
|
||||||
|
"version" "1.0.0"
|
||||||
|
|
||||||
|
"chalk@^2.0.0":
|
||||||
|
"integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
||||||
|
"version" "2.4.2"
|
||||||
|
dependencies:
|
||||||
|
"ansi-styles" "^3.2.1"
|
||||||
|
"escape-string-regexp" "^1.0.5"
|
||||||
|
"supports-color" "^5.3.0"
|
||||||
|
|
||||||
|
"color-convert@^1.9.0":
|
||||||
|
"integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="
|
||||||
|
"resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
|
||||||
|
"version" "1.9.3"
|
||||||
|
dependencies:
|
||||||
|
"color-name" "1.1.3"
|
||||||
|
|
||||||
|
"color-name@1.1.3":
|
||||||
|
"integrity" "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||||
|
"resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
||||||
|
"version" "1.1.3"
|
||||||
|
|
||||||
|
"cross-fetch@^3.1.5":
|
||||||
|
"integrity" "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz"
|
||||||
|
"version" "3.1.5"
|
||||||
|
dependencies:
|
||||||
|
"node-fetch" "2.6.7"
|
||||||
|
|
||||||
|
"css-color-keywords@^1.0.0":
|
||||||
|
"integrity" "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU="
|
||||||
|
"resolved" "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz"
|
||||||
|
"version" "1.0.0"
|
||||||
|
|
||||||
|
"css-to-react-native@^3.0.0":
|
||||||
|
"integrity" "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz"
|
||||||
|
"version" "3.0.0"
|
||||||
|
dependencies:
|
||||||
|
"camelize" "^1.0.0"
|
||||||
|
"css-color-keywords" "^1.0.0"
|
||||||
|
"postcss-value-parser" "^4.0.2"
|
||||||
|
|
||||||
|
"csstype@^3.0.2":
|
||||||
|
"integrity" "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz"
|
||||||
|
"version" "3.0.8"
|
||||||
|
|
||||||
|
"debug@^4.1.0":
|
||||||
|
"integrity" "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q=="
|
||||||
|
"resolved" "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz"
|
||||||
|
"version" "4.3.3"
|
||||||
|
dependencies:
|
||||||
|
"ms" "2.1.2"
|
||||||
|
|
||||||
|
"esbuild@^0.12.17":
|
||||||
|
"integrity" "sha512-GshKJyVYUnlSXIZj/NheC2O0Kblh42CS7P1wJyTbbIHevTG4jYMS9NNw8EOd8dDWD0dzydYHS01MpZoUcQXB4g=="
|
||||||
|
"resolved" "https://registry.npmjs.org/esbuild/-/esbuild-0.12.17.tgz"
|
||||||
|
"version" "0.12.17"
|
||||||
|
|
||||||
|
"escape-string-regexp@^1.0.5":
|
||||||
|
"integrity" "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||||
|
"resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
|
||||||
|
"version" "1.0.5"
|
||||||
|
|
||||||
|
"globals@^11.1.0":
|
||||||
|
"integrity" "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz"
|
||||||
|
"version" "11.12.0"
|
||||||
|
|
||||||
|
"has-flag@^3.0.0":
|
||||||
|
"integrity" "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||||
|
"resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
|
||||||
|
"version" "3.0.0"
|
||||||
|
|
||||||
|
"history@^4.9.0":
|
||||||
|
"integrity" "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew=="
|
||||||
|
"resolved" "https://registry.npmjs.org/history/-/history-4.10.1.tgz"
|
||||||
|
"version" "4.10.1"
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.1.2"
|
||||||
|
"loose-envify" "^1.2.0"
|
||||||
|
"resolve-pathname" "^3.0.0"
|
||||||
|
"tiny-invariant" "^1.0.2"
|
||||||
|
"tiny-warning" "^1.0.0"
|
||||||
|
"value-equal" "^1.0.1"
|
||||||
|
|
||||||
|
"hoist-non-react-statics@^3.0.0", "hoist-non-react-statics@^3.1.0", "hoist-non-react-statics@^3.3.0":
|
||||||
|
"integrity" "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz"
|
||||||
|
"version" "3.3.2"
|
||||||
|
dependencies:
|
||||||
|
"react-is" "^16.7.0"
|
||||||
|
|
||||||
|
"isarray@0.0.1":
|
||||||
|
"integrity" "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||||
|
"resolved" "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
|
||||||
|
"version" "0.0.1"
|
||||||
|
|
||||||
|
"js-tokens@^3.0.0 || ^4.0.0", "js-tokens@^4.0.0":
|
||||||
|
"integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
|
||||||
|
"version" "4.0.0"
|
||||||
|
|
||||||
|
"jsesc@^2.5.1":
|
||||||
|
"integrity" "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz"
|
||||||
|
"version" "2.5.2"
|
||||||
|
|
||||||
|
"lodash@^4.17.11":
|
||||||
|
"integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
|
"resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
|
||||||
|
"version" "4.17.21"
|
||||||
|
|
||||||
|
"loose-envify@^1.1.0", "loose-envify@^1.2.0", "loose-envify@^1.3.1", "loose-envify@^1.4.0":
|
||||||
|
"integrity" "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="
|
||||||
|
"resolved" "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
|
||||||
|
"version" "1.4.0"
|
||||||
|
dependencies:
|
||||||
|
"js-tokens" "^3.0.0 || ^4.0.0"
|
||||||
|
|
||||||
|
"mini-create-react-context@^0.4.0":
|
||||||
|
"integrity" "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz"
|
||||||
|
"version" "0.4.1"
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.1"
|
||||||
|
"tiny-warning" "^1.0.3"
|
||||||
|
|
||||||
|
"ms@2.1.2":
|
||||||
|
"integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
"resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
||||||
|
"version" "2.1.2"
|
||||||
|
|
||||||
|
"node-fetch@2.6.7":
|
||||||
|
"integrity" "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz"
|
||||||
|
"version" "2.6.7"
|
||||||
|
dependencies:
|
||||||
|
"whatwg-url" "^5.0.0"
|
||||||
|
|
||||||
|
"object-assign@^4.1.1":
|
||||||
|
"integrity" "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||||
|
"resolved" "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
|
||||||
|
"version" "4.1.1"
|
||||||
|
|
||||||
|
"path-to-regexp@^1.7.0":
|
||||||
|
"integrity" "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz"
|
||||||
|
"version" "1.8.0"
|
||||||
|
dependencies:
|
||||||
|
"isarray" "0.0.1"
|
||||||
|
|
||||||
|
"postcss-value-parser@^4.0.2":
|
||||||
|
"integrity" "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
|
||||||
|
"version" "4.2.0"
|
||||||
|
|
||||||
|
"prettier@2.7.1":
|
||||||
|
"integrity" "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g=="
|
||||||
|
"resolved" "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz"
|
||||||
|
"version" "2.7.1"
|
||||||
|
|
||||||
|
"prop-types@^15.0.0", "prop-types@^15.6.2":
|
||||||
|
"integrity" "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz"
|
||||||
|
"version" "15.7.2"
|
||||||
|
dependencies:
|
||||||
|
"loose-envify" "^1.4.0"
|
||||||
|
"object-assign" "^4.1.1"
|
||||||
|
"react-is" "^16.8.1"
|
||||||
|
|
||||||
|
"react-dom@^17.0.2", "react-dom@>= 16.8.0":
|
||||||
|
"integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz"
|
||||||
|
"version" "17.0.2"
|
||||||
|
dependencies:
|
||||||
|
"loose-envify" "^1.1.0"
|
||||||
|
"object-assign" "^4.1.1"
|
||||||
|
"scheduler" "^0.20.2"
|
||||||
|
|
||||||
|
"react-is@^16.6.0":
|
||||||
|
"integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||||
|
"version" "16.13.1"
|
||||||
|
|
||||||
|
"react-is@^16.7.0":
|
||||||
|
"integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||||
|
"version" "16.13.1"
|
||||||
|
|
||||||
|
"react-is@^16.8.1":
|
||||||
|
"integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||||
|
"version" "16.13.1"
|
||||||
|
|
||||||
|
"react-is@^17.0.2", "react-is@>= 16.8.0":
|
||||||
|
"integrity" "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
||||||
|
"resolved" "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
|
||||||
|
"version" "17.0.2"
|
||||||
|
|
||||||
|
"react-router-dom@^5.2.0":
|
||||||
|
"integrity" "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz"
|
||||||
|
"version" "5.2.0"
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.1.2"
|
||||||
|
"history" "^4.9.0"
|
||||||
|
"loose-envify" "^1.3.1"
|
||||||
|
"prop-types" "^15.6.2"
|
||||||
|
"react-router" "5.2.0"
|
||||||
|
"tiny-invariant" "^1.0.2"
|
||||||
|
"tiny-warning" "^1.0.0"
|
||||||
|
|
||||||
|
"react-router@5.2.0":
|
||||||
|
"integrity" "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz"
|
||||||
|
"version" "5.2.0"
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.1.2"
|
||||||
|
"history" "^4.9.0"
|
||||||
|
"hoist-non-react-statics" "^3.1.0"
|
||||||
|
"loose-envify" "^1.3.1"
|
||||||
|
"mini-create-react-context" "^0.4.0"
|
||||||
|
"path-to-regexp" "^1.7.0"
|
||||||
|
"prop-types" "^15.6.2"
|
||||||
|
"react-is" "^16.6.0"
|
||||||
|
"tiny-invariant" "^1.0.2"
|
||||||
|
"tiny-warning" "^1.0.0"
|
||||||
|
|
||||||
|
"react@^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "react@^17.0.2", "react@>= 16.8.0", "react@>=15", "react@>=16", "react@17.0.2":
|
||||||
|
"integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz"
|
||||||
|
"version" "17.0.2"
|
||||||
|
dependencies:
|
||||||
|
"loose-envify" "^1.1.0"
|
||||||
|
"object-assign" "^4.1.1"
|
||||||
|
|
||||||
|
"regenerator-runtime@^0.13.4":
|
||||||
|
"integrity" "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz"
|
||||||
|
"version" "0.13.9"
|
||||||
|
|
||||||
|
"resolve-pathname@^3.0.0":
|
||||||
|
"integrity" "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
|
||||||
|
"resolved" "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz"
|
||||||
|
"version" "3.0.0"
|
||||||
|
|
||||||
|
"scheduler@^0.20.2":
|
||||||
|
"integrity" "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz"
|
||||||
|
"version" "0.20.2"
|
||||||
|
dependencies:
|
||||||
|
"loose-envify" "^1.1.0"
|
||||||
|
"object-assign" "^4.1.1"
|
||||||
|
|
||||||
|
"shallowequal@^1.1.0":
|
||||||
|
"integrity" "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz"
|
||||||
|
"version" "1.1.0"
|
||||||
|
|
||||||
|
"source-map@^0.5.0":
|
||||||
|
"integrity" "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
|
||||||
|
"resolved" "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
|
||||||
|
"version" "0.5.7"
|
||||||
|
|
||||||
|
"styled-components@^5.3.0", "styled-components@>= 2":
|
||||||
|
"integrity" "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz"
|
||||||
|
"version" "5.3.3"
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-module-imports" "^7.0.0"
|
||||||
|
"@babel/traverse" "^7.4.5"
|
||||||
|
"@emotion/is-prop-valid" "^0.8.8"
|
||||||
|
"@emotion/stylis" "^0.8.4"
|
||||||
|
"@emotion/unitless" "^0.7.4"
|
||||||
|
"babel-plugin-styled-components" ">= 1.12.0"
|
||||||
|
"css-to-react-native" "^3.0.0"
|
||||||
|
"hoist-non-react-statics" "^3.0.0"
|
||||||
|
"shallowequal" "^1.1.0"
|
||||||
|
"supports-color" "^5.5.0"
|
||||||
|
|
||||||
|
"supports-color@^5.3.0", "supports-color@^5.5.0":
|
||||||
|
"integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="
|
||||||
|
"resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
|
||||||
|
"version" "5.5.0"
|
||||||
|
dependencies:
|
||||||
|
"has-flag" "^3.0.0"
|
||||||
|
|
||||||
|
"tiny-invariant@^1.0.2":
|
||||||
|
"integrity" "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz"
|
||||||
|
"version" "1.1.0"
|
||||||
|
|
||||||
|
"tiny-warning@^1.0.0", "tiny-warning@^1.0.3":
|
||||||
|
"integrity" "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz"
|
||||||
|
"version" "1.0.3"
|
||||||
|
|
||||||
|
"to-fast-properties@^2.0.0":
|
||||||
|
"integrity" "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
|
||||||
|
"resolved" "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz"
|
||||||
|
"version" "2.0.0"
|
||||||
|
|
||||||
|
"tr46@~0.0.3":
|
||||||
|
"integrity" "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"
|
||||||
|
"version" "0.0.3"
|
||||||
|
|
||||||
|
"typescript@^4.3.5":
|
||||||
|
"integrity" "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA=="
|
||||||
|
"resolved" "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz"
|
||||||
|
"version" "4.3.5"
|
||||||
|
|
||||||
|
"value-equal@^1.0.1":
|
||||||
|
"integrity" "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz"
|
||||||
|
"version" "1.0.1"
|
||||||
|
|
||||||
|
"webidl-conversions@^3.0.0":
|
||||||
|
"integrity" "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||||
|
"resolved" "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz"
|
||||||
|
"version" "3.0.1"
|
||||||
|
|
||||||
|
"whatwg-url@^5.0.0":
|
||||||
|
"integrity" "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="
|
||||||
|
"resolved" "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz"
|
||||||
|
"version" "5.0.0"
|
||||||
|
dependencies:
|
||||||
|
"tr46" "~0.0.3"
|
||||||
|
"webidl-conversions" "^3.0.0"
|
1154
dashboard/package-lock.json
generated
1154
dashboard/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,7 @@ const DeleteEmailTemplateModal = ({
|
|||||||
title: capitalizeFirstLetter(res.error.message),
|
title: capitalizeFirstLetter(res.error.message),
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -53,7 +53,7 @@ const DeleteEmailTemplateModal = ({
|
|||||||
title: capitalizeFirstLetter(res.data?._delete_email_template.message),
|
title: capitalizeFirstLetter(res.data?._delete_email_template.message),
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
onClose();
|
onClose();
|
||||||
|
@@ -51,7 +51,7 @@ const DeleteUserModal = ({
|
|||||||
title: capitalizeFirstLetter(res.error.message),
|
title: capitalizeFirstLetter(res.error.message),
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -60,7 +60,7 @@ const DeleteUserModal = ({
|
|||||||
title: capitalizeFirstLetter(res.data?._delete_user.message),
|
title: capitalizeFirstLetter(res.data?._delete_user.message),
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
onClose();
|
onClose();
|
||||||
|
@@ -44,7 +44,7 @@ const DeleteWebhookModal = ({
|
|||||||
title: capitalizeFirstLetter(res.error.message),
|
title: capitalizeFirstLetter(res.error.message),
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -53,7 +53,7 @@ const DeleteWebhookModal = ({
|
|||||||
title: capitalizeFirstLetter(res.data?._delete_webhook.message),
|
title: capitalizeFirstLetter(res.data?._delete_webhook.message),
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
onClose();
|
onClose();
|
||||||
|
@@ -104,14 +104,14 @@ const EditUserModal = ({
|
|||||||
title: 'User data update failed',
|
title: 'User data update failed',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
} else if (res.data?._update_user?.id) {
|
} else if (res.data?._update_user?.id) {
|
||||||
toast({
|
toast({
|
||||||
title: 'User data update successful',
|
title: 'User data update successful',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
onClose();
|
onClose();
|
||||||
|
@@ -8,86 +8,90 @@ 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">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">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.
|
||||||
@@ -98,15 +102,10 @@ const Features = ({ variables, setVariables }: any) => {
|
|||||||
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>
|
|
||||||
<Divider paddingY={5} />
|
|
||||||
<Text fontSize="md" paddingTop={5} fontWeight="bold" mb={5}>
|
|
||||||
Enable Features
|
|
||||||
</Text>
|
|
||||||
<Stack spacing={6}>
|
|
||||||
<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">
|
||||||
|
@@ -43,7 +43,7 @@ const JSTConfigurations = ({
|
|||||||
title: `JWT config copied successfully`,
|
title: `JWT config copied successfully`,
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error({
|
console.error({
|
||||||
@@ -54,14 +54,13 @@ const JSTConfigurations = ({
|
|||||||
title: `Failed to copy JWT config`,
|
title: `Failed to copy JWT config`,
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{' '}
|
|
||||||
<Flex
|
<Flex
|
||||||
borderRadius={5}
|
borderRadius={5}
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@@ -16,8 +16,15 @@ import {
|
|||||||
FaLinkedin,
|
FaLinkedin,
|
||||||
FaApple,
|
FaApple,
|
||||||
FaTwitter,
|
FaTwitter,
|
||||||
|
FaMicrosoft,
|
||||||
} 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,
|
||||||
@@ -69,6 +76,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}>
|
||||||
@@ -303,6 +346,57 @@ 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"
|
||||||
|
>
|
||||||
|
<FaMicrosoft />
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '35%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
marginRight="1.5%"
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={TextInputType.MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID}
|
||||||
|
placeholder="Microsoft Active Directory TenantID"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '35%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
marginRight="1.5%"
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={TextInputType.MICROSOFT_CLIENT_ID}
|
||||||
|
placeholder="Microsoft 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.MICROSOFT_CLIENT_SECRET}
|
||||||
|
placeholder="Microsoft Client Secret"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Flex>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -73,7 +73,7 @@ const GenerateKeysModal = ({ jwtType, getData }: propTypes) => {
|
|||||||
title: 'Error occurred generating jwt keys',
|
title: 'Error occurred generating jwt keys',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
closeHandler();
|
closeHandler();
|
||||||
} else {
|
} else {
|
||||||
@@ -107,7 +107,7 @@ const GenerateKeysModal = ({ jwtType, getData }: propTypes) => {
|
|||||||
title: 'Error occurred setting jwt keys',
|
title: 'Error occurred setting jwt keys',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -116,7 +116,7 @@ const GenerateKeysModal = ({ jwtType, getData }: propTypes) => {
|
|||||||
title: 'JWT keys updated successfully',
|
title: 'JWT keys updated successfully',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
closeHandler();
|
closeHandler();
|
||||||
};
|
};
|
||||||
|
@@ -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,
|
||||||
|
@@ -105,7 +105,7 @@ const InviteMembersModal = ({
|
|||||||
title: 'Invites sent successfully!',
|
title: 'Invites sent successfully!',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
updateUserList();
|
updateUserList();
|
||||||
@@ -117,7 +117,7 @@ const InviteMembersModal = ({
|
|||||||
title: error?.message || 'Error occurred, try again!',
|
title: error?.message || 'Error occurred, try again!',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
@@ -173,7 +173,7 @@ const UpdateEmailTemplate = ({
|
|||||||
title: capitalizeFirstLetter(res.error.message),
|
title: capitalizeFirstLetter(res.error.message),
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
} else if (
|
} else if (
|
||||||
res.data?._add_email_template ||
|
res.data?._add_email_template ||
|
||||||
@@ -186,7 +186,7 @@ const UpdateEmailTemplate = ({
|
|||||||
),
|
),
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
setTemplateData({
|
setTemplateData({
|
||||||
...initTemplateData,
|
...initTemplateData,
|
||||||
|
@@ -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],
|
||||||
@@ -290,7 +298,7 @@ const UpdateWebhookModal = ({
|
|||||||
title: capitalizeFirstLetter(res.error.message),
|
title: capitalizeFirstLetter(res.error.message),
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
} else if (res.data?._add_webhook || res.data?._update_webhook) {
|
} else if (res.data?._add_webhook || res.data?._update_webhook) {
|
||||||
toast({
|
toast({
|
||||||
@@ -299,7 +307,7 @@ const UpdateWebhookModal = ({
|
|||||||
),
|
),
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
setWebhook({
|
setWebhook({
|
||||||
...initWebhookData,
|
...initWebhookData,
|
||||||
@@ -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"
|
||||||
|
@@ -10,6 +10,8 @@ export const TextInputType = {
|
|||||||
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
|
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
|
||||||
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
|
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
|
||||||
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
|
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
|
||||||
|
MICROSOFT_CLIENT_ID: 'MICROSOFT_CLIENT_ID',
|
||||||
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: 'MICROSOFT_ACTIVE_DIRECTORY_TENANT_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',
|
||||||
@@ -38,6 +40,7 @@ export const HiddenInputType = {
|
|||||||
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
|
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
|
||||||
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
||||||
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
||||||
|
MICROSOFT_CLIENT_SECRET: 'MICROSOFT_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',
|
||||||
@@ -54,6 +57,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 = {
|
||||||
@@ -120,6 +125,9 @@ export interface envVarTypes {
|
|||||||
APPLE_CLIENT_SECRET: string;
|
APPLE_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_SECRET: string;
|
||||||
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: string;
|
||||||
ROLES: [string] | [];
|
ROLES: [string] | [];
|
||||||
DEFAULT_ROLES: [string] | [];
|
DEFAULT_ROLES: [string] | [];
|
||||||
PROTECTED_ROLES: [string] | [];
|
PROTECTED_ROLES: [string] | [];
|
||||||
@@ -155,6 +163,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const envSubViews = {
|
export const envSubViews = {
|
||||||
@@ -173,6 +183,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',
|
||||||
@@ -342,3 +353,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',
|
||||||
|
};
|
||||||
|
@@ -32,6 +32,9 @@ export const EnvVariablesQuery = `
|
|||||||
APPLE_CLIENT_SECRET
|
APPLE_CLIENT_SECRET
|
||||||
TWITTER_CLIENT_ID
|
TWITTER_CLIENT_ID
|
||||||
TWITTER_CLIENT_SECRET
|
TWITTER_CLIENT_SECRET
|
||||||
|
MICROSOFT_CLIENT_ID
|
||||||
|
MICROSOFT_CLIENT_SECRET
|
||||||
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID
|
||||||
DEFAULT_ROLES
|
DEFAULT_ROLES
|
||||||
PROTECTED_ROLES
|
PROTECTED_ROLES
|
||||||
ROLES
|
ROLES
|
||||||
@@ -67,6 +70,8 @@ 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@@ -115,6 +120,7 @@ export const WebhooksDataQuery = `
|
|||||||
_webhooks(params: $params){
|
_webhooks(params: $params){
|
||||||
webhooks{
|
webhooks{
|
||||||
id
|
id
|
||||||
|
event_description
|
||||||
event_name
|
event_name
|
||||||
endpoint
|
endpoint
|
||||||
enabled
|
enabled
|
||||||
|
@@ -57,7 +57,7 @@ export default function Auth() {
|
|||||||
title: capitalizeFirstLetter(error.message),
|
title: capitalizeFirstLetter(error.message),
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -52,6 +52,9 @@ const Environment = () => {
|
|||||||
APPLE_CLIENT_SECRET: '',
|
APPLE_CLIENT_SECRET: '',
|
||||||
TWITTER_CLIENT_ID: '',
|
TWITTER_CLIENT_ID: '',
|
||||||
TWITTER_CLIENT_SECRET: '',
|
TWITTER_CLIENT_SECRET: '',
|
||||||
|
MICROSOFT_CLIENT_ID: '',
|
||||||
|
MICROSOFT_CLIENT_SECRET: '',
|
||||||
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: '',
|
||||||
ROLES: [],
|
ROLES: [],
|
||||||
DEFAULT_ROLES: [],
|
DEFAULT_ROLES: [],
|
||||||
PROTECTED_ROLES: [],
|
PROTECTED_ROLES: [],
|
||||||
@@ -87,6 +90,8 @@ 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: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const [fieldVisibility, setFieldVisibility] = React.useState<
|
const [fieldVisibility, setFieldVisibility] = React.useState<
|
||||||
@@ -203,7 +208,7 @@ const Environment = () => {
|
|||||||
} variables`,
|
} variables`,
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -180,14 +180,14 @@ export default function Users() {
|
|||||||
title: 'User verification failed',
|
title: 'User verification failed',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
} else if (res.data?._update_user?.id) {
|
} else if (res.data?._update_user?.id) {
|
||||||
toast({
|
toast({
|
||||||
title: 'User verification successful',
|
title: 'User verification successful',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
updateUserList();
|
updateUserList();
|
||||||
@@ -211,14 +211,14 @@ export default function Users() {
|
|||||||
title: 'User access enable failed',
|
title: 'User access enable failed',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toast({
|
toast({
|
||||||
title: 'User access enabled successfully',
|
title: 'User access enabled successfully',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
updateUserList();
|
updateUserList();
|
||||||
@@ -236,14 +236,14 @@ export default function Users() {
|
|||||||
title: 'User access revoke failed',
|
title: 'User access revoke failed',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toast({
|
toast({
|
||||||
title: 'User access revoked successfully',
|
title: 'User access revoked successfully',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
updateUserList();
|
updateUserList();
|
||||||
@@ -268,7 +268,7 @@ export default function Users() {
|
|||||||
} for user`,
|
} for user`,
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
updateUserList();
|
updateUserList();
|
||||||
return;
|
return;
|
||||||
@@ -277,7 +277,7 @@ export default function Users() {
|
|||||||
title: 'Multi factor authentication update failed for user',
|
title: 'Multi factor authentication update failed for user',
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
position: 'bottom-right',
|
position: 'top-right',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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>;
|
||||||
@@ -117,6 +118,7 @@ const Webhooks = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchWebookData();
|
fetchWebookData();
|
||||||
}, [paginationProps.page, paginationProps.limit]);
|
}, [paginationProps.page, paginationProps.limit]);
|
||||||
|
console.log({ webhookData });
|
||||||
return (
|
return (
|
||||||
<Box m="5" py="5" px="10" bg="white" rounded="md">
|
<Box m="5" py="5" px="10" bg="white" rounded="md">
|
||||||
<Flex margin="2% 0" justifyContent="space-between" alignItems="center">
|
<Flex margin="2% 0" justifyContent="space-between" alignItems="center">
|
||||||
@@ -134,6 +136,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 +150,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 +270,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}
|
||||||
|
1889
dashboard/yarn.lock
Normal file
1889
dashboard/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
39
scripts/couchbase-test.sh
Normal file
39
scripts/couchbase-test.sh
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -x
|
||||||
|
set -m
|
||||||
|
|
||||||
|
sleep 15
|
||||||
|
|
||||||
|
# Setup index and memory quota
|
||||||
|
# curl -v -X POST http://127.0.0.1:8091/pools/default -d memoryQuota=300 -d indexMemoryQuota=300
|
||||||
|
|
||||||
|
# Setup services
|
||||||
|
curl -v http://127.0.0.1:8091/node/controller/setupServices -d services=kv%2Cn1ql%2Cindex
|
||||||
|
|
||||||
|
# Setup credentials
|
||||||
|
curl -v http://127.0.0.1:8091/settings/web -d port=8091 -d username=Administrator -d password=password
|
||||||
|
|
||||||
|
# Setup Memory Optimized Indexes
|
||||||
|
curl -i -u Administrator:password -X POST http://127.0.0.1:8091/settings/indexes -d 'storageMode=memory_optimized'
|
||||||
|
|
||||||
|
# Load travel-sample bucket
|
||||||
|
#curl -v -u Administrator:password -X POST http://127.0.0.1:8091/sampleBuckets/install -d '["travel-sample"]'
|
||||||
|
|
||||||
|
echo "Type: $TYPE"
|
||||||
|
|
||||||
|
if [ "$TYPE" = "WORKER" ]; then
|
||||||
|
echo "Sleeping ..."
|
||||||
|
sleep 15
|
||||||
|
|
||||||
|
#IP=`hostname -s`
|
||||||
|
IP=`hostname -I | cut -d ' ' -f1`
|
||||||
|
echo "IP: " $IP
|
||||||
|
|
||||||
|
echo "Auto Rebalance: $AUTO_REBALANCE"
|
||||||
|
if [ "$AUTO_REBALANCE" = "true" ]; then
|
||||||
|
couchbase-cli rebalance --cluster=$COUCHBASE_MASTER:8091 --user=Administrator --password=password --server-add=$IP --server-add-username=Administrator --server-add-password=password
|
||||||
|
else
|
||||||
|
couchbase-cli server-add --cluster=$COUCHBASE_MASTER:8091 --user=Administrator --password=password --server-add=$IP --server-add-username=Administrator --server-add-password=password
|
||||||
|
fi;
|
||||||
|
fi;
|
@@ -3,6 +3,8 @@ package constants
|
|||||||
const (
|
const (
|
||||||
// AuthRecipeMethodBasicAuth is the basic_auth auth method
|
// AuthRecipeMethodBasicAuth is the basic_auth auth method
|
||||||
AuthRecipeMethodBasicAuth = "basic_auth"
|
AuthRecipeMethodBasicAuth = "basic_auth"
|
||||||
|
// AuthRecipeMethodMobileBasicAuth is the mobile basic_auth method, where user can signup using mobile number and password
|
||||||
|
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"
|
||||||
// AuthRecipeMethodGoogle is the google auth method
|
// AuthRecipeMethodGoogle is the google auth method
|
||||||
@@ -17,4 +19,6 @@ const (
|
|||||||
AuthRecipeMethodApple = "apple"
|
AuthRecipeMethodApple = "apple"
|
||||||
// AuthRecipeMethodTwitter is the twitter auth method
|
// AuthRecipeMethodTwitter is the twitter auth method
|
||||||
AuthRecipeMethodTwitter = "twitter"
|
AuthRecipeMethodTwitter = "twitter"
|
||||||
|
// AuthRecipeMethodMicrosoft is the microsoft auth method
|
||||||
|
AuthRecipeMethodMicrosoft = "microsoft"
|
||||||
)
|
)
|
||||||
|
@@ -27,6 +27,6 @@ const (
|
|||||||
DbTypePlanetScaleDB = "planetscale"
|
DbTypePlanetScaleDB = "planetscale"
|
||||||
// DbTypeDynamoDB is the Dynamo database type
|
// DbTypeDynamoDB is the Dynamo database type
|
||||||
DbTypeDynamoDB = "dynamodb"
|
DbTypeDynamoDB = "dynamodb"
|
||||||
// DbTypeSurrealDB is the SurrealDB database type
|
// DbTypeCouchbaseDB is the Couchbase database type
|
||||||
DbTypeSurrealDB = "surrealdb"
|
DbTypeCouchbaseDB = "couchbase"
|
||||||
)
|
)
|
||||||
|
@@ -43,6 +43,13 @@ const (
|
|||||||
EnvKeyDatabaseCertKey = "DATABASE_CERT_KEY"
|
EnvKeyDatabaseCertKey = "DATABASE_CERT_KEY"
|
||||||
// EnvKeyDatabaseCACert key for env variable DATABASE_CA_CERT
|
// EnvKeyDatabaseCACert key for env variable DATABASE_CA_CERT
|
||||||
EnvKeyDatabaseCACert = "DATABASE_CA_CERT"
|
EnvKeyDatabaseCACert = "DATABASE_CA_CERT"
|
||||||
|
// EnvCouchbaseBucket key for env variable COUCHBASE_BUCKET
|
||||||
|
EnvCouchbaseBucket = "COUCHBASE_BUCKET"
|
||||||
|
// EnvCouchbaseBucketRAMQuotaMB key for env variable COUCHBASE_BUCKET_RAM_QUOTA
|
||||||
|
// This value should be parsed as number
|
||||||
|
EnvCouchbaseBucketRAMQuotaMB = "COUCHBASE_BUCKET_RAM_QUOTA"
|
||||||
|
// EnvCouchbaseBucket key for env variable COUCHBASE_SCOPE
|
||||||
|
EnvCouchbaseScope = "COUCHBASE_SCOPE"
|
||||||
// EnvKeySmtpHost key for env variable SMTP_HOST
|
// EnvKeySmtpHost key for env variable SMTP_HOST
|
||||||
EnvKeySmtpHost = "SMTP_HOST"
|
EnvKeySmtpHost = "SMTP_HOST"
|
||||||
// EnvKeySmtpPort key for env variable SMTP_PORT
|
// EnvKeySmtpPort key for env variable SMTP_PORT
|
||||||
@@ -101,6 +108,12 @@ const (
|
|||||||
EnvKeyTwitterClientID = "TWITTER_CLIENT_ID"
|
EnvKeyTwitterClientID = "TWITTER_CLIENT_ID"
|
||||||
// EnvKeyTwitterClientSecret key for env variable TWITTER_CLIENT_SECRET
|
// EnvKeyTwitterClientSecret key for env variable TWITTER_CLIENT_SECRET
|
||||||
EnvKeyTwitterClientSecret = "TWITTER_CLIENT_SECRET"
|
EnvKeyTwitterClientSecret = "TWITTER_CLIENT_SECRET"
|
||||||
|
// EnvKeyMicrosoftClientID key for env variable MICROSOFT_CLIENT_ID
|
||||||
|
EnvKeyMicrosoftClientID = "MICROSOFT_CLIENT_ID"
|
||||||
|
// EnvKeyMicrosoftActiveDirectoryTenantID key for env variable MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID
|
||||||
|
EnvKeyMicrosoftActiveDirectoryTenantID = "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID"
|
||||||
|
// EnvKeyMicrosoftClientSecret key for env variable MICROSOFT_CLIENT_SECRET
|
||||||
|
EnvKeyMicrosoftClientSecret = "MICROSOFT_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
|
||||||
@@ -125,6 +138,8 @@ const (
|
|||||||
EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION"
|
EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION"
|
||||||
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
|
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
|
||||||
EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION"
|
EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION"
|
||||||
|
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_MOBILE_BASIC_AUTH
|
||||||
|
EnvKeyDisableMobileBasicAuthentication = "DISABLE_MOBILE_BASIC_AUTHENTICATION"
|
||||||
// EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN
|
// EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN
|
||||||
EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN"
|
EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN"
|
||||||
// EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE
|
// EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE
|
||||||
@@ -151,4 +166,12 @@ 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"
|
||||||
)
|
)
|
||||||
|
@@ -16,4 +16,8 @@ const (
|
|||||||
LinkedInEmailURL = "https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))"
|
LinkedInEmailURL = "https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))"
|
||||||
|
|
||||||
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"
|
||||||
|
|
||||||
|
// Get microsoft user info.
|
||||||
|
// Ref: https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo
|
||||||
|
MicrosoftUserInfoURL = "https://graph.microsoft.com/oidc/userinfo"
|
||||||
)
|
)
|
||||||
|
@@ -7,10 +7,10 @@ import (
|
|||||||
"github.com/authorizerdev/authorizer/server/db/providers"
|
"github.com/authorizerdev/authorizer/server/db/providers"
|
||||||
"github.com/authorizerdev/authorizer/server/db/providers/arangodb"
|
"github.com/authorizerdev/authorizer/server/db/providers/arangodb"
|
||||||
"github.com/authorizerdev/authorizer/server/db/providers/cassandradb"
|
"github.com/authorizerdev/authorizer/server/db/providers/cassandradb"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/providers/couchbase"
|
||||||
"github.com/authorizerdev/authorizer/server/db/providers/dynamodb"
|
"github.com/authorizerdev/authorizer/server/db/providers/dynamodb"
|
||||||
"github.com/authorizerdev/authorizer/server/db/providers/mongodb"
|
"github.com/authorizerdev/authorizer/server/db/providers/mongodb"
|
||||||
"github.com/authorizerdev/authorizer/server/db/providers/sql"
|
"github.com/authorizerdev/authorizer/server/db/providers/sql"
|
||||||
"github.com/authorizerdev/authorizer/server/db/providers/surrealdb"
|
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,12 +22,12 @@ func InitDB() error {
|
|||||||
|
|
||||||
envs := memorystore.RequiredEnvStoreObj.GetRequiredEnv()
|
envs := memorystore.RequiredEnvStoreObj.GetRequiredEnv()
|
||||||
|
|
||||||
isSQL := envs.DatabaseType != constants.DbTypeArangodb && envs.DatabaseType != constants.DbTypeMongodb && envs.DatabaseType != constants.DbTypeCassandraDB && envs.DatabaseType != constants.DbTypeScyllaDB && envs.DatabaseType != constants.DbTypeDynamoDB && envs.DatabaseType != constants.DbTypeSurrealDB
|
isSQL := envs.DatabaseType != constants.DbTypeArangodb && envs.DatabaseType != constants.DbTypeMongodb && envs.DatabaseType != constants.DbTypeCassandraDB && envs.DatabaseType != constants.DbTypeScyllaDB && envs.DatabaseType != constants.DbTypeDynamoDB && envs.DatabaseType != constants.DbTypeCouchbaseDB
|
||||||
isArangoDB := envs.DatabaseType == constants.DbTypeArangodb
|
isArangoDB := envs.DatabaseType == constants.DbTypeArangodb
|
||||||
isMongoDB := envs.DatabaseType == constants.DbTypeMongodb
|
isMongoDB := envs.DatabaseType == constants.DbTypeMongodb
|
||||||
isCassandra := envs.DatabaseType == constants.DbTypeCassandraDB || envs.DatabaseType == constants.DbTypeScyllaDB
|
isCassandra := envs.DatabaseType == constants.DbTypeCassandraDB || envs.DatabaseType == constants.DbTypeScyllaDB
|
||||||
isDynamoDB := envs.DatabaseType == constants.DbTypeDynamoDB
|
isDynamoDB := envs.DatabaseType == constants.DbTypeDynamoDB
|
||||||
isSurrealDB := envs.DatabaseType == constants.DbTypeSurrealDB
|
isCouchbaseDB := envs.DatabaseType == constants.DbTypeCouchbaseDB
|
||||||
|
|
||||||
if isSQL {
|
if isSQL {
|
||||||
log.Info("Initializing SQL Driver for: ", envs.DatabaseType)
|
log.Info("Initializing SQL Driver for: ", envs.DatabaseType)
|
||||||
@@ -74,11 +74,11 @@ func InitDB() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isSurrealDB {
|
if isCouchbaseDB {
|
||||||
log.Info("Initializing Surreal Driver")
|
log.Info("Initializing CouchbaseDB Driver for: ", envs.DatabaseType)
|
||||||
Provider, err = surrealdb.NewProvider()
|
Provider, err = couchbase.NewProvider()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to initialize Surreal driver: ", err)
|
log.Fatal("Failed to initialize Couchbase driver: ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
@@ -36,10 +35,3 @@ func (e *EmailTemplate) AsAPIEmailTemplate() *model.EmailTemplate {
|
|||||||
UpdatedAt: refs.NewInt64Ref(e.UpdatedAt),
|
UpdatedAt: refs.NewInt64Ref(e.UpdatedAt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EmailTemplate) ToMap() map[string]interface{} {
|
|
||||||
res := map[string]interface{}{}
|
|
||||||
data, _ := json.Marshal(e) // Convert to a json string
|
|
||||||
json.Unmarshal(data, &res) // Convert to a map
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
@@ -1,22 +1,14 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
// Env model for db
|
// Env model for db
|
||||||
type Env struct {
|
type Env 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"`
|
||||||
EnvData string `json:"env" bson:"env" cql:"env" dynamo:"env"`
|
EnvData string `json:"env" bson:"env" cql:"env" dynamo:"env"`
|
||||||
Hash string `json:"hash" bson:"hash" cql:"hash" dynamo:"hash"`
|
Hash string `json:"hash" bson:"hash" cql:"hash" dynamo:"hash"`
|
||||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
EncryptionKey string `json:"encryption_key" bson:"encryption_key" cql:"encryption_key" dynamo:"encryption_key"` // couchbase has "hash" as reserved keyword so we cannot use it. This will be empty for other dbs.
|
||||||
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"`
|
||||||
}
|
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||||
|
|
||||||
func (env *Env) ToMap() map[string]interface{} {
|
|
||||||
res := map[string]interface{}{}
|
|
||||||
data, _ := json.Marshal(env) // Convert to a json string
|
|
||||||
json.Unmarshal(data, &res) // Convert to a map
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
@@ -13,10 +13,6 @@ type CollectionList struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DB/Namespace
|
|
||||||
DBNamespace = "authorizer"
|
|
||||||
// Identifier field used for surreal db
|
|
||||||
SurrealDbIdentifier = "identifier"
|
|
||||||
// Prefix for table name / collection names
|
// Prefix for table name / collection names
|
||||||
Prefix = "authorizer_"
|
Prefix = "authorizer_"
|
||||||
// Collections / Tables available for authorizer in the database (used for dbs other than gorm)
|
// Collections / Tables available for authorizer in the database (used for dbs other than gorm)
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
// 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
|
||||||
@@ -16,10 +14,3 @@ type OTP struct {
|
|||||||
type Paging struct {
|
type Paging struct {
|
||||||
ID string `json:"id,omitempty" dynamo:"id,hash"`
|
ID string `json:"id,omitempty" dynamo:"id,hash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OTP) ToMap() map[string]interface{} {
|
|
||||||
res := map[string]interface{}{}
|
|
||||||
data, _ := json.Marshal(o) // Convert to a json string
|
|
||||||
json.Unmarshal(data, &res) // Convert to a map
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
// Session model for db
|
// Session model for db
|
||||||
@@ -14,10 +12,3 @@ type Session struct {
|
|||||||
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"`
|
||||||
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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) ToMap() map[string]interface{} {
|
|
||||||
res := map[string]interface{}{}
|
|
||||||
data, _ := json.Marshal(s) // Convert to a json string
|
|
||||||
json.Unmarshal(data, &res) // Convert to a map
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
@@ -42,10 +41,3 @@ func (v *VerificationRequest) AsAPIVerificationRequest() *model.VerificationRequ
|
|||||||
UpdatedAt: refs.NewInt64Ref(v.UpdatedAt),
|
UpdatedAt: refs.NewInt64Ref(v.UpdatedAt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VerificationRequest) ToMap() map[string]interface{} {
|
|
||||||
res := map[string]interface{}{}
|
|
||||||
data, _ := json.Marshal(v) // Convert to a json string
|
|
||||||
json.Unmarshal(data, &res) // Convert to a map
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
@@ -10,42 +10,42 @@ 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"`
|
||||||
EndPoint string `json:"endpoint" bson:"endpoint" cql:"endpoint" dynamo:"endpoint"`
|
EventDescription string `json:"event_description" bson:"event_description" cql:"event_description" dynamo:"event_description"`
|
||||||
Headers string `json:"headers" bson:"headers" cql:"headers" dynamo:"headers"`
|
EndPoint string `json:"endpoint" bson:"endpoint" cql:"endpoint" dynamo:"endpoint"`
|
||||||
Enabled bool `json:"enabled" bson:"enabled" cql:"enabled" dynamo:"enabled"`
|
Headers string `json:"headers" bson:"headers" cql:"headers" dynamo:"headers"`
|
||||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
Enabled bool `json:"enabled" bson:"enabled" cql:"enabled" dynamo:"enabled"`
|
||||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||||
|
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AsAPIWebhook to return webhook as graphql response object
|
// AsAPIWebhook to return webhook as graphql response object
|
||||||
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),
|
||||||
Endpoint: refs.NewStringRef(w.EndPoint),
|
EventDescription: refs.NewStringRef(w.EventDescription),
|
||||||
Headers: headersMap,
|
Endpoint: refs.NewStringRef(w.EndPoint),
|
||||||
Enabled: refs.NewBoolRef(w.Enabled),
|
Headers: headersMap,
|
||||||
CreatedAt: refs.NewInt64Ref(w.CreatedAt),
|
Enabled: refs.NewBoolRef(w.Enabled),
|
||||||
UpdatedAt: refs.NewInt64Ref(w.UpdatedAt),
|
CreatedAt: refs.NewInt64Ref(w.CreatedAt),
|
||||||
|
UpdatedAt: refs.NewInt64Ref(w.UpdatedAt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Webhook) ToMap() map[string]interface{} {
|
|
||||||
res := map[string]interface{}{}
|
|
||||||
data, _ := json.Marshal(w) // Convert to a json string
|
|
||||||
json.Unmarshal(data, &res) // Convert to a map
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
@@ -38,10 +37,3 @@ func (w *WebhookLog) AsAPIWebhookLog() *model.WebhookLog {
|
|||||||
UpdatedAt: refs.NewInt64Ref(w.UpdatedAt),
|
UpdatedAt: refs.NewInt64Ref(w.UpdatedAt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WebhookLog) ToMap() map[string]interface{} {
|
|
||||||
res := map[string]interface{}{}
|
|
||||||
data, _ := json.Marshal(w) // Convert to a json string
|
|
||||||
json.Unmarshal(data, &res) // Convert to a map
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
@@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"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"
|
||||||
@@ -52,7 +51,7 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin
|
|||||||
|
|
||||||
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 := driver.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
|
||||||
|
@@ -2,8 +2,11 @@ package arangodb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/arangodb/go-driver"
|
|
||||||
arangoDriver "github.com/arangodb/go-driver"
|
arangoDriver "github.com/arangodb/go-driver"
|
||||||
"github.com/arangodb/go-driver/http"
|
"github.com/arangodb/go-driver/http"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
@@ -22,44 +25,75 @@ type provider struct {
|
|||||||
func NewProvider() (*provider, error) {
|
func NewProvider() (*provider, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
||||||
conn, err := http.NewConnection(http.ConnectionConfig{
|
dbUsername := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseUsername
|
||||||
|
dbPassword := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePassword
|
||||||
|
dbCACertificate := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseCACert
|
||||||
|
httpConfig := http.ConnectionConfig{
|
||||||
Endpoints: []string{dbURL},
|
Endpoints: []string{dbURL},
|
||||||
})
|
}
|
||||||
|
// If ca certificate if present, create tls config
|
||||||
|
if dbCACertificate != "" {
|
||||||
|
caCert, err := base64.StdEncoding.DecodeString(dbCACertificate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Prepare TLS Config
|
||||||
|
tlsConfig := &tls.Config{}
|
||||||
|
certPool := x509.NewCertPool()
|
||||||
|
if success := certPool.AppendCertsFromPEM(caCert); !success {
|
||||||
|
return nil, fmt.Errorf("invalid certificate")
|
||||||
|
}
|
||||||
|
tlsConfig.RootCAs = certPool
|
||||||
|
httpConfig.TLSConfig = tlsConfig
|
||||||
|
}
|
||||||
|
// Create new http connection
|
||||||
|
conn, err := http.NewConnection(httpConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
clientConfig := arangoDriver.ClientConfig{
|
||||||
arangoClient, err := arangoDriver.NewClient(arangoDriver.ClientConfig{
|
|
||||||
Connection: conn,
|
Connection: conn,
|
||||||
})
|
}
|
||||||
|
if dbUsername != "" && dbPassword != "" {
|
||||||
|
clientConfig.Authentication = arangoDriver.BasicAuthentication(dbUsername, dbPassword)
|
||||||
|
}
|
||||||
|
arangoClient, err := arangoDriver.NewClient(clientConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var arangodb driver.Database
|
var arangodb arangoDriver.Database
|
||||||
dbName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName
|
dbName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName
|
||||||
arangodb_exists, err := arangoClient.DatabaseExists(nil, dbName)
|
arangodb_exists, err := arangoClient.DatabaseExists(ctx, dbName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if arangodb_exists {
|
if arangodb_exists {
|
||||||
arangodb, err = arangoClient.Database(nil, dbName)
|
arangodb, err = arangoClient.Database(ctx, dbName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
arangodb, err = arangoClient.CreateDatabase(nil, dbName, nil)
|
arangodb, err = arangoClient.CreateDatabase(ctx, dbName, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
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 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if !userCollectionExists {
|
if !userCollectionExists {
|
||||||
_, err = arangodb.CreateCollection(ctx, models.Collections.User, nil)
|
_, err = arangodb.CreateCollection(ctx, models.Collections.User, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
userCollection, _ := arangodb.Collection(nil, models.Collections.User)
|
userCollection, err := arangodb.Collection(ctx, models.Collections.User)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
userCollection.EnsureHashIndex(ctx, []string{"email"}, &arangoDriver.EnsureHashIndexOptions{
|
userCollection.EnsureHashIndex(ctx, []string{"email"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
Unique: true,
|
Unique: true,
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
@@ -70,6 +104,9 @@ func NewProvider() (*provider, error) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
verificationRequestCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.VerificationRequest)
|
verificationRequestCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.VerificationRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if !verificationRequestCollectionExists {
|
if !verificationRequestCollectionExists {
|
||||||
_, err = arangodb.CreateCollection(ctx, models.Collections.VerificationRequest, nil)
|
_, err = arangodb.CreateCollection(ctx, models.Collections.VerificationRequest, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -77,7 +114,10 @@ func NewProvider() (*provider, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verificationRequestCollection, _ := arangodb.Collection(nil, models.Collections.VerificationRequest)
|
verificationRequestCollection, err := arangodb.Collection(ctx, models.Collections.VerificationRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
verificationRequestCollection.EnsureHashIndex(ctx, []string{"email", "identifier"}, &arangoDriver.EnsureHashIndexOptions{
|
verificationRequestCollection.EnsureHashIndex(ctx, []string{"email", "identifier"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
Unique: true,
|
Unique: true,
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
@@ -87,6 +127,9 @@ func NewProvider() (*provider, error) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
sessionCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Session)
|
sessionCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Session)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if !sessionCollectionExists {
|
if !sessionCollectionExists {
|
||||||
_, err = arangodb.CreateCollection(ctx, models.Collections.Session, nil)
|
_, err = arangodb.CreateCollection(ctx, models.Collections.Session, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -94,13 +137,19 @@ func NewProvider() (*provider, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionCollection, _ := arangodb.Collection(nil, models.Collections.Session)
|
sessionCollection, err := arangodb.Collection(ctx, models.Collections.Session)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
sessionCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{
|
sessionCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
configCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Env)
|
envCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Env)
|
||||||
if !configCollectionExists {
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !envCollectionExists {
|
||||||
_, err = arangodb.CreateCollection(ctx, models.Collections.Env, nil)
|
_, err = arangodb.CreateCollection(ctx, models.Collections.Env, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -108,6 +157,9 @@ func NewProvider() (*provider, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
webhookCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Webhook)
|
webhookCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Webhook)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if !webhookCollectionExists {
|
if !webhookCollectionExists {
|
||||||
_, err = arangodb.CreateCollection(ctx, models.Collections.Webhook, nil)
|
_, err = arangodb.CreateCollection(ctx, models.Collections.Webhook, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -115,13 +167,19 @@ func NewProvider() (*provider, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
webhookCollection, _ := arangodb.Collection(nil, models.Collections.Webhook)
|
webhookCollection, err := arangodb.Collection(ctx, models.Collections.Webhook)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
webhookCollection.EnsureHashIndex(ctx, []string{"event_name"}, &arangoDriver.EnsureHashIndexOptions{
|
webhookCollection.EnsureHashIndex(ctx, []string{"event_name"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
Unique: true,
|
Unique: true,
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
webhookLogCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.WebhookLog)
|
webhookLogCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.WebhookLog)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if !webhookLogCollectionExists {
|
if !webhookLogCollectionExists {
|
||||||
_, err = arangodb.CreateCollection(ctx, models.Collections.WebhookLog, nil)
|
_, err = arangodb.CreateCollection(ctx, models.Collections.WebhookLog, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -129,12 +187,18 @@ func NewProvider() (*provider, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
webhookLogCollection, _ := arangodb.Collection(nil, models.Collections.WebhookLog)
|
webhookLogCollection, err := arangodb.Collection(ctx, models.Collections.WebhookLog)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
webhookLogCollection.EnsureHashIndex(ctx, []string{"webhook_id"}, &arangoDriver.EnsureHashIndexOptions{
|
webhookLogCollection.EnsureHashIndex(ctx, []string{"webhook_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
emailTemplateCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.EmailTemplate)
|
emailTemplateCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.EmailTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if !emailTemplateCollectionExists {
|
if !emailTemplateCollectionExists {
|
||||||
_, err = arangodb.CreateCollection(ctx, models.Collections.EmailTemplate, nil)
|
_, err = arangodb.CreateCollection(ctx, models.Collections.EmailTemplate, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -142,13 +206,19 @@ func NewProvider() (*provider, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emailTemplateCollection, _ := arangodb.Collection(nil, models.Collections.EmailTemplate)
|
emailTemplateCollection, err := arangodb.Collection(ctx, models.Collections.EmailTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
emailTemplateCollection.EnsureHashIndex(ctx, []string{"event_name"}, &arangoDriver.EnsureHashIndexOptions{
|
emailTemplateCollection.EnsureHashIndex(ctx, []string{"event_name"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
Unique: true,
|
Unique: true,
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
otpCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.OTP)
|
otpCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.OTP)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if !otpCollectionExists {
|
if !otpCollectionExists {
|
||||||
_, err = arangodb.CreateCollection(ctx, models.Collections.OTP, nil)
|
_, err = arangodb.CreateCollection(ctx, models.Collections.OTP, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -156,7 +226,10 @@ func NewProvider() (*provider, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
otpCollection, _ := arangodb.Collection(nil, models.Collections.OTP)
|
otpCollection, err := arangodb.Collection(ctx, models.Collections.OTP)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
otpCollection.EnsureHashIndex(ctx, []string{"email"}, &arangoDriver.EnsureHashIndexOptions{
|
otpCollection.EnsureHashIndex(ctx, []string{"email"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
Unique: true,
|
Unique: true,
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
|
@@ -7,7 +7,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/arangodb/go-driver"
|
|
||||||
arangoDriver "github.com/arangodb/go-driver"
|
arangoDriver "github.com/arangodb/go-driver"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
@@ -15,6 +14,7 @@ import (
|
|||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddUser to save user information in database
|
// AddUser to save user information in database
|
||||||
@@ -32,6 +32,12 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
|||||||
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||||
@@ -48,6 +54,7 @@ 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 {
|
||||||
@@ -83,7 +90,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) {
|
||||||
var users []*model.User
|
var users []*model.User
|
||||||
sctx := driver.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)
|
||||||
|
|
||||||
@@ -191,7 +198,7 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
|||||||
}
|
}
|
||||||
|
|
||||||
query := ""
|
query := ""
|
||||||
if ids != nil && len(ids) > 0 {
|
if len(ids) > 0 {
|
||||||
keysArray := ""
|
keysArray := ""
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
keysArray += fmt.Sprintf("'%s', ", id)
|
keysArray += fmt.Sprintf("'%s', ", id)
|
||||||
@@ -204,10 +211,40 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, 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
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.User)
|
||||||
|
bindVars := map[string]interface{}{
|
||||||
|
"phone_number": phoneNumber,
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cursor.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if !cursor.HasMore() {
|
||||||
|
if user.Key == "" {
|
||||||
|
return nil, fmt.Errorf("user not found")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_, err := cursor.ReadDocument(ctx, &user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
@@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"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"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@@ -96,7 +96,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
|||||||
// 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 := driver.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)
|
||||||
@@ -112,7 +112,7 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode
|
|||||||
var verificationRequest models.VerificationRequest
|
var verificationRequest models.VerificationRequest
|
||||||
meta, err := cursor.ReadDocument(ctx, &verificationRequest)
|
meta, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||||
|
|
||||||
if driver.IsNoMoreDocuments(err) {
|
if arangoDriver.IsNoMoreDocuments(err) {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -132,8 +132,8 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode
|
|||||||
|
|
||||||
// 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(nil, models.Collections.VerificationRequest)
|
collection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
|
||||||
_, err := collection.RemoveDocument(nil, verificationRequest.Key)
|
_, err := collection.RemoveDocument(ctx, verificationRequest.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ package arangodb
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/arangodb/go-driver"
|
"github.com/arangodb/go-driver"
|
||||||
@@ -18,8 +19,9 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod
|
|||||||
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)
|
||||||
@@ -33,12 +35,15 @@ 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
|
||||||
@@ -50,16 +55,14 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
|||||||
|
|
||||||
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 := driver.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)
|
||||||
@@ -88,13 +91,11 @@ func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model
|
|||||||
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.Key == "" {
|
||||||
@@ -111,32 +112,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
|
||||||
@@ -146,17 +143,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
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"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"
|
||||||
@@ -44,7 +43,7 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sctx := driver.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
|
||||||
|
@@ -161,6 +161,12 @@ func NewProvider() (*provider, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userPhoneNumberIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_user_phone_number ON %s.%s (phone_number)", KeySpace, models.Collections.User)
|
||||||
|
err = session.Query(userPhoneNumberIndexQuery).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
// add is_multi_factor_auth_enabled on users table
|
// add is_multi_factor_auth_enabled on users table
|
||||||
userTableAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD is_multi_factor_auth_enabled boolean`, KeySpace, models.Collections.User)
|
userTableAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD is_multi_factor_auth_enabled boolean`, KeySpace, models.Collections.User)
|
||||||
err = session.Query(userTableAlterQuery).Exec()
|
err = session.Query(userTableAlterQuery).Exec()
|
||||||
@@ -201,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()
|
||||||
|
@@ -12,6 +12,7 @@ import (
|
|||||||
"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/gocql/gocql"
|
"github.com/gocql/gocql"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
@@ -30,6 +31,12 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
|||||||
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
@@ -299,3 +306,14 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user models.User
|
||||||
|
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)
|
||||||
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.CreatedAt, &user.UpdatedAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
@@ -19,29 +19,26 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod
|
|||||||
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 {
|
||||||
@@ -92,24 +84,21 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook models.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
|
||||||
}
|
}
|
||||||
@@ -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) {
|
||||||
var webhook models.Webhook
|
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+"%")
|
||||||
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)
|
scanner := p.db.Query(query).Iter().Scanner()
|
||||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&webhook.ID, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
|
webhooks := []*model.Webhook{}
|
||||||
if err != nil {
|
for scanner.Next() {
|
||||||
return nil, err
|
var webhook models.Webhook
|
||||||
|
err := scanner.Scan(&webhook.ID, &webhook.EventDescription, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||||
}
|
}
|
||||||
return webhook.AsAPIWebhook(), nil
|
return webhooks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWebhook to delete webhook
|
// DeleteWebhook to delete webhook
|
||||||
|
166
server/db/providers/couchbase/email_template.go
Normal file
166
server/db/providers/couchbase/email_template.go
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddEmailTemplate to add EmailTemplate
|
||||||
|
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
|
|
||||||
|
if emailTemplate.ID == "" {
|
||||||
|
emailTemplate.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
emailTemplate.Key = emailTemplate.ID
|
||||||
|
emailTemplate.CreatedAt = time.Now().Unix()
|
||||||
|
emailTemplate.UpdatedAt = time.Now().Unix()
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := p.db.Collection(models.Collections.EmailTemplate).Insert(emailTemplate.ID, emailTemplate, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return emailTemplate.AsAPIEmailTemplate(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEmailTemplate to update EmailTemplate
|
||||||
|
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||||
|
bytes, err := json.Marshal(emailTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
|
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||||
|
decoder.UseNumber()
|
||||||
|
emailTemplateMap := map[string]interface{}{}
|
||||||
|
err = decoder.Decode(&emailTemplateMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFields, params := GetSetFields(emailTemplateMap)
|
||||||
|
params["emailId"] = emailTemplate.ID
|
||||||
|
|
||||||
|
query := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = $emailId", p.scopeName, models.Collections.EmailTemplate, updateFields)
|
||||||
|
|
||||||
|
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEmailTemplates to list EmailTemplate
|
||||||
|
func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) {
|
||||||
|
emailTemplates := []*model.EmailTemplate{}
|
||||||
|
paginationClone := pagination
|
||||||
|
total, err := p.GetTotalDocs(ctx, models.Collections.EmailTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
paginationClone.Total = total
|
||||||
|
userQuery := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s ORDER BY _id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.EmailTemplate)
|
||||||
|
|
||||||
|
queryResult, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{paginationClone.Offset, paginationClone.Limit},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for queryResult.Next() {
|
||||||
|
emailTemplate := models.EmailTemplate{}
|
||||||
|
err := queryResult.Row(&emailTemplate)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := queryResult.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return &model.EmailTemplates{
|
||||||
|
Pagination: &paginationClone,
|
||||||
|
EmailTemplates: emailTemplates,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEmailTemplateByID to get EmailTemplate by id
|
||||||
|
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
||||||
|
emailTemplate := models.EmailTemplate{}
|
||||||
|
|
||||||
|
query := fmt.Sprintf(`SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1`, p.scopeName, models.Collections.EmailTemplate)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{emailTemplateID},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = q.One(&emailTemplate)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
||||||
|
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
||||||
|
emailTemplate := models.EmailTemplate{}
|
||||||
|
|
||||||
|
query := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE event_name=$1 LIMIT 1", p.scopeName, models.Collections.EmailTemplate)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{eventName},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = q.One(&emailTemplate)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteEmailTemplate to delete EmailTemplate
|
||||||
|
func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error {
|
||||||
|
removeOpt := gocb.RemoveOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.EmailTemplate).Remove(emailTemplate.ID, &removeOpt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
package surrealdb
|
package couchbase
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/surrealdb/surrealdb.go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEnv to save environment information in database
|
// AddEnv to save environment information in database
|
||||||
@@ -15,14 +15,15 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro
|
|||||||
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.EncryptionKey = env.Hash
|
||||||
|
|
||||||
mapData := env.ToMap()
|
insertOpt := gocb.InsertOptions{
|
||||||
mapData[models.SurrealDbIdentifier] = env.ID
|
Context: ctx,
|
||||||
|
}
|
||||||
_, err := p.db.Create(models.Collections.Env, mapData)
|
_, err := p.db.Collection(models.Collections.Env).Insert(env.ID, env, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return env, err
|
||||||
}
|
}
|
||||||
@@ -32,14 +33,18 @@ 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()
|
||||||
|
env.EncryptionKey = env.Hash
|
||||||
|
|
||||||
mapData := env.ToMap()
|
updateEnvQuery := fmt.Sprintf("UPDATE %s.%s SET env = $1, updated_at = $2 WHERE _id = $3", p.scopeName, models.Collections.Env)
|
||||||
mapData[models.SurrealDbIdentifier] = env.ID
|
_, err := p.db.Query(updateEnvQuery, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{env.EnvData, env.UpdatedAt, env.UpdatedAt, env.ID},
|
||||||
|
})
|
||||||
|
|
||||||
_, err := p.db.Update(models.Collections.Env, mapData)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return env, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,22 +52,19 @@ func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, e
|
|||||||
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
|
||||||
|
|
||||||
mapData, err := p.db.Select(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{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return env, err
|
||||||
}
|
}
|
||||||
|
err = q.One(&env)
|
||||||
|
|
||||||
envs := []models.Env{}
|
|
||||||
err = surrealdb.Unmarshal(mapData, &envs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return env, err
|
||||||
}
|
}
|
||||||
|
env.Hash = env.EncryptionKey
|
||||||
if len(envs) > 0 {
|
|
||||||
env = envs[0]
|
|
||||||
} else {
|
|
||||||
return env, fmt.Errorf("env record not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
84
server/db/providers/couchbase/otp.go
Normal file
84
server/db/providers/couchbase/otp.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UpsertOTP to add or update otp
|
||||||
|
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
|
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
|
||||||
|
|
||||||
|
shouldCreate := false
|
||||||
|
if otp == nil {
|
||||||
|
shouldCreate = true
|
||||||
|
otp = &models.OTP{
|
||||||
|
ID: uuid.NewString(),
|
||||||
|
Otp: otpParam.Otp,
|
||||||
|
Email: otpParam.Email,
|
||||||
|
ExpiresAt: otpParam.ExpiresAt,
|
||||||
|
CreatedAt: time.Now().Unix(),
|
||||||
|
UpdatedAt: time.Now().Unix(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
otp.Otp = otpParam.Otp
|
||||||
|
otp.ExpiresAt = otpParam.ExpiresAt
|
||||||
|
}
|
||||||
|
|
||||||
|
otp.UpdatedAt = time.Now().Unix()
|
||||||
|
if shouldCreate {
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.OTP).Insert(otp.ID, otp, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return otp, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
query := fmt.Sprintf(`UPDATE %s.%s SET otp=$1, expires_at=$2, updated_at=$3 WHERE _id=$4`, p.scopeName, models.Collections.OTP)
|
||||||
|
_, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
PositionalParameters: []interface{}{otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return otp, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return otp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOTPByEmail to get otp for a given email address
|
||||||
|
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||||
|
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)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{emailAddress},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = q.One(&otp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &otp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteOTP to delete otp
|
||||||
|
func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error {
|
||||||
|
removeOpt := gocb.RemoveOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.OTP).Remove(otp.ID, &removeOpt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
170
server/db/providers/couchbase/provider.go
Normal file
170
server/db/providers/couchbase/provider.go
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultBucketName = "authorizer"
|
||||||
|
defaultScope = "_default"
|
||||||
|
)
|
||||||
|
|
||||||
|
type provider struct {
|
||||||
|
db *gocb.Scope
|
||||||
|
scopeName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProvider returns a new Couchbase provider
|
||||||
|
func NewProvider() (*provider, error) {
|
||||||
|
bucketName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().CouchbaseBucket
|
||||||
|
scopeName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().CouchbaseScope
|
||||||
|
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
||||||
|
userName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseUsername
|
||||||
|
password := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePassword
|
||||||
|
opts := gocb.ClusterOptions{
|
||||||
|
Username: userName,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
if bucketName == "" {
|
||||||
|
bucketName = defaultBucketName
|
||||||
|
}
|
||||||
|
if scopeName == "" {
|
||||||
|
scopeName = defaultScope
|
||||||
|
}
|
||||||
|
cluster, err := gocb.Connect(dbURL, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// To create the bucket and scope if not exist
|
||||||
|
bucket, err := CreateBucketAndScope(cluster, bucketName, scopeName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
scope := bucket.Scope(scopeName)
|
||||||
|
scopeIdentifier := fmt.Sprintf("%s.%s", bucketName, scopeName)
|
||||||
|
v := reflect.ValueOf(models.Collections)
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
collectionName := v.Field(i)
|
||||||
|
user := gocb.CollectionSpec{
|
||||||
|
Name: collectionName.String(),
|
||||||
|
ScopeName: scopeName,
|
||||||
|
}
|
||||||
|
collectionOpts := gocb.CreateCollectionOptions{
|
||||||
|
Context: context.TODO(),
|
||||||
|
}
|
||||||
|
err = bucket.Collections().CreateCollection(user, &collectionOpts)
|
||||||
|
if err != nil && !errors.Is(err, gocb.ErrCollectionExists) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// TODO: find how to fix this sleep time.
|
||||||
|
// Add wait time for successful collection creation
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
indexQuery := fmt.Sprintf("CREATE PRIMARY INDEX ON %s.%s", scopeIdentifier, collectionName.String())
|
||||||
|
_, err = scope.Query(indexQuery, nil)
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "The index #primary already exists") {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
indices := GetIndex(scopeIdentifier)
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
field := v.Field(i)
|
||||||
|
for _, indexQuery := range indices[field.String()] {
|
||||||
|
scope.Query(indexQuery, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &provider{
|
||||||
|
db: scope,
|
||||||
|
scopeName: scopeIdentifier,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateBucketAndScope(cluster *gocb.Cluster, bucketName string, scopeName string) (*gocb.Bucket, error) {
|
||||||
|
bucketRAMQuotaMB := memorystore.RequiredEnvStoreObj.GetRequiredEnv().CouchbaseBucketRAMQuotaMB
|
||||||
|
if bucketRAMQuotaMB == "" {
|
||||||
|
bucketRAMQuotaMB = "1000"
|
||||||
|
}
|
||||||
|
bucketRAMQuota, err := strconv.ParseInt(bucketRAMQuotaMB, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
settings := gocb.BucketSettings{
|
||||||
|
Name: bucketName,
|
||||||
|
RAMQuotaMB: uint64(bucketRAMQuota),
|
||||||
|
BucketType: gocb.CouchbaseBucketType,
|
||||||
|
EvictionPolicy: gocb.EvictionPolicyTypeValueOnly,
|
||||||
|
FlushEnabled: true,
|
||||||
|
CompressionMode: gocb.CompressionModeActive,
|
||||||
|
}
|
||||||
|
shouldCreateBucket := false
|
||||||
|
// check if bucket exists
|
||||||
|
_, err = cluster.Buckets().GetBucket(bucketName, nil)
|
||||||
|
if err != nil {
|
||||||
|
// bucket not found
|
||||||
|
shouldCreateBucket = true
|
||||||
|
}
|
||||||
|
if shouldCreateBucket {
|
||||||
|
err = cluster.Buckets().CreateBucket(gocb.CreateBucketSettings{
|
||||||
|
BucketSettings: settings,
|
||||||
|
ConflictResolutionType: gocb.ConflictResolutionTypeSequenceNumber,
|
||||||
|
}, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bucket := cluster.Bucket(bucketName)
|
||||||
|
if scopeName != defaultScope {
|
||||||
|
err = bucket.Collections().CreateScope(scopeName, nil)
|
||||||
|
if err != nil && !errors.Is(err, gocb.ErrScopeExists) {
|
||||||
|
return bucket, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bucket, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetIndex(scopeName string) map[string][]string {
|
||||||
|
indices := make(map[string][]string)
|
||||||
|
|
||||||
|
// User Index
|
||||||
|
userIndex1 := fmt.Sprintf("CREATE INDEX userEmailIndex ON %s.%s(email)", scopeName, models.Collections.User)
|
||||||
|
userIndex2 := fmt.Sprintf("CREATE INDEX userPhoneIndex ON %s.%s(phone_number)", scopeName, models.Collections.User)
|
||||||
|
indices[models.Collections.User] = []string{userIndex1, userIndex2}
|
||||||
|
|
||||||
|
// VerificationRequest
|
||||||
|
verificationIndex1 := fmt.Sprintf("CREATE INDEX verificationRequestTokenIndex ON %s.%s(token)", scopeName, models.Collections.VerificationRequest)
|
||||||
|
verificationIndex2 := fmt.Sprintf("CREATE INDEX verificationRequestEmailAndIdentifierIndex ON %s.%s(email,identifier)", scopeName, models.Collections.VerificationRequest)
|
||||||
|
indices[models.Collections.VerificationRequest] = []string{verificationIndex1, verificationIndex2}
|
||||||
|
|
||||||
|
// Session index
|
||||||
|
sessionIndex1 := fmt.Sprintf("CREATE INDEX SessionUserIdIndex ON %s.%s(user_id)", scopeName, models.Collections.Session)
|
||||||
|
indices[models.Collections.Session] = []string{sessionIndex1}
|
||||||
|
|
||||||
|
// Webhook index
|
||||||
|
webhookIndex1 := fmt.Sprintf("CREATE INDEX webhookEventNameIndex ON %s.%s(event_name)", scopeName, models.Collections.Webhook)
|
||||||
|
indices[models.Collections.Webhook] = []string{webhookIndex1}
|
||||||
|
|
||||||
|
// WebhookLog index
|
||||||
|
webhookLogIndex1 := fmt.Sprintf("CREATE INDEX webhookLogIdIndex ON %s.%s(webhook_id)", scopeName, models.Collections.WebhookLog)
|
||||||
|
indices[models.Collections.Webhook] = []string{webhookLogIndex1}
|
||||||
|
|
||||||
|
// WebhookLog index
|
||||||
|
emailTempIndex1 := fmt.Sprintf("CREATE INDEX EmailTemplateEventNameIndex ON %s.%s(event_name)", scopeName, models.Collections.EmailTemplate)
|
||||||
|
indices[models.Collections.EmailTemplate] = []string{emailTempIndex1}
|
||||||
|
|
||||||
|
// OTP index
|
||||||
|
otpIndex1 := fmt.Sprintf("CREATE INDEX OTPEmailIndex ON %s.%s(email)", scopeName, models.Collections.OTP)
|
||||||
|
indices[models.Collections.OTP] = []string{otpIndex1}
|
||||||
|
|
||||||
|
return indices
|
||||||
|
}
|
@@ -1,10 +1,11 @@
|
|||||||
package surrealdb
|
package couchbase
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,6 +17,14 @@ func (p *provider) AddSession(ctx context.Context, session models.Session) error
|
|||||||
|
|
||||||
session.CreatedAt = time.Now().Unix()
|
session.CreatedAt = time.Now().Unix()
|
||||||
session.UpdatedAt = time.Now().Unix()
|
session.UpdatedAt = time.Now().Unix()
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.Session).Insert(session.ID, session, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
65
server/db/providers/couchbase/shared.go
Normal file
65
server/db/providers/couchbase/shared.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interface{}) {
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
|
||||||
|
updateFields := ""
|
||||||
|
|
||||||
|
for key, value := range webhookMap {
|
||||||
|
if key == "_id" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == "_key" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if value == nil {
|
||||||
|
updateFields += fmt.Sprintf("%s=$%s,", key, key)
|
||||||
|
params[key] = "null"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
valueType := reflect.TypeOf(value)
|
||||||
|
if valueType.Name() == "string" {
|
||||||
|
updateFields += fmt.Sprintf("%s = $%s, ", key, key)
|
||||||
|
params[key] = value.(string)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
updateFields += fmt.Sprintf("%s = $%s, ", key, key)
|
||||||
|
params[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateFields = strings.Trim(updateFields, " ")
|
||||||
|
updateFields = strings.TrimSuffix(updateFields, ",")
|
||||||
|
return updateFields, params
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetTotalDocs(ctx context.Context, collection string) (int64, error) {
|
||||||
|
totalDocs := TotalDocs{}
|
||||||
|
|
||||||
|
countQuery := fmt.Sprintf("SELECT COUNT(*) as Total FROM %s.%s", p.scopeName, collection)
|
||||||
|
queryRes, err := p.db.Query(countQuery, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
})
|
||||||
|
|
||||||
|
queryRes.One(&totalDocs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return totalDocs.Total, err
|
||||||
|
}
|
||||||
|
return totalDocs.Total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TotalDocs struct {
|
||||||
|
Total int64
|
||||||
|
}
|
199
server/db/providers/couchbase/user.go
Normal file
199
server/db/providers/couchbase/user.go
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddUser to save user information in database
|
||||||
|
func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
|
||||||
|
if user.ID == "" {
|
||||||
|
user.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Roles == "" {
|
||||||
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
user.Roles = defaultRoles
|
||||||
|
}
|
||||||
|
|
||||||
|
user.CreatedAt = time.Now().Unix()
|
||||||
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.User).Insert(user.ID, user, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUser to update user information in database
|
||||||
|
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
||||||
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
unsertOpt := gocb.UpsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &unsertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUser to delete user information from database
|
||||||
|
func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
||||||
|
removeOpt := gocb.RemoveOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.User).Remove(user.ID, &removeOpt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListUsers to get list of users from database
|
||||||
|
func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
|
||||||
|
users := []*model.User{}
|
||||||
|
paginationClone := pagination
|
||||||
|
|
||||||
|
userQuery := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s ORDER BY id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.User)
|
||||||
|
|
||||||
|
queryResult, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{paginationClone.Offset, paginationClone.Limit},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
total, err := p.GetTotalDocs(ctx, models.Collections.User)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
paginationClone.Total = total
|
||||||
|
for queryResult.Next() {
|
||||||
|
var user models.User
|
||||||
|
err := queryResult.Row(&user)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
users = append(users, user.AsAPIUser())
|
||||||
|
}
|
||||||
|
if err := queryResult.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &model.Users{
|
||||||
|
Pagination: &paginationClone,
|
||||||
|
Users: users,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserByEmail to get user information from database using email address
|
||||||
|
func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
|
||||||
|
user := models.User{}
|
||||||
|
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{email},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
err = q.One(&user)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserByID to get user information from database using user ID
|
||||||
|
func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
|
||||||
|
user := models.User{}
|
||||||
|
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{id},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
err = q.One(&user)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
||||||
|
// If ids set to nil / empty all the users will be updated
|
||||||
|
func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error {
|
||||||
|
// set updated_at time for all users
|
||||||
|
data["updated_at"] = time.Now().Unix()
|
||||||
|
updateFields, params := GetSetFields(data)
|
||||||
|
if len(ids) > 0 {
|
||||||
|
for _, id := range ids {
|
||||||
|
params["id"] = id
|
||||||
|
userQuery := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = $id", p.scopeName, models.Collections.User, updateFields)
|
||||||
|
|
||||||
|
_, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
userQuery := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id IS NOT NULL", p.scopeName, models.Collections.User, updateFields)
|
||||||
|
_, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user *models.User
|
||||||
|
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)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{phoneNumber},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
err = q.One(&user)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
128
server/db/providers/couchbase/verification_requests.go
Normal file
128
server/db/providers/couchbase/verification_requests.go
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddVerification to save verification request in database
|
||||||
|
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
|
||||||
|
if verificationRequest.ID == "" {
|
||||||
|
verificationRequest.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
verificationRequest.Key = verificationRequest.ID
|
||||||
|
verificationRequest.CreatedAt = time.Now().Unix()
|
||||||
|
verificationRequest.UpdatedAt = time.Now().Unix()
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.VerificationRequest).Insert(verificationRequest.ID, verificationRequest, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return verificationRequest, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return verificationRequest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVerificationRequestByToken to get verification request from database using token
|
||||||
|
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
|
||||||
|
verificationRequest := models.VerificationRequest{}
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
params["token"] = token
|
||||||
|
query := fmt.Sprintf("SELECT _id, token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE token=$1 LIMIT 1", p.scopeName, models.Collections.VerificationRequest)
|
||||||
|
|
||||||
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{token},
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return verificationRequest, err
|
||||||
|
}
|
||||||
|
err = queryResult.One(&verificationRequest)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return verificationRequest, err
|
||||||
|
}
|
||||||
|
return verificationRequest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVerificationRequestByEmail to get verification request by email from database
|
||||||
|
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
|
||||||
|
|
||||||
|
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{
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{email, identifier},
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
})
|
||||||
|
verificationRequest := models.VerificationRequest{}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return verificationRequest, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = queryResult.One(&verificationRequest)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return verificationRequest, err
|
||||||
|
}
|
||||||
|
return verificationRequest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListVerificationRequests to get list of verification requests from database
|
||||||
|
func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
|
||||||
|
var verificationRequests []*model.VerificationRequest
|
||||||
|
paginationClone := pagination
|
||||||
|
total, err := p.GetTotalDocs(ctx, models.Collections.VerificationRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
paginationClone.Total = total
|
||||||
|
query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM %s.%s OFFSET $1 LIMIT $2", p.scopeName, models.Collections.VerificationRequest)
|
||||||
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{paginationClone.Offset, paginationClone.Limit},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for queryResult.Next() {
|
||||||
|
var verificationRequest models.VerificationRequest
|
||||||
|
err := queryResult.Row(&verificationRequest)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
verificationRequests = append(verificationRequests, verificationRequest.AsAPIVerificationRequest())
|
||||||
|
}
|
||||||
|
if err := queryResult.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
|
||||||
|
}
|
||||||
|
return &model.VerificationRequests{
|
||||||
|
VerificationRequests: verificationRequests,
|
||||||
|
Pagination: &paginationClone,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteVerificationRequest to delete verification request from database
|
||||||
|
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
||||||
|
removeOpt := gocb.RemoveOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.VerificationRequest).Remove(verificationRequest.ID, &removeOpt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
181
server/db/providers/couchbase/webhook.go
Normal file
181
server/db/providers/couchbase/webhook.go
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddWebhook to add webhook
|
||||||
|
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
||||||
|
if webhook.ID == "" {
|
||||||
|
webhook.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
webhook.Key = webhook.ID
|
||||||
|
webhook.CreatedAt = time.Now().Unix()
|
||||||
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
|
// Add timestamp to make event name unique for legacy version
|
||||||
|
webhook.EventName = fmt.Sprintf("%s-%d", webhook.EventName, time.Now().Unix())
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.Webhook).Insert(webhook.ID, webhook, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return webhook.AsAPIWebhook(), err
|
||||||
|
}
|
||||||
|
return webhook.AsAPIWebhook(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateWebhook to update webhook
|
||||||
|
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
||||||
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
|
// Event is changed
|
||||||
|
if !strings.Contains(webhook.EventName, "-") {
|
||||||
|
webhook.EventName = fmt.Sprintf("%s-%d", webhook.EventName, time.Now().Unix())
|
||||||
|
}
|
||||||
|
bytes, err := json.Marshal(webhook)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
|
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||||
|
decoder.UseNumber()
|
||||||
|
webhookMap := map[string]interface{}{}
|
||||||
|
err = decoder.Decode(&webhookMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
updateFields, params := GetSetFields(webhookMap)
|
||||||
|
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{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return webhook.AsAPIWebhook(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListWebhooks to list webhook
|
||||||
|
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
|
||||||
|
webhooks := []*model.Webhook{}
|
||||||
|
paginationClone := pagination
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
params["offset"] = paginationClone.Offset
|
||||||
|
params["limit"] = paginationClone.Limit
|
||||||
|
total, err := p.GetTotalDocs(ctx, models.Collections.Webhook)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
paginationClone.Total = total
|
||||||
|
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{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for queryResult.Next() {
|
||||||
|
var webhook models.Webhook
|
||||||
|
err := queryResult.Row(&webhook)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||||
|
}
|
||||||
|
if err := queryResult.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &model.Webhooks{
|
||||||
|
Pagination: &paginationClone,
|
||||||
|
Webhooks: webhooks,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWebhookByID to get webhook by id
|
||||||
|
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
||||||
|
var webhook models.Webhook
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
params["_id"] = webhookID
|
||||||
|
query := fmt.Sprintf(`SELECT _id, event_description, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s.%s WHERE _id=$_id LIMIT 1`, p.scopeName, models.Collections.Webhook)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = q.One(&webhook)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return webhook.AsAPIWebhook(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWebhookByEventName to get webhook by event_name
|
||||||
|
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*model.Webhook, error) {
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
// 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+"%")
|
||||||
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
webhooks := []*model.Webhook{}
|
||||||
|
for queryResult.Next() {
|
||||||
|
var webhook models.Webhook
|
||||||
|
err := queryResult.Row(&webhook)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||||
|
}
|
||||||
|
if err := queryResult.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return webhooks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteWebhook to delete webhook
|
||||||
|
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
params["webhook_id"] = webhook.ID
|
||||||
|
removeOpt := gocb.RemoveOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.Webhook).Remove(webhook.ID, &removeOpt)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := fmt.Sprintf(`DELETE FROM %s.%s WHERE webhook_id=$webhook_id`, p.scopeName, models.Collections.WebhookLog)
|
||||||
|
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
85
server/db/providers/couchbase/webhook_log.go
Normal file
85
server/db/providers/couchbase/webhook_log.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddWebhookLog to add webhook log
|
||||||
|
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
|
||||||
|
if webhookLog.ID == "" {
|
||||||
|
webhookLog.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
webhookLog.Key = webhookLog.ID
|
||||||
|
webhookLog.CreatedAt = time.Now().Unix()
|
||||||
|
webhookLog.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.WebhookLog).Insert(webhookLog.ID, webhookLog, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return webhookLog.AsAPIWebhookLog(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
return webhookLog.AsAPIWebhookLog(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListWebhookLogs to list webhook logs
|
||||||
|
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
|
||||||
|
var query string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
webhookLogs := []*model.WebhookLog{}
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
paginationClone := pagination
|
||||||
|
|
||||||
|
params["webhookID"] = webhookID
|
||||||
|
params["offset"] = paginationClone.Offset
|
||||||
|
params["limit"] = paginationClone.Limit
|
||||||
|
total, err := p.GetTotalDocs(ctx, models.Collections.WebhookLog)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
paginationClone.Total = total
|
||||||
|
if webhookID != "" {
|
||||||
|
query = fmt.Sprintf(`SELECT _id, http_status, response, request, webhook_id, created_at, updated_at FROM %s.%s WHERE webhook_id=$webhookID`, p.scopeName, models.Collections.WebhookLog)
|
||||||
|
} else {
|
||||||
|
query = fmt.Sprintf("SELECT _id, http_status, response, request, webhook_id, created_at, updated_at FROM %s.%s OFFSET $offset LIMIT $limit", p.scopeName, models.Collections.WebhookLog)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for queryResult.Next() {
|
||||||
|
var webhookLog models.WebhookLog
|
||||||
|
err := queryResult.Row(&webhookLog)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := queryResult.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
|
||||||
|
}
|
||||||
|
return &model.WebhookLogs{
|
||||||
|
Pagination: &paginationClone,
|
||||||
|
WebhookLogs: webhookLogs,
|
||||||
|
}, nil
|
||||||
|
}
|
@@ -34,7 +34,6 @@ 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) {
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.Env)
|
collection := p.db.Table(models.Collections.Env)
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
@@ -3,12 +3,15 @@ package dynamodb
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"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/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/guregu/dynamo"
|
"github.com/guregu/dynamo"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -30,6 +33,12 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
|||||||
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 {
|
||||||
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
@@ -193,3 +202,23 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var users []models.User
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
collection := p.db.Table(models.Collections.User)
|
||||||
|
err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).AllWithContext(ctx, &users)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(users) > 0 {
|
||||||
|
user = users[0]
|
||||||
|
return &user, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("no record found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
@@ -33,11 +34,13 @@ 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
|
||||||
}
|
}
|
||||||
@@ -51,16 +54,13 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
|||||||
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,9 +75,7 @@ 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,
|
||||||
@@ -88,37 +86,29 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
|||||||
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 webhook.AsAPIWebhook(), 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
|
||||||
@@ -133,7 +123,6 @@ func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) er
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
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 {
|
||||||
|
@@ -155,3 +155,16 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||||
|
err := userCollection.FindOne(ctx, bson.M{"phone_number": phoneNumber}).Decode(&user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
@@ -2,6 +2,8 @@ package mongodb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
@@ -16,11 +18,11 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod
|
|||||||
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())
|
||||||
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
||||||
_, err := webhookCollection.InsertOne(ctx, webhook)
|
_, err := webhookCollection.InsertOne(ctx, webhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -32,39 +34,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(models.Collections.Webhook, options.Collection())
|
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
||||||
_, err := webhookCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": webhook.ID}}, bson.M{"$set": webhook}, options.MergeUpdateOptions())
|
_, err := webhookCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": webhook.ID}}, bson.M{"$set": webhook}, options.MergeUpdateOptions())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
var webhooks []*model.Webhook
|
webhooks := []*model.Webhook{}
|
||||||
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
|
||||||
|
|
||||||
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
||||||
count, err := webhookCollection.CountDocuments(ctx, bson.M{}, options.Count())
|
count, err := webhookCollection.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 := webhookCollection.Find(ctx, bson.M{}, opts)
|
cursor, err := webhookCollection.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 webhook models.Webhook
|
var webhook models.Webhook
|
||||||
err := cursor.Decode(&webhook)
|
err := cursor.Decode(&webhook)
|
||||||
@@ -73,7 +73,6 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
|||||||
}
|
}
|
||||||
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.Webhooks{
|
return &model.Webhooks{
|
||||||
Pagination: &paginationClone,
|
Pagination: &paginationClone,
|
||||||
Webhooks: webhooks,
|
Webhooks: webhooks,
|
||||||
@@ -92,14 +91,27 @@ 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
|
webhooks := []*model.Webhook{}
|
||||||
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
|
||||||
err := webhookCollection.FindOne(ctx, bson.M{"event_name": eventName}).Decode(&webhook)
|
opts := options.Find()
|
||||||
|
opts.SetSort(bson.M{"created_at": -1})
|
||||||
|
cursor, err := webhookCollection.Find(ctx, bson.M{"event_name": bson.M{
|
||||||
|
"$regex": fmt.Sprintf("^%s", eventName),
|
||||||
|
}}, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return webhook.AsAPIWebhook(), nil
|
defer cursor.Close(ctx)
|
||||||
|
for cursor.Next(ctx) {
|
||||||
|
var webhook models.Webhook
|
||||||
|
err := cursor.Decode(&webhook)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||||
|
}
|
||||||
|
return webhooks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWebhook to delete webhook
|
// DeleteWebhook to delete webhook
|
||||||
@@ -109,12 +121,10 @@ func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
webhookLogCollection := p.db.Collection(models.Collections.WebhookLog, options.Collection())
|
webhookLogCollection := p.db.Collection(models.Collections.WebhookLog, options.Collection())
|
||||||
_, err = webhookLogCollection.DeleteMany(nil, bson.M{"webhook_id": webhook.ID}, options.Delete())
|
_, err = webhookLogCollection.DeleteMany(nil, bson.M{"webhook_id": webhook.ID}, options.Delete())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -69,3 +69,10 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user *models.User
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
@@ -2,6 +2,8 @@ package provider_template
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
@@ -14,16 +16,21 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod
|
|||||||
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())
|
||||||
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())
|
||||||
|
}
|
||||||
return webhook.AsAPIWebhook(), nil
|
return webhook.AsAPIWebhook(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +45,7 @@ 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) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,6 +18,8 @@ type Provider interface {
|
|||||||
ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error)
|
ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error)
|
||||||
// GetUserByEmail to get user information from database using email address
|
// GetUserByEmail to get user information from database using email address
|
||||||
GetUserByEmail(ctx context.Context, email string) (models.User, error)
|
GetUserByEmail(ctx context.Context, email string) (models.User, error)
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error)
|
||||||
// GetUserByID to get user information from database using user ID
|
// GetUserByID to get user information from database using user ID
|
||||||
GetUserByID(ctx context.Context, id string) (models.User, error)
|
GetUserByID(ctx context.Context, id string) (models.User, error)
|
||||||
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
||||||
@@ -54,7 +56,7 @@ type Provider interface {
|
|||||||
// GetWebhookByID to get webhook by id
|
// GetWebhookByID to get webhook by id
|
||||||
GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error)
|
GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error)
|
||||||
// GetWebhookByEventName to get webhook by event_name
|
// GetWebhookByEventName to get webhook by event_name
|
||||||
GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error)
|
GetWebhookByEventName(ctx context.Context, eventName string) ([]*model.Webhook, error)
|
||||||
// DeleteWebhook to delete webhook
|
// DeleteWebhook to delete webhook
|
||||||
DeleteWebhook(ctx context.Context, webhook *model.Webhook) error
|
DeleteWebhook(ctx context.Context, webhook *model.Webhook) error
|
||||||
|
|
||||||
|
@@ -31,7 +31,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
if u, _ := p.GetUserByPhone(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
||||||
return user, fmt.Errorf("user with given phone number already exists")
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,12 +56,6 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
|||||||
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()
|
||||||
|
|
||||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
|
||||||
if u, _ := p.GetUserByPhone(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
|
||||||
return user, fmt.Errorf("user with given phone number already exists")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result := p.db.Save(&user)
|
result := p.db.Save(&user)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
@@ -73,13 +67,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 {
|
||||||
result := p.db.Delete(&user)
|
result := p.db.Where("user_id = ?", user.ID).Delete(&models.Session{})
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
result = p.db.Where("user_id = ?", user.ID).Delete(&models.Session{})
|
result = p.db.Delete(&user)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
@@ -157,12 +150,13 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) GetUserByPhone(ctx context.Context, phoneNumber string) (*models.User, error) {
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
var user *models.User
|
var user *models.User
|
||||||
result := p.db.Where("phone_number = ?", phoneNumber).First(&user)
|
result := p.db.Where("phone_number = ?", phoneNumber).First(&user)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return user, result.Error
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
|
@@ -2,6 +2,8 @@ package sql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
@@ -14,10 +16,11 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod
|
|||||||
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())
|
||||||
res := p.db.Create(&webhook)
|
res := p.db.Create(&webhook)
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
return nil, res.Error
|
return nil, res.Error
|
||||||
@@ -28,33 +31,31 @@ 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())
|
||||||
|
}
|
||||||
result := p.db.Save(&webhook)
|
result := p.db.Save(&webhook)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return nil, result.Error
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
var webhooks []models.Webhook
|
var webhooks []models.Webhook
|
||||||
|
|
||||||
result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&webhooks)
|
result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&webhooks)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return nil, result.Error
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
var total int64
|
var total int64
|
||||||
totalRes := p.db.Model(&models.Webhook{}).Count(&total)
|
totalRes := p.db.Model(&models.Webhook{}).Count(&total)
|
||||||
if totalRes.Error != nil {
|
if totalRes.Error != nil {
|
||||||
return nil, totalRes.Error
|
return nil, totalRes.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
paginationClone.Total = total
|
paginationClone.Total = total
|
||||||
|
|
||||||
responseWebhooks := []*model.Webhook{}
|
responseWebhooks := []*model.Webhook{}
|
||||||
for _, w := range webhooks {
|
for _, w := range webhooks {
|
||||||
responseWebhooks = append(responseWebhooks, w.AsAPIWebhook())
|
responseWebhooks = append(responseWebhooks, w.AsAPIWebhook())
|
||||||
@@ -77,14 +78,17 @@ 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
|
var webhooks []models.Webhook
|
||||||
|
result := p.db.Where("event_name LIKE ?", eventName+"%").Find(&webhooks)
|
||||||
result := p.db.Where("event_name = ?", eventName).First(&webhook)
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return nil, result.Error
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
return webhook.AsAPIWebhook(), nil
|
responseWebhooks := []*model.Webhook{}
|
||||||
|
for _, w := range webhooks {
|
||||||
|
responseWebhooks = append(responseWebhooks, w.AsAPIWebhook())
|
||||||
|
}
|
||||||
|
return responseWebhooks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWebhook to delete webhook
|
// DeleteWebhook to delete webhook
|
||||||
|
@@ -1,48 +0,0 @@
|
|||||||
package surrealdb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddEmailTemplate to add EmailTemplate
|
|
||||||
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
|
||||||
if emailTemplate.ID == "" {
|
|
||||||
emailTemplate.ID = uuid.New().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
emailTemplate.Key = emailTemplate.ID
|
|
||||||
emailTemplate.CreatedAt = time.Now().Unix()
|
|
||||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
|
||||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateEmailTemplate to update EmailTemplate
|
|
||||||
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
|
||||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
|
||||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListEmailTemplates to list EmailTemplate
|
|
||||||
func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetEmailTemplateByID to get EmailTemplate by id
|
|
||||||
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
|
||||||
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteEmailTemplate to delete EmailTemplate
|
|
||||||
func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
@@ -1,22 +0,0 @@
|
|||||||
package surrealdb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpsertOTP to add or update otp
|
|
||||||
func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOTPByEmail to get otp for a given email address
|
|
||||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteOTP to delete otp
|
|
||||||
func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
@@ -1,42 +0,0 @@
|
|||||||
package surrealdb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
|
||||||
"github.com/surrealdb/surrealdb.go"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO change following provider to new db provider
|
|
||||||
type provider struct {
|
|
||||||
db *surrealdb.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewProvider returns a new SQL provider
|
|
||||||
// TODO change following provider to new db provider
|
|
||||||
func NewProvider() (*provider, error) {
|
|
||||||
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
|
||||||
db, err := surrealdb.New(dbURL)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
dbUsername := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseUsername
|
|
||||||
dbPassword := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePassword
|
|
||||||
|
|
||||||
_, err = db.Signin(map[string]interface{}{
|
|
||||||
"user": dbUsername,
|
|
||||||
"pass": dbPassword,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = db.Use(models.DBNamespace, models.DBNamespace)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &provider{
|
|
||||||
db: db,
|
|
||||||
}, nil
|
|
||||||
}
|
|
@@ -1,71 +0,0 @@
|
|||||||
package surrealdb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddUser to save user information in database
|
|
||||||
func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
|
|
||||||
if user.ID == "" {
|
|
||||||
user.ID = uuid.New().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.Roles == "" {
|
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
|
||||||
if err != nil {
|
|
||||||
return user, err
|
|
||||||
}
|
|
||||||
user.Roles = defaultRoles
|
|
||||||
}
|
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
|
||||||
user.UpdatedAt = time.Now().Unix()
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateUser to update user information in database
|
|
||||||
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
|
||||||
user.UpdatedAt = time.Now().Unix()
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteUser to delete user information from database
|
|
||||||
func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListUsers to get list of users from database
|
|
||||||
func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserByEmail to get user information from database using email address
|
|
||||||
func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
|
|
||||||
var user models.User
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserByID to get user information from database using user ID
|
|
||||||
func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
|
|
||||||
var user models.User
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
|
||||||
// If ids set to nil / empty all the users will be updated
|
|
||||||
func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error {
|
|
||||||
// set updated_at time for all users
|
|
||||||
data["updated_at"] = time.Now().Unix()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@@ -1,46 +0,0 @@
|
|||||||
package surrealdb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddVerification to save verification request in database
|
|
||||||
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
|
|
||||||
if verificationRequest.ID == "" {
|
|
||||||
verificationRequest.ID = uuid.New().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
verificationRequest.CreatedAt = time.Now().Unix()
|
|
||||||
verificationRequest.UpdatedAt = time.Now().Unix()
|
|
||||||
|
|
||||||
return verificationRequest, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetVerificationRequestByToken to get verification request from database using token
|
|
||||||
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
|
|
||||||
var verificationRequest models.VerificationRequest
|
|
||||||
|
|
||||||
return verificationRequest, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetVerificationRequestByEmail to get verification request by email from database
|
|
||||||
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
|
|
||||||
var verificationRequest models.VerificationRequest
|
|
||||||
|
|
||||||
return verificationRequest, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListVerificationRequests to get list of verification requests from database
|
|
||||||
func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteVerificationRequest to delete verification request from database
|
|
||||||
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
@@ -1,49 +0,0 @@
|
|||||||
package surrealdb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddWebhook to add webhook
|
|
||||||
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
|
||||||
if webhook.ID == "" {
|
|
||||||
webhook.ID = uuid.New().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
webhook.Key = webhook.ID
|
|
||||||
webhook.CreatedAt = time.Now().Unix()
|
|
||||||
webhook.UpdatedAt = time.Now().Unix()
|
|
||||||
return webhook.AsAPIWebhook(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateWebhook to update webhook
|
|
||||||
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
|
||||||
webhook.UpdatedAt = time.Now().Unix()
|
|
||||||
return webhook.AsAPIWebhook(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListWebhooks to list webhook
|
|
||||||
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWebhookByID to get webhook by id
|
|
||||||
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWebhookByEventName to get webhook by event_name
|
|
||||||
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteWebhook to delete webhook
|
|
||||||
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
|
||||||
// Also delete webhook logs for given webhook id
|
|
||||||
return nil
|
|
||||||
}
|
|
@@ -1,27 +0,0 @@
|
|||||||
package surrealdb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddWebhookLog to add webhook log
|
|
||||||
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
|
|
||||||
if webhookLog.ID == "" {
|
|
||||||
webhookLog.ID = uuid.New().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
webhookLog.Key = webhookLog.ID
|
|
||||||
webhookLog.CreatedAt = time.Now().Unix()
|
|
||||||
webhookLog.UpdatedAt = time.Now().Unix()
|
|
||||||
return webhookLog.AsAPIWebhookLog(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListWebhookLogs to list webhook logs
|
|
||||||
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
90
server/env/env.go
vendored
90
server/env/env.go
vendored
@@ -75,17 +75,26 @@ func InitAllEnv() error {
|
|||||||
osAppleClientSecret := os.Getenv(constants.EnvKeyAppleClientSecret)
|
osAppleClientSecret := os.Getenv(constants.EnvKeyAppleClientSecret)
|
||||||
osTwitterClientID := os.Getenv(constants.EnvKeyTwitterClientID)
|
osTwitterClientID := os.Getenv(constants.EnvKeyTwitterClientID)
|
||||||
osTwitterClientSecret := os.Getenv(constants.EnvKeyTwitterClientSecret)
|
osTwitterClientSecret := os.Getenv(constants.EnvKeyTwitterClientSecret)
|
||||||
|
osMicrosoftClientID := os.Getenv(constants.EnvKeyMicrosoftClientID)
|
||||||
|
osMicrosoftClientSecret := os.Getenv(constants.EnvKeyMicrosoftClientSecret)
|
||||||
|
osMicrosoftActiveDirectoryTenantID := os.Getenv(constants.EnvKeyMicrosoftActiveDirectoryTenantID)
|
||||||
osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL)
|
osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL)
|
||||||
osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName)
|
osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName)
|
||||||
osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo)
|
osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo)
|
||||||
osAwsRegion := os.Getenv(constants.EnvAwsRegion)
|
osAwsRegion := os.Getenv(constants.EnvAwsRegion)
|
||||||
osAwsAccessKey := os.Getenv(constants.EnvAwsAccessKeyID)
|
osAwsAccessKey := os.Getenv(constants.EnvAwsAccessKeyID)
|
||||||
osAwsSecretKey := os.Getenv(constants.EnvAwsSecretAccessKey)
|
osAwsSecretKey := os.Getenv(constants.EnvAwsSecretAccessKey)
|
||||||
|
osCouchbaseBucket := os.Getenv(constants.EnvCouchbaseBucket)
|
||||||
|
osCouchbaseScope := os.Getenv(constants.EnvCouchbaseScope)
|
||||||
|
osCouchbaseBucketRAMQuotaMB := os.Getenv(constants.EnvCouchbaseBucketRAMQuotaMB)
|
||||||
|
osAuthorizeResponseType := os.Getenv(constants.EnvKeyDefaultAuthorizeResponseType)
|
||||||
|
osAuthorizeResponseMode := os.Getenv(constants.EnvKeyDefaultAuthorizeResponseMode)
|
||||||
|
|
||||||
// os bool vars
|
// os bool vars
|
||||||
osAppCookieSecure := os.Getenv(constants.EnvKeyAppCookieSecure)
|
osAppCookieSecure := os.Getenv(constants.EnvKeyAppCookieSecure)
|
||||||
osAdminCookieSecure := os.Getenv(constants.EnvKeyAdminCookieSecure)
|
osAdminCookieSecure := os.Getenv(constants.EnvKeyAdminCookieSecure)
|
||||||
osDisableBasicAuthentication := os.Getenv(constants.EnvKeyDisableBasicAuthentication)
|
osDisableBasicAuthentication := os.Getenv(constants.EnvKeyDisableBasicAuthentication)
|
||||||
|
osDisableMobileBasicAuthentication := os.Getenv(constants.AuthRecipeMethodMobileBasicAuth)
|
||||||
osDisableEmailVerification := os.Getenv(constants.EnvKeyDisableEmailVerification)
|
osDisableEmailVerification := os.Getenv(constants.EnvKeyDisableEmailVerification)
|
||||||
osDisableMagicLinkLogin := os.Getenv(constants.EnvKeyDisableMagicLinkLogin)
|
osDisableMagicLinkLogin := os.Getenv(constants.EnvKeyDisableMagicLinkLogin)
|
||||||
osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage)
|
osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage)
|
||||||
@@ -133,17 +142,38 @@ func InitAllEnv() error {
|
|||||||
if val, ok := envData[constants.EnvAwsAccessKeyID]; !ok || val == "" {
|
if val, ok := envData[constants.EnvAwsAccessKeyID]; !ok || val == "" {
|
||||||
envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey
|
envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey
|
||||||
}
|
}
|
||||||
if osAwsAccessKey != "" && envData[constants.EnvAwsAccessKeyID] != osAwsRegion {
|
if osAwsAccessKey != "" && envData[constants.EnvAwsAccessKeyID] != osAwsAccessKey {
|
||||||
envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey
|
envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, ok := envData[constants.EnvAwsSecretAccessKey]; !ok || val == "" {
|
if val, ok := envData[constants.EnvAwsSecretAccessKey]; !ok || val == "" {
|
||||||
envData[constants.EnvAwsSecretAccessKey] = osAwsSecretKey
|
envData[constants.EnvAwsSecretAccessKey] = osAwsSecretKey
|
||||||
}
|
}
|
||||||
if osAwsSecretKey != "" && envData[constants.EnvAwsSecretAccessKey] != osAwsRegion {
|
if osAwsSecretKey != "" && envData[constants.EnvAwsSecretAccessKey] != osAwsSecretKey {
|
||||||
envData[constants.EnvAwsSecretAccessKey] = osAwsSecretKey
|
envData[constants.EnvAwsSecretAccessKey] = osAwsSecretKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvCouchbaseBucket]; !ok || val == "" {
|
||||||
|
envData[constants.EnvCouchbaseBucket] = osCouchbaseBucket
|
||||||
|
}
|
||||||
|
if osCouchbaseBucket != "" && envData[constants.EnvCouchbaseBucket] != osCouchbaseBucket {
|
||||||
|
envData[constants.EnvCouchbaseBucket] = osCouchbaseBucket
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvCouchbaseBucketRAMQuotaMB]; !ok || val == "" {
|
||||||
|
envData[constants.EnvCouchbaseBucketRAMQuotaMB] = osCouchbaseBucketRAMQuotaMB
|
||||||
|
}
|
||||||
|
if osCouchbaseBucketRAMQuotaMB != "" && envData[constants.EnvCouchbaseBucketRAMQuotaMB] != osCouchbaseBucketRAMQuotaMB {
|
||||||
|
envData[constants.EnvCouchbaseBucketRAMQuotaMB] = osCouchbaseBucketRAMQuotaMB
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvCouchbaseScope]; !ok || val == "" {
|
||||||
|
envData[constants.EnvCouchbaseScope] = osCouchbaseScope
|
||||||
|
}
|
||||||
|
if osCouchbaseScope != "" && envData[constants.EnvCouchbaseScope] != osCouchbaseScope {
|
||||||
|
envData[constants.EnvCouchbaseScope] = osCouchbaseScope
|
||||||
|
}
|
||||||
|
|
||||||
if val, ok := envData[constants.EnvKeyAppURL]; !ok || val == "" {
|
if val, ok := envData[constants.EnvKeyAppURL]; !ok || val == "" {
|
||||||
envData[constants.EnvKeyAppURL] = osAppURL
|
envData[constants.EnvKeyAppURL] = osAppURL
|
||||||
}
|
}
|
||||||
@@ -430,6 +460,27 @@ func InitAllEnv() error {
|
|||||||
envData[constants.EnvKeyTwitterClientSecret] = osTwitterClientSecret
|
envData[constants.EnvKeyTwitterClientSecret] = osTwitterClientSecret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyMicrosoftClientID]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyMicrosoftClientID] = osMicrosoftClientID
|
||||||
|
}
|
||||||
|
if osMicrosoftClientID != "" && envData[constants.EnvKeyMicrosoftClientID] != osMicrosoftClientID {
|
||||||
|
envData[constants.EnvKeyMicrosoftClientID] = osMicrosoftClientID
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyMicrosoftClientSecret]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyMicrosoftClientSecret] = osMicrosoftClientSecret
|
||||||
|
}
|
||||||
|
if osMicrosoftClientSecret != "" && envData[constants.EnvKeyMicrosoftClientSecret] != osMicrosoftClientSecret {
|
||||||
|
envData[constants.EnvKeyMicrosoftClientSecret] = osMicrosoftClientSecret
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyMicrosoftActiveDirectoryTenantID]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyMicrosoftActiveDirectoryTenantID] = osMicrosoftActiveDirectoryTenantID
|
||||||
|
}
|
||||||
|
if osMicrosoftActiveDirectoryTenantID != "" && envData[constants.EnvKeyMicrosoftActiveDirectoryTenantID] != osMicrosoftActiveDirectoryTenantID {
|
||||||
|
envData[constants.EnvKeyMicrosoftActiveDirectoryTenantID] = osMicrosoftActiveDirectoryTenantID
|
||||||
|
}
|
||||||
|
|
||||||
if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" {
|
if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" {
|
||||||
envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/")
|
envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/")
|
||||||
}
|
}
|
||||||
@@ -498,6 +549,19 @@ func InitAllEnv() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, ok := envData[constants.EnvKeyDisableMobileBasicAuthentication]; !ok {
|
||||||
|
envData[constants.EnvKeyDisableMobileBasicAuthentication] = osDisableBasicAuthentication == "true"
|
||||||
|
}
|
||||||
|
if osDisableMobileBasicAuthentication != "" {
|
||||||
|
boolValue, err := strconv.ParseBool(osDisableMobileBasicAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if boolValue != envData[constants.EnvKeyDisableMobileBasicAuthentication].(bool) {
|
||||||
|
envData[constants.EnvKeyDisableMobileBasicAuthentication] = boolValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if _, ok := envData[constants.EnvKeyDisableEmailVerification]; !ok {
|
if _, ok := envData[constants.EnvKeyDisableEmailVerification]; !ok {
|
||||||
envData[constants.EnvKeyDisableEmailVerification] = osDisableEmailVerification == "true"
|
envData[constants.EnvKeyDisableEmailVerification] = osDisableEmailVerification == "true"
|
||||||
}
|
}
|
||||||
@@ -673,6 +737,28 @@ func InitAllEnv() error {
|
|||||||
envData[constants.EnvKeyProtectedRoles] = osProtectedRoles
|
envData[constants.EnvKeyProtectedRoles] = osProtectedRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyDefaultAuthorizeResponseType]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyDefaultAuthorizeResponseType] = osAuthorizeResponseType
|
||||||
|
// Set the default value to token type
|
||||||
|
if envData[constants.EnvKeyDefaultAuthorizeResponseType] == "" {
|
||||||
|
envData[constants.EnvKeyDefaultAuthorizeResponseType] = constants.ResponseTypeToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if osAuthorizeResponseType != "" && envData[constants.EnvKeyDefaultAuthorizeResponseType] != osAuthorizeResponseType {
|
||||||
|
envData[constants.EnvKeyDefaultAuthorizeResponseType] = osAuthorizeResponseType
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyDefaultAuthorizeResponseMode]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyDefaultAuthorizeResponseMode] = osAuthorizeResponseMode
|
||||||
|
// Set the default value to token type
|
||||||
|
if envData[constants.EnvKeyDefaultAuthorizeResponseMode] == "" {
|
||||||
|
envData[constants.EnvKeyDefaultAuthorizeResponseMode] = constants.ResponseModeQuery
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if osAuthorizeResponseMode != "" && envData[constants.EnvKeyDefaultAuthorizeResponseMode] != osAuthorizeResponseMode {
|
||||||
|
envData[constants.EnvKeyDefaultAuthorizeResponseMode] = osAuthorizeResponseMode
|
||||||
|
}
|
||||||
|
|
||||||
err = memorystore.Provider.UpdateEnvStore(envData)
|
err = memorystore.Provider.UpdateEnvStore(envData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error while updating env store: ", err)
|
log.Debug("Error while updating env store: ", err)
|
||||||
|
3
server/env/persist_env.go
vendored
3
server/env/persist_env.go
vendored
@@ -75,7 +75,6 @@ func GetEnvData() (map[string]interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
|
||||||
|
|
||||||
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
|
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error while decrypting env data from B64: ", err)
|
log.Debug("Error while decrypting env data from B64: ", err)
|
||||||
@@ -201,7 +200,7 @@ func PersistEnv() error {
|
|||||||
envValue := strings.TrimSpace(os.Getenv(key))
|
envValue := strings.TrimSpace(os.Getenv(key))
|
||||||
if envValue != "" {
|
if envValue != "" {
|
||||||
switch key {
|
switch key {
|
||||||
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure:
|
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure:
|
||||||
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
||||||
if value.(bool) != envValueBool {
|
if value.(bool) != envValueBool {
|
||||||
storeData[key] = envValueBool
|
storeData[key] = envValueBool
|
||||||
|
@@ -4,45 +4,38 @@ go 1.16
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/99designs/gqlgen v0.17.20
|
github.com/99designs/gqlgen v0.17.20
|
||||||
github.com/arangodb/go-driver v1.4.0
|
github.com/arangodb/go-driver v1.2.1
|
||||||
github.com/aws/aws-sdk-go v1.44.145
|
github.com/aws/aws-sdk-go v1.44.109
|
||||||
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
|
github.com/coreos/go-oidc/v3 v3.1.0
|
||||||
github.com/coreos/go-oidc/v3 v3.4.0
|
github.com/couchbase/gocb/v2 v2.6.0
|
||||||
github.com/gin-gonic/gin v1.8.1
|
github.com/gin-gonic/gin v1.8.1
|
||||||
github.com/glebarez/go-sqlite v1.19.5 // indirect
|
|
||||||
github.com/glebarez/sqlite v1.5.0
|
github.com/glebarez/sqlite v1.5.0
|
||||||
github.com/go-playground/validator/v10 v10.11.1 // indirect
|
github.com/go-playground/validator/v10 v10.11.1 // indirect
|
||||||
github.com/go-redis/redis/v8 v8.11.5
|
|
||||||
github.com/goccy/go-json v0.9.11 // indirect
|
github.com/goccy/go-json v0.9.11 // indirect
|
||||||
github.com/gocql/gocql v1.2.1
|
github.com/gocql/gocql v1.2.0
|
||||||
github.com/gofrs/uuid v4.3.1+incompatible // indirect
|
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/google/go-cmp v0.5.6 // indirect
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/guregu/dynamo v1.17.0
|
github.com/guregu/dynamo v1.16.0
|
||||||
github.com/joho/godotenv v1.4.0
|
github.com/joho/godotenv v1.3.0
|
||||||
github.com/klauspost/compress v1.15.12 // indirect
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20220927061507-ef77025ab5aa // indirect
|
github.com/redis/go-redis/v9 v9.0.3
|
||||||
github.com/robertkrimen/otto v0.0.0-20221126133309-a3b51c68f2a4
|
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f
|
||||||
github.com/sirupsen/logrus v1.9.0
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.0
|
||||||
github.com/surrealdb/surrealdb.go v0.1.2-0.20221019092700-845266102715
|
|
||||||
github.com/urfave/cli/v2 v2.23.5 // indirect
|
|
||||||
github.com/vektah/gqlparser/v2 v2.5.1
|
github.com/vektah/gqlparser/v2 v2.5.1
|
||||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
|
go.mongodb.org/mongo-driver v1.8.1
|
||||||
go.mongodb.org/mongo-driver v1.11.0
|
golang.org/x/crypto v0.4.0
|
||||||
golang.org/x/crypto v0.3.0
|
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
||||||
golang.org/x/oauth2 v0.2.0
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
golang.org/x/tools v0.3.0 // indirect
|
|
||||||
google.golang.org/protobuf v1.28.1 // indirect
|
google.golang.org/protobuf v1.28.1 // indirect
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/mail.v2 v2.3.1
|
gopkg.in/mail.v2 v2.3.1
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0
|
gopkg.in/square/go-jose.v2 v2.6.0
|
||||||
gorm.io/driver/mysql v1.4.4
|
gorm.io/driver/mysql v1.4.3
|
||||||
gorm.io/driver/postgres v1.4.5
|
gorm.io/driver/postgres v1.4.7
|
||||||
gorm.io/driver/sqlserver v1.4.1
|
gorm.io/driver/sqlserver v1.4.1
|
||||||
gorm.io/gorm v1.24.2
|
gorm.io/gorm v1.24.2
|
||||||
)
|
)
|
||||||
|
576
server/go.sum
576
server/go.sum
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -10,10 +10,11 @@ type AddEmailTemplateRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AddWebhookRequest struct {
|
type AddWebhookRequest struct {
|
||||||
EventName string `json:"event_name"`
|
EventName string `json:"event_name"`
|
||||||
Endpoint string `json:"endpoint"`
|
EventDescription *string `json:"event_description"`
|
||||||
Enabled bool `json:"enabled"`
|
Endpoint string `json:"endpoint"`
|
||||||
Headers map[string]interface{} `json:"headers"`
|
Enabled bool `json:"enabled"`
|
||||||
|
Headers map[string]interface{} `json:"headers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AdminLoginInput struct {
|
type AdminLoginInput struct {
|
||||||
@@ -109,10 +110,15 @@ type Env struct {
|
|||||||
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
|
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
|
||||||
TwitterClientID *string `json:"TWITTER_CLIENT_ID"`
|
TwitterClientID *string `json:"TWITTER_CLIENT_ID"`
|
||||||
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET"`
|
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET"`
|
||||||
|
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID"`
|
||||||
|
MicrosoftClientSecret *string `json:"MICROSOFT_CLIENT_SECRET"`
|
||||||
|
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID"`
|
||||||
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
||||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
||||||
AppCookieSecure bool `json:"APP_COOKIE_SECURE"`
|
AppCookieSecure bool `json:"APP_COOKIE_SECURE"`
|
||||||
AdminCookieSecure bool `json:"ADMIN_COOKIE_SECURE"`
|
AdminCookieSecure bool `json:"ADMIN_COOKIE_SECURE"`
|
||||||
|
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE"`
|
||||||
|
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Error struct {
|
type Error struct {
|
||||||
@@ -136,11 +142,20 @@ type GenerateJWTKeysResponse struct {
|
|||||||
PrivateKey *string `json:"private_key"`
|
PrivateKey *string `json:"private_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetUserRequest struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
type InviteMemberInput struct {
|
type InviteMemberInput struct {
|
||||||
Emails []string `json:"emails"`
|
Emails []string `json:"emails"`
|
||||||
RedirectURI *string `json:"redirect_uri"`
|
RedirectURI *string `json:"redirect_uri"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InviteMembersResponse struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Users []*User `json:"Users"`
|
||||||
|
}
|
||||||
|
|
||||||
type ListWebhookLogRequest struct {
|
type ListWebhookLogRequest struct {
|
||||||
Pagination *PaginationInput `json:"pagination"`
|
Pagination *PaginationInput `json:"pagination"`
|
||||||
WebhookID *string `json:"webhook_id"`
|
WebhookID *string `json:"webhook_id"`
|
||||||
@@ -171,6 +186,7 @@ type Meta struct {
|
|||||||
IsLinkedinLoginEnabled bool `json:"is_linkedin_login_enabled"`
|
IsLinkedinLoginEnabled bool `json:"is_linkedin_login_enabled"`
|
||||||
IsAppleLoginEnabled bool `json:"is_apple_login_enabled"`
|
IsAppleLoginEnabled bool `json:"is_apple_login_enabled"`
|
||||||
IsTwitterLoginEnabled bool `json:"is_twitter_login_enabled"`
|
IsTwitterLoginEnabled bool `json:"is_twitter_login_enabled"`
|
||||||
|
IsMicrosoftLoginEnabled bool `json:"is_microsoft_login_enabled"`
|
||||||
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
||||||
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
||||||
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
||||||
@@ -179,6 +195,33 @@ type Meta struct {
|
|||||||
IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"`
|
IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MobileLoginInput struct {
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Roles []string `json:"roles"`
|
||||||
|
Scope []string `json:"scope"`
|
||||||
|
State *string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MobileSignUpInput struct {
|
||||||
|
Email *string `json:"email"`
|
||||||
|
GivenName *string `json:"given_name"`
|
||||||
|
FamilyName *string `json:"family_name"`
|
||||||
|
MiddleName *string `json:"middle_name"`
|
||||||
|
Nickname *string `json:"nickname"`
|
||||||
|
Gender *string `json:"gender"`
|
||||||
|
Birthdate *string `json:"birthdate"`
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
Picture *string `json:"picture"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
ConfirmPassword string `json:"confirm_password"`
|
||||||
|
Roles []string `json:"roles"`
|
||||||
|
Scope []string `json:"scope"`
|
||||||
|
RedirectURI *string `json:"redirect_uri"`
|
||||||
|
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
|
||||||
|
State *string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
type OAuthRevokeInput struct {
|
type OAuthRevokeInput struct {
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
}
|
}
|
||||||
@@ -312,8 +355,13 @@ type UpdateEnvInput struct {
|
|||||||
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
|
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
|
||||||
TwitterClientID *string `json:"TWITTER_CLIENT_ID"`
|
TwitterClientID *string `json:"TWITTER_CLIENT_ID"`
|
||||||
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET"`
|
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET"`
|
||||||
|
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID"`
|
||||||
|
MicrosoftClientSecret *string `json:"MICROSOFT_CLIENT_SECRET"`
|
||||||
|
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID"`
|
||||||
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
||||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
||||||
|
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE"`
|
||||||
|
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateProfileInput struct {
|
type UpdateProfileInput struct {
|
||||||
@@ -349,11 +397,12 @@ type UpdateUserInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UpdateWebhookRequest struct {
|
type UpdateWebhookRequest struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
EventName *string `json:"event_name"`
|
EventName *string `json:"event_name"`
|
||||||
Endpoint *string `json:"endpoint"`
|
EventDescription *string `json:"event_description"`
|
||||||
Enabled *bool `json:"enabled"`
|
Endpoint *string `json:"endpoint"`
|
||||||
Headers map[string]interface{} `json:"headers"`
|
Enabled *bool `json:"enabled"`
|
||||||
|
Headers map[string]interface{} `json:"headers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
@@ -423,13 +472,14 @@ type VerifyOTPRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Webhook struct {
|
type Webhook struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
EventName *string `json:"event_name"`
|
EventName *string `json:"event_name"`
|
||||||
Endpoint *string `json:"endpoint"`
|
EventDescription *string `json:"event_description"`
|
||||||
Enabled *bool `json:"enabled"`
|
Endpoint *string `json:"endpoint"`
|
||||||
Headers map[string]interface{} `json:"headers"`
|
Enabled *bool `json:"enabled"`
|
||||||
CreatedAt *int64 `json:"created_at"`
|
Headers map[string]interface{} `json:"headers"`
|
||||||
UpdatedAt *int64 `json:"updated_at"`
|
CreatedAt *int64 `json:"created_at"`
|
||||||
|
UpdatedAt *int64 `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebhookLog struct {
|
type WebhookLog struct {
|
||||||
|
@@ -6,527 +6,586 @@ scalar Map
|
|||||||
scalar Any
|
scalar Any
|
||||||
|
|
||||||
type Pagination {
|
type Pagination {
|
||||||
limit: Int64!
|
limit: Int64!
|
||||||
page: Int64!
|
page: Int64!
|
||||||
offset: Int64!
|
offset: Int64!
|
||||||
total: Int64!
|
total: Int64!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Meta {
|
type Meta {
|
||||||
version: String!
|
version: String!
|
||||||
client_id: String!
|
client_id: String!
|
||||||
is_google_login_enabled: Boolean!
|
is_google_login_enabled: Boolean!
|
||||||
is_facebook_login_enabled: Boolean!
|
is_facebook_login_enabled: Boolean!
|
||||||
is_github_login_enabled: Boolean!
|
is_github_login_enabled: Boolean!
|
||||||
is_linkedin_login_enabled: Boolean!
|
is_linkedin_login_enabled: Boolean!
|
||||||
is_apple_login_enabled: Boolean!
|
is_apple_login_enabled: Boolean!
|
||||||
is_twitter_login_enabled: Boolean!
|
is_twitter_login_enabled: Boolean!
|
||||||
is_email_verification_enabled: Boolean!
|
is_microsoft_login_enabled: Boolean!
|
||||||
is_basic_authentication_enabled: Boolean!
|
is_email_verification_enabled: Boolean!
|
||||||
is_magic_link_login_enabled: Boolean!
|
is_basic_authentication_enabled: Boolean!
|
||||||
is_sign_up_enabled: Boolean!
|
is_magic_link_login_enabled: Boolean!
|
||||||
is_strong_password_enabled: Boolean!
|
is_sign_up_enabled: Boolean!
|
||||||
is_multi_factor_auth_enabled: Boolean!
|
is_strong_password_enabled: Boolean!
|
||||||
|
is_multi_factor_auth_enabled: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
type User {
|
type User {
|
||||||
id: ID!
|
id: ID!
|
||||||
email: String!
|
email: String!
|
||||||
email_verified: Boolean!
|
email_verified: Boolean!
|
||||||
signup_methods: String!
|
signup_methods: String!
|
||||||
given_name: String
|
given_name: String
|
||||||
family_name: String
|
family_name: String
|
||||||
middle_name: String
|
middle_name: String
|
||||||
nickname: String
|
nickname: String
|
||||||
# defaults to email
|
# defaults to email
|
||||||
preferred_username: String
|
preferred_username: String
|
||||||
gender: String
|
gender: String
|
||||||
birthdate: String
|
birthdate: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
phone_number_verified: Boolean
|
phone_number_verified: Boolean
|
||||||
picture: String
|
picture: String
|
||||||
roles: [String!]!
|
roles: [String!]!
|
||||||
created_at: Int64
|
created_at: Int64
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
revoked_timestamp: Int64
|
revoked_timestamp: Int64
|
||||||
is_multi_factor_auth_enabled: Boolean
|
is_multi_factor_auth_enabled: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type Users {
|
type Users {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
users: [User!]!
|
users: [User!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type VerificationRequest {
|
type VerificationRequest {
|
||||||
id: ID!
|
id: ID!
|
||||||
identifier: String
|
identifier: String
|
||||||
token: String
|
token: String
|
||||||
email: String
|
email: String
|
||||||
expires: Int64
|
expires: Int64
|
||||||
created_at: Int64
|
created_at: Int64
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
nonce: String
|
nonce: String
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type VerificationRequests {
|
type VerificationRequests {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
verification_requests: [VerificationRequest!]!
|
verification_requests: [VerificationRequest!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Error {
|
type Error {
|
||||||
message: String!
|
message: String!
|
||||||
reason: String!
|
reason: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthResponse {
|
type AuthResponse {
|
||||||
message: String!
|
message: String!
|
||||||
should_show_otp_screen: Boolean
|
should_show_otp_screen: Boolean
|
||||||
access_token: String
|
access_token: String
|
||||||
id_token: String
|
id_token: String
|
||||||
refresh_token: String
|
refresh_token: String
|
||||||
expires_in: Int64
|
expires_in: Int64
|
||||||
user: User
|
user: User
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response {
|
type Response {
|
||||||
message: String!
|
message: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type InviteMembersResponse {
|
||||||
|
message: String!
|
||||||
|
Users: [User!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Env {
|
type Env {
|
||||||
ACCESS_TOKEN_EXPIRY_TIME: String
|
ACCESS_TOKEN_EXPIRY_TIME: String
|
||||||
ADMIN_SECRET: String
|
ADMIN_SECRET: String
|
||||||
DATABASE_NAME: String
|
DATABASE_NAME: String
|
||||||
DATABASE_URL: String
|
DATABASE_URL: String
|
||||||
DATABASE_TYPE: String
|
DATABASE_TYPE: String
|
||||||
DATABASE_USERNAME: String
|
DATABASE_USERNAME: String
|
||||||
DATABASE_PASSWORD: String
|
DATABASE_PASSWORD: String
|
||||||
DATABASE_HOST: String
|
DATABASE_HOST: String
|
||||||
DATABASE_PORT: String
|
DATABASE_PORT: String
|
||||||
CLIENT_ID: String!
|
CLIENT_ID: String!
|
||||||
CLIENT_SECRET: String!
|
CLIENT_SECRET: String!
|
||||||
CUSTOM_ACCESS_TOKEN_SCRIPT: String
|
CUSTOM_ACCESS_TOKEN_SCRIPT: String
|
||||||
SMTP_HOST: String
|
SMTP_HOST: String
|
||||||
SMTP_PORT: String
|
SMTP_PORT: String
|
||||||
SMTP_USERNAME: String
|
SMTP_USERNAME: String
|
||||||
SMTP_PASSWORD: String
|
SMTP_PASSWORD: String
|
||||||
SMTP_LOCAL_NAME: String
|
SMTP_LOCAL_NAME: String
|
||||||
SENDER_EMAIL: String
|
SENDER_EMAIL: String
|
||||||
JWT_TYPE: String
|
JWT_TYPE: String
|
||||||
JWT_SECRET: String
|
JWT_SECRET: String
|
||||||
JWT_PRIVATE_KEY: String
|
JWT_PRIVATE_KEY: String
|
||||||
JWT_PUBLIC_KEY: String
|
JWT_PUBLIC_KEY: String
|
||||||
ALLOWED_ORIGINS: [String!]
|
ALLOWED_ORIGINS: [String!]
|
||||||
APP_URL: String
|
APP_URL: String
|
||||||
REDIS_URL: String
|
REDIS_URL: String
|
||||||
RESET_PASSWORD_URL: String
|
RESET_PASSWORD_URL: String
|
||||||
DISABLE_EMAIL_VERIFICATION: Boolean!
|
DISABLE_EMAIL_VERIFICATION: Boolean!
|
||||||
DISABLE_BASIC_AUTHENTICATION: Boolean!
|
DISABLE_BASIC_AUTHENTICATION: Boolean!
|
||||||
DISABLE_MAGIC_LINK_LOGIN: Boolean!
|
DISABLE_MAGIC_LINK_LOGIN: Boolean!
|
||||||
DISABLE_LOGIN_PAGE: Boolean!
|
DISABLE_LOGIN_PAGE: Boolean!
|
||||||
DISABLE_SIGN_UP: Boolean!
|
DISABLE_SIGN_UP: Boolean!
|
||||||
DISABLE_REDIS_FOR_ENV: Boolean!
|
DISABLE_REDIS_FOR_ENV: Boolean!
|
||||||
DISABLE_STRONG_PASSWORD: Boolean!
|
DISABLE_STRONG_PASSWORD: Boolean!
|
||||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: Boolean!
|
DISABLE_MULTI_FACTOR_AUTHENTICATION: Boolean!
|
||||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: Boolean!
|
ENFORCE_MULTI_FACTOR_AUTHENTICATION: Boolean!
|
||||||
ROLES: [String!]
|
ROLES: [String!]
|
||||||
PROTECTED_ROLES: [String!]
|
PROTECTED_ROLES: [String!]
|
||||||
DEFAULT_ROLES: [String!]
|
DEFAULT_ROLES: [String!]
|
||||||
JWT_ROLE_CLAIM: String
|
JWT_ROLE_CLAIM: String
|
||||||
GOOGLE_CLIENT_ID: String
|
GOOGLE_CLIENT_ID: String
|
||||||
GOOGLE_CLIENT_SECRET: String
|
GOOGLE_CLIENT_SECRET: String
|
||||||
GITHUB_CLIENT_ID: String
|
GITHUB_CLIENT_ID: String
|
||||||
GITHUB_CLIENT_SECRET: String
|
GITHUB_CLIENT_SECRET: String
|
||||||
FACEBOOK_CLIENT_ID: String
|
FACEBOOK_CLIENT_ID: String
|
||||||
FACEBOOK_CLIENT_SECRET: String
|
FACEBOOK_CLIENT_SECRET: String
|
||||||
LINKEDIN_CLIENT_ID: String
|
LINKEDIN_CLIENT_ID: String
|
||||||
LINKEDIN_CLIENT_SECRET: String
|
LINKEDIN_CLIENT_SECRET: String
|
||||||
APPLE_CLIENT_ID: String
|
APPLE_CLIENT_ID: String
|
||||||
APPLE_CLIENT_SECRET: String
|
APPLE_CLIENT_SECRET: String
|
||||||
TWITTER_CLIENT_ID: String
|
TWITTER_CLIENT_ID: String
|
||||||
TWITTER_CLIENT_SECRET: String
|
TWITTER_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
MICROSOFT_CLIENT_ID: String
|
||||||
ORGANIZATION_LOGO: String
|
MICROSOFT_CLIENT_SECRET: String
|
||||||
APP_COOKIE_SECURE: Boolean!
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
||||||
ADMIN_COOKIE_SECURE: Boolean!
|
ORGANIZATION_NAME: String
|
||||||
|
ORGANIZATION_LOGO: String
|
||||||
|
APP_COOKIE_SECURE: Boolean!
|
||||||
|
ADMIN_COOKIE_SECURE: Boolean!
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type ValidateJWTTokenResponse {
|
type ValidateJWTTokenResponse {
|
||||||
is_valid: Boolean!
|
is_valid: Boolean!
|
||||||
claims: Map
|
claims: Map
|
||||||
}
|
}
|
||||||
|
|
||||||
type GenerateJWTKeysResponse {
|
type GenerateJWTKeysResponse {
|
||||||
secret: String
|
secret: String
|
||||||
public_key: String
|
public_key: String
|
||||||
private_key: String
|
private_key: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type Webhook {
|
type Webhook {
|
||||||
id: ID!
|
id: ID!
|
||||||
event_name: String
|
event_name: String # this is unique string
|
||||||
endpoint: String
|
event_description: String
|
||||||
enabled: Boolean
|
endpoint: String
|
||||||
headers: Map
|
enabled: Boolean
|
||||||
created_at: Int64
|
headers: Map
|
||||||
updated_at: Int64
|
created_at: Int64
|
||||||
|
updated_at: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Webhooks {
|
type Webhooks {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
webhooks: [Webhook!]!
|
webhooks: [Webhook!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebhookLog {
|
type WebhookLog {
|
||||||
id: ID!
|
id: ID!
|
||||||
http_status: Int64
|
http_status: Int64
|
||||||
response: String
|
response: String
|
||||||
request: String
|
request: String
|
||||||
webhook_id: ID
|
webhook_id: ID
|
||||||
created_at: Int64
|
created_at: Int64
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestEndpointResponse {
|
type TestEndpointResponse {
|
||||||
http_status: Int64
|
http_status: Int64
|
||||||
response: String
|
response: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebhookLogs {
|
type WebhookLogs {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
webhook_logs: [WebhookLog!]!
|
webhook_logs: [WebhookLog!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmailTemplate {
|
type EmailTemplate {
|
||||||
id: ID!
|
id: ID!
|
||||||
event_name: String!
|
event_name: String!
|
||||||
template: String!
|
template: String!
|
||||||
design: String!
|
design: String!
|
||||||
subject: String!
|
subject: String!
|
||||||
created_at: Int64
|
created_at: Int64
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmailTemplates {
|
type EmailTemplates {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
email_templates: [EmailTemplate!]!
|
email_templates: [EmailTemplate!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateEnvInput {
|
input UpdateEnvInput {
|
||||||
ACCESS_TOKEN_EXPIRY_TIME: String
|
ACCESS_TOKEN_EXPIRY_TIME: String
|
||||||
ADMIN_SECRET: String
|
ADMIN_SECRET: String
|
||||||
CUSTOM_ACCESS_TOKEN_SCRIPT: String
|
CUSTOM_ACCESS_TOKEN_SCRIPT: String
|
||||||
OLD_ADMIN_SECRET: String
|
OLD_ADMIN_SECRET: String
|
||||||
SMTP_HOST: String
|
SMTP_HOST: String
|
||||||
SMTP_PORT: String
|
SMTP_PORT: String
|
||||||
SMTP_USERNAME: String
|
SMTP_USERNAME: String
|
||||||
SMTP_PASSWORD: String
|
SMTP_PASSWORD: String
|
||||||
SMTP_LOCAL_NAME: String
|
SMTP_LOCAL_NAME: String
|
||||||
SENDER_EMAIL: String
|
SENDER_EMAIL: String
|
||||||
JWT_TYPE: String
|
JWT_TYPE: String
|
||||||
JWT_SECRET: String
|
JWT_SECRET: String
|
||||||
JWT_PRIVATE_KEY: String
|
JWT_PRIVATE_KEY: String
|
||||||
JWT_PUBLIC_KEY: String
|
JWT_PUBLIC_KEY: String
|
||||||
ALLOWED_ORIGINS: [String!]
|
ALLOWED_ORIGINS: [String!]
|
||||||
APP_URL: String
|
APP_URL: String
|
||||||
RESET_PASSWORD_URL: String
|
RESET_PASSWORD_URL: String
|
||||||
APP_COOKIE_SECURE: Boolean
|
APP_COOKIE_SECURE: Boolean
|
||||||
ADMIN_COOKIE_SECURE: Boolean
|
ADMIN_COOKIE_SECURE: Boolean
|
||||||
DISABLE_EMAIL_VERIFICATION: Boolean
|
DISABLE_EMAIL_VERIFICATION: Boolean
|
||||||
DISABLE_BASIC_AUTHENTICATION: Boolean
|
DISABLE_BASIC_AUTHENTICATION: Boolean
|
||||||
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
||||||
DISABLE_LOGIN_PAGE: Boolean
|
DISABLE_LOGIN_PAGE: Boolean
|
||||||
DISABLE_SIGN_UP: Boolean
|
DISABLE_SIGN_UP: Boolean
|
||||||
DISABLE_REDIS_FOR_ENV: Boolean
|
DISABLE_REDIS_FOR_ENV: Boolean
|
||||||
DISABLE_STRONG_PASSWORD: Boolean
|
DISABLE_STRONG_PASSWORD: Boolean
|
||||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: Boolean
|
DISABLE_MULTI_FACTOR_AUTHENTICATION: Boolean
|
||||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: Boolean
|
ENFORCE_MULTI_FACTOR_AUTHENTICATION: Boolean
|
||||||
ROLES: [String!]
|
ROLES: [String!]
|
||||||
PROTECTED_ROLES: [String!]
|
PROTECTED_ROLES: [String!]
|
||||||
DEFAULT_ROLES: [String!]
|
DEFAULT_ROLES: [String!]
|
||||||
JWT_ROLE_CLAIM: String
|
JWT_ROLE_CLAIM: String
|
||||||
GOOGLE_CLIENT_ID: String
|
GOOGLE_CLIENT_ID: String
|
||||||
GOOGLE_CLIENT_SECRET: String
|
GOOGLE_CLIENT_SECRET: String
|
||||||
GITHUB_CLIENT_ID: String
|
GITHUB_CLIENT_ID: String
|
||||||
GITHUB_CLIENT_SECRET: String
|
GITHUB_CLIENT_SECRET: String
|
||||||
FACEBOOK_CLIENT_ID: String
|
FACEBOOK_CLIENT_ID: String
|
||||||
FACEBOOK_CLIENT_SECRET: String
|
FACEBOOK_CLIENT_SECRET: String
|
||||||
LINKEDIN_CLIENT_ID: String
|
LINKEDIN_CLIENT_ID: String
|
||||||
LINKEDIN_CLIENT_SECRET: String
|
LINKEDIN_CLIENT_SECRET: String
|
||||||
APPLE_CLIENT_ID: String
|
APPLE_CLIENT_ID: String
|
||||||
APPLE_CLIENT_SECRET: String
|
APPLE_CLIENT_SECRET: String
|
||||||
TWITTER_CLIENT_ID: String
|
TWITTER_CLIENT_ID: String
|
||||||
TWITTER_CLIENT_SECRET: String
|
TWITTER_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
MICROSOFT_CLIENT_ID: String
|
||||||
ORGANIZATION_LOGO: String
|
MICROSOFT_CLIENT_SECRET: String
|
||||||
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
||||||
|
ORGANIZATION_NAME: String
|
||||||
|
ORGANIZATION_LOGO: String
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
||||||
|
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input AdminLoginInput {
|
input AdminLoginInput {
|
||||||
admin_secret: String!
|
admin_secret: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input AdminSignupInput {
|
input AdminSignupInput {
|
||||||
admin_secret: String!
|
admin_secret: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
input MobileSignUpInput {
|
||||||
|
email: String
|
||||||
|
given_name: String
|
||||||
|
family_name: String
|
||||||
|
middle_name: String
|
||||||
|
nickname: String
|
||||||
|
gender: String
|
||||||
|
birthdate: String
|
||||||
|
phone_number: String!
|
||||||
|
picture: String
|
||||||
|
password: String!
|
||||||
|
confirm_password: String!
|
||||||
|
roles: [String!]
|
||||||
|
scope: [String!]
|
||||||
|
redirect_uri: String
|
||||||
|
is_multi_factor_auth_enabled: Boolean
|
||||||
|
# state is used for authorization code grant flow
|
||||||
|
# it is used to get code for an on-going auth process during login
|
||||||
|
# and use that code for setting `c_hash` in id_token
|
||||||
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input SignUpInput {
|
input SignUpInput {
|
||||||
email: String!
|
email: String!
|
||||||
given_name: String
|
given_name: String
|
||||||
family_name: String
|
family_name: String
|
||||||
middle_name: String
|
middle_name: String
|
||||||
nickname: String
|
nickname: String
|
||||||
gender: String
|
gender: String
|
||||||
birthdate: String
|
birthdate: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
picture: String
|
picture: String
|
||||||
password: String!
|
password: String!
|
||||||
confirm_password: String!
|
confirm_password: String!
|
||||||
roles: [String!]
|
roles: [String!]
|
||||||
scope: [String!]
|
scope: [String!]
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
is_multi_factor_auth_enabled: Boolean
|
is_multi_factor_auth_enabled: Boolean
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
# and use that code for setting `c_hash` in id_token
|
# and use that code for setting `c_hash` in id_token
|
||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input LoginInput {
|
input LoginInput {
|
||||||
email: String!
|
email: String!
|
||||||
password: String!
|
password: String!
|
||||||
roles: [String!]
|
roles: [String!]
|
||||||
scope: [String!]
|
scope: [String!]
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
# and use that code for setting `c_hash` in id_token
|
# and use that code for setting `c_hash` in id_token
|
||||||
state: String
|
state: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input MobileLoginInput {
|
||||||
|
phone_number: String!
|
||||||
|
password: String!
|
||||||
|
roles: [String!]
|
||||||
|
scope: [String!]
|
||||||
|
# state is used for authorization code grant flow
|
||||||
|
# it is used to get code for an on-going auth process during login
|
||||||
|
# and use that code for setting `c_hash` in id_token
|
||||||
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input VerifyEmailInput {
|
input VerifyEmailInput {
|
||||||
token: String!
|
token: String!
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
# and use that code for setting `c_hash` in id_token
|
# and use that code for setting `c_hash` in id_token
|
||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ResendVerifyEmailInput {
|
input ResendVerifyEmailInput {
|
||||||
email: String!
|
email: String!
|
||||||
identifier: String!
|
identifier: String!
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
# and use that code for setting `c_hash` in id_token
|
# and use that code for setting `c_hash` in id_token
|
||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateProfileInput {
|
input UpdateProfileInput {
|
||||||
old_password: String
|
old_password: String
|
||||||
new_password: String
|
new_password: String
|
||||||
confirm_new_password: String
|
confirm_new_password: String
|
||||||
email: String
|
email: String
|
||||||
given_name: String
|
given_name: String
|
||||||
family_name: String
|
family_name: String
|
||||||
middle_name: String
|
middle_name: String
|
||||||
nickname: String
|
nickname: String
|
||||||
gender: String
|
gender: String
|
||||||
birthdate: String
|
birthdate: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
picture: String
|
picture: String
|
||||||
is_multi_factor_auth_enabled: Boolean
|
is_multi_factor_auth_enabled: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateUserInput {
|
input UpdateUserInput {
|
||||||
id: ID!
|
id: ID!
|
||||||
email: String
|
email: String
|
||||||
email_verified: Boolean
|
email_verified: Boolean
|
||||||
given_name: String
|
given_name: String
|
||||||
family_name: String
|
family_name: String
|
||||||
middle_name: String
|
middle_name: String
|
||||||
nickname: String
|
nickname: String
|
||||||
gender: String
|
gender: String
|
||||||
birthdate: String
|
birthdate: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
picture: String
|
picture: String
|
||||||
roles: [String]
|
roles: [String]
|
||||||
is_multi_factor_auth_enabled: Boolean
|
is_multi_factor_auth_enabled: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
input ForgotPasswordInput {
|
input ForgotPasswordInput {
|
||||||
email: String!
|
email: String!
|
||||||
state: String
|
state: String
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ResetPasswordInput {
|
input ResetPasswordInput {
|
||||||
token: String!
|
token: String!
|
||||||
password: String!
|
password: String!
|
||||||
confirm_password: String!
|
confirm_password: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input DeleteUserInput {
|
input DeleteUserInput {
|
||||||
email: String!
|
email: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input MagicLinkLoginInput {
|
input MagicLinkLoginInput {
|
||||||
email: String!
|
email: String!
|
||||||
roles: [String!]
|
roles: [String!]
|
||||||
scope: [String!]
|
scope: [String!]
|
||||||
state: String
|
state: String
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input SessionQueryInput {
|
input SessionQueryInput {
|
||||||
roles: [String!]
|
roles: [String!]
|
||||||
scope: [String!]
|
scope: [String!]
|
||||||
}
|
}
|
||||||
|
|
||||||
input PaginationInput {
|
input PaginationInput {
|
||||||
limit: Int64
|
limit: Int64
|
||||||
page: Int64
|
page: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
input PaginatedInput {
|
input PaginatedInput {
|
||||||
pagination: PaginationInput
|
pagination: PaginationInput
|
||||||
}
|
}
|
||||||
|
|
||||||
input OAuthRevokeInput {
|
input OAuthRevokeInput {
|
||||||
refresh_token: String!
|
refresh_token: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input InviteMemberInput {
|
input InviteMemberInput {
|
||||||
emails: [String!]!
|
emails: [String!]!
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateAccessInput {
|
input UpdateAccessInput {
|
||||||
user_id: String!
|
user_id: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input ValidateJWTTokenInput {
|
input ValidateJWTTokenInput {
|
||||||
token_type: String!
|
token_type: String!
|
||||||
token: String!
|
token: String!
|
||||||
roles: [String!]
|
roles: [String!]
|
||||||
}
|
}
|
||||||
|
|
||||||
input GenerateJWTKeysInput {
|
input GenerateJWTKeysInput {
|
||||||
type: String!
|
type: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input ListWebhookLogRequest {
|
input ListWebhookLogRequest {
|
||||||
pagination: PaginationInput
|
pagination: PaginationInput
|
||||||
webhook_id: String
|
webhook_id: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input AddWebhookRequest {
|
input AddWebhookRequest {
|
||||||
event_name: String!
|
event_name: String!
|
||||||
endpoint: String!
|
event_description: String
|
||||||
enabled: Boolean!
|
endpoint: String!
|
||||||
headers: Map
|
enabled: Boolean!
|
||||||
|
headers: Map
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateWebhookRequest {
|
input UpdateWebhookRequest {
|
||||||
id: ID!
|
id: ID!
|
||||||
event_name: String
|
event_name: String
|
||||||
endpoint: String
|
event_description: String
|
||||||
enabled: Boolean
|
endpoint: String
|
||||||
headers: Map
|
enabled: Boolean
|
||||||
|
headers: Map
|
||||||
}
|
}
|
||||||
|
|
||||||
input WebhookRequest {
|
input WebhookRequest {
|
||||||
id: ID!
|
id: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
input TestEndpointRequest {
|
input TestEndpointRequest {
|
||||||
endpoint: String!
|
endpoint: String!
|
||||||
event_name: String!
|
event_name: String!
|
||||||
headers: Map
|
headers: Map
|
||||||
}
|
}
|
||||||
|
|
||||||
input AddEmailTemplateRequest {
|
input AddEmailTemplateRequest {
|
||||||
event_name: String!
|
event_name: String!
|
||||||
subject: String!
|
subject: String!
|
||||||
template: String!
|
template: String!
|
||||||
# Design value is set when editor is used
|
# Design value is set when editor is used
|
||||||
# If raw HTML is used design value is set to null
|
# If raw HTML is used design value is set to null
|
||||||
design: String
|
design: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateEmailTemplateRequest {
|
input UpdateEmailTemplateRequest {
|
||||||
id: ID!
|
id: ID!
|
||||||
event_name: String
|
event_name: String
|
||||||
template: String
|
template: String
|
||||||
subject: String
|
subject: String
|
||||||
# Design value is set when editor is used
|
# Design value is set when editor is used
|
||||||
# If raw HTML is used design value is set to null
|
# If raw HTML is used design value is set to null
|
||||||
design: String
|
design: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input DeleteEmailTemplateRequest {
|
input DeleteEmailTemplateRequest {
|
||||||
id: ID!
|
id: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
input VerifyOTPRequest {
|
input VerifyOTPRequest {
|
||||||
email: String!
|
email: String!
|
||||||
otp: String!
|
otp: String!
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
# and use that code for setting `c_hash` in id_token
|
# and use that code for setting `c_hash` in id_token
|
||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ResendOTPRequest {
|
input ResendOTPRequest {
|
||||||
email: String!
|
email: String!
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
# and use that code for setting `c_hash` in id_token
|
# and use that code for setting `c_hash` in id_token
|
||||||
state: String
|
state: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input GetUserRequest {
|
||||||
|
id: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
signup(params: SignUpInput!): AuthResponse!
|
signup(params: SignUpInput!): AuthResponse!
|
||||||
login(params: LoginInput!): AuthResponse!
|
mobile_signup(params: MobileSignUpInput): AuthResponse!
|
||||||
magic_link_login(params: MagicLinkLoginInput!): Response!
|
login(params: LoginInput!): AuthResponse!
|
||||||
logout: Response!
|
mobile_login(params: MobileLoginInput!): AuthResponse!
|
||||||
update_profile(params: UpdateProfileInput!): Response!
|
magic_link_login(params: MagicLinkLoginInput!): Response!
|
||||||
verify_email(params: VerifyEmailInput!): AuthResponse!
|
logout: Response!
|
||||||
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
update_profile(params: UpdateProfileInput!): Response!
|
||||||
forgot_password(params: ForgotPasswordInput!): Response!
|
verify_email(params: VerifyEmailInput!): AuthResponse!
|
||||||
reset_password(params: ResetPasswordInput!): Response!
|
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
||||||
revoke(params: OAuthRevokeInput!): Response!
|
forgot_password(params: ForgotPasswordInput!): Response!
|
||||||
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
reset_password(params: ResetPasswordInput!): Response!
|
||||||
resend_otp(params: ResendOTPRequest!): Response!
|
revoke(params: OAuthRevokeInput!): Response!
|
||||||
# admin only apis
|
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
||||||
_delete_user(params: DeleteUserInput!): Response!
|
resend_otp(params: ResendOTPRequest!): Response!
|
||||||
_update_user(params: UpdateUserInput!): User!
|
# admin only apis
|
||||||
_admin_signup(params: AdminSignupInput!): Response!
|
_delete_user(params: DeleteUserInput!): Response!
|
||||||
_admin_login(params: AdminLoginInput!): Response!
|
_update_user(params: UpdateUserInput!): User!
|
||||||
_admin_logout: Response!
|
_admin_signup(params: AdminSignupInput!): Response!
|
||||||
_update_env(params: UpdateEnvInput!): Response!
|
_admin_login(params: AdminLoginInput!): Response!
|
||||||
_invite_members(params: InviteMemberInput!): Response!
|
_admin_logout: Response!
|
||||||
_revoke_access(param: UpdateAccessInput!): Response!
|
_update_env(params: UpdateEnvInput!): Response!
|
||||||
_enable_access(param: UpdateAccessInput!): Response!
|
_invite_members(params: InviteMemberInput!): InviteMembersResponse!
|
||||||
_generate_jwt_keys(params: GenerateJWTKeysInput!): GenerateJWTKeysResponse!
|
_revoke_access(param: UpdateAccessInput!): Response!
|
||||||
_add_webhook(params: AddWebhookRequest!): Response!
|
_enable_access(param: UpdateAccessInput!): Response!
|
||||||
_update_webhook(params: UpdateWebhookRequest!): Response!
|
_generate_jwt_keys(params: GenerateJWTKeysInput!): GenerateJWTKeysResponse!
|
||||||
_delete_webhook(params: WebhookRequest!): Response!
|
_add_webhook(params: AddWebhookRequest!): Response!
|
||||||
_test_endpoint(params: TestEndpointRequest!): TestEndpointResponse!
|
_update_webhook(params: UpdateWebhookRequest!): Response!
|
||||||
_add_email_template(params: AddEmailTemplateRequest!): Response!
|
_delete_webhook(params: WebhookRequest!): Response!
|
||||||
_update_email_template(params: UpdateEmailTemplateRequest!): Response!
|
_test_endpoint(params: TestEndpointRequest!): TestEndpointResponse!
|
||||||
_delete_email_template(params: DeleteEmailTemplateRequest!): Response!
|
_add_email_template(params: AddEmailTemplateRequest!): Response!
|
||||||
|
_update_email_template(params: UpdateEmailTemplateRequest!): Response!
|
||||||
|
_delete_email_template(params: DeleteEmailTemplateRequest!): Response!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
meta: Meta!
|
meta: Meta!
|
||||||
session(params: SessionQueryInput): AuthResponse!
|
session(params: SessionQueryInput): AuthResponse!
|
||||||
profile: User!
|
profile: User!
|
||||||
validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse!
|
validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse!
|
||||||
# admin only apis
|
# admin only apis
|
||||||
_users(params: PaginatedInput): Users!
|
_users(params: PaginatedInput): Users!
|
||||||
_verification_requests(params: PaginatedInput): VerificationRequests!
|
_user(params: GetUserRequest!): User!
|
||||||
_admin_session: Response!
|
_verification_requests(params: PaginatedInput): VerificationRequests!
|
||||||
_env: Env!
|
_admin_session: Response!
|
||||||
_webhook(params: WebhookRequest!): Webhook!
|
_env: Env!
|
||||||
_webhooks(params: PaginatedInput): Webhooks!
|
_webhook(params: WebhookRequest!): Webhook!
|
||||||
_webhook_logs(params: ListWebhookLogRequest): WebhookLogs!
|
_webhooks(params: PaginatedInput): Webhooks!
|
||||||
_email_templates(params: PaginatedInput): EmailTemplates!
|
_webhook_logs(params: ListWebhookLogRequest): WebhookLogs!
|
||||||
|
_email_templates(params: PaginatedInput): EmailTemplates!
|
||||||
}
|
}
|
||||||
|
@@ -16,11 +16,21 @@ func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpInput)
|
|||||||
return resolvers.SignupResolver(ctx, params)
|
return resolvers.SignupResolver(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MobileSignup is the resolver for the mobile_signup field.
|
||||||
|
func (r *mutationResolver) MobileSignup(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error) {
|
||||||
|
return resolvers.MobileSignupResolver(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
// Login is the resolver for the login field.
|
// Login is the resolver for the login field.
|
||||||
func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) {
|
func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) {
|
||||||
return resolvers.LoginResolver(ctx, params)
|
return resolvers.LoginResolver(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MobileLogin is the resolver for the mobile_login field.
|
||||||
|
func (r *mutationResolver) MobileLogin(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error) {
|
||||||
|
return resolvers.MobileLoginResolver(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
// MagicLinkLogin is the resolver for the magic_link_login field.
|
// MagicLinkLogin is the resolver for the magic_link_login field.
|
||||||
func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
|
func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
|
||||||
return resolvers.MagicLinkLoginResolver(ctx, params)
|
return resolvers.MagicLinkLoginResolver(ctx, params)
|
||||||
@@ -102,7 +112,7 @@ func (r *mutationResolver) UpdateEnv(ctx context.Context, params model.UpdateEnv
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InviteMembers is the resolver for the _invite_members field.
|
// InviteMembers is the resolver for the _invite_members field.
|
||||||
func (r *mutationResolver) InviteMembers(ctx context.Context, params model.InviteMemberInput) (*model.Response, error) {
|
func (r *mutationResolver) InviteMembers(ctx context.Context, params model.InviteMemberInput) (*model.InviteMembersResponse, error) {
|
||||||
return resolvers.InviteMembersResolver(ctx, params)
|
return resolvers.InviteMembersResolver(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +191,11 @@ func (r *queryResolver) Users(ctx context.Context, params *model.PaginatedInput)
|
|||||||
return resolvers.UsersResolver(ctx, params)
|
return resolvers.UsersResolver(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// User is the resolver for the _user field.
|
||||||
|
func (r *queryResolver) User(ctx context.Context, params model.GetUserRequest) (*model.User, error) {
|
||||||
|
return resolvers.UserResolver(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
// VerificationRequests is the resolver for the _verification_requests field.
|
// VerificationRequests is the resolver for the _verification_requests field.
|
||||||
func (r *queryResolver) VerificationRequests(ctx context.Context, params *model.PaginatedInput) (*model.VerificationRequests, error) {
|
func (r *queryResolver) VerificationRequests(ctx context.Context, params *model.PaginatedInput) (*model.VerificationRequests, error) {
|
||||||
return resolvers.VerificationRequestsResolver(ctx, params)
|
return resolvers.VerificationRequestsResolver(ctx, params)
|
||||||
|
@@ -76,7 +76,7 @@ func AppHandler() gin.HandlerFunc {
|
|||||||
"data": map[string]interface{}{
|
"data": map[string]interface{}{
|
||||||
"authorizerURL": hostname,
|
"authorizerURL": hostname,
|
||||||
"redirectURL": redirectURI,
|
"redirectURL": redirectURI,
|
||||||
"scope": scope,
|
"scope": strings.Join(scope, " "),
|
||||||
"state": state,
|
"state": state,
|
||||||
"organizationName": orgName,
|
"organizationName": orgName,
|
||||||
"organizationLogo": orgLogo,
|
"organizationLogo": orgLogo,
|
||||||
|
@@ -83,7 +83,11 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if responseMode == "" {
|
if responseMode == "" {
|
||||||
responseMode = constants.ResponseModeQuery
|
if val, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultAuthorizeResponseMode); err == nil {
|
||||||
|
responseType = val
|
||||||
|
} else {
|
||||||
|
responseType = constants.ResponseModeQuery
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if redirectURI == "" {
|
if redirectURI == "" {
|
||||||
@@ -91,7 +95,11 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if responseType == "" {
|
if responseType == "" {
|
||||||
responseType = "token"
|
if val, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultAuthorizeResponseType); err == nil {
|
||||||
|
responseType = val
|
||||||
|
} else {
|
||||||
|
responseType = constants.ResponseTypeToken
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge); err != nil {
|
if err := validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge); err != nil {
|
||||||
@@ -139,6 +147,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
"error_description": "code challenge is required",
|
"error_description": "code challenge is required",
|
||||||
},
|
},
|
||||||
}, http.StatusOK)
|
}, http.StatusOK)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
loginError := map[string]interface{}{
|
loginError := map[string]interface{}{
|
||||||
@@ -185,7 +194,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
// rollover the session for security
|
// rollover the session for security
|
||||||
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
|
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
|
||||||
if responseType == constants.ResponseTypeCode {
|
if responseType == constants.ResponseTypeCode {
|
||||||
newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod)
|
newSessionTokenData, newSessionToken, newSessionExpiresAt, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("CreateSessionToken failed: ", err)
|
log.Debug("CreateSessionToken failed: ", err)
|
||||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||||
@@ -206,7 +215,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken); err != nil {
|
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken, newSessionExpiresAt); err != nil {
|
||||||
log.Debug("SetUserSession failed: ", err)
|
log.Debug("SetUserSession failed: ", err)
|
||||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||||
return
|
return
|
||||||
@@ -262,13 +271,13 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+nonce, authToken.FingerPrintHash); err != nil {
|
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+nonce, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt); err != nil {
|
||||||
log.Debug("SetUserSession failed: ", err)
|
log.Debug("SetUserSession failed: ", err)
|
||||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce, authToken.FingerPrintHash); err != nil {
|
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt); err != nil {
|
||||||
log.Debug("SetUserSession failed: ", err)
|
log.Debug("SetUserSession failed: ", err)
|
||||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||||
return
|
return
|
||||||
@@ -283,7 +292,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
"access_token": authToken.AccessToken.Token,
|
"access_token": authToken.AccessToken.Token,
|
||||||
"id_token": authToken.IDToken.Token,
|
"id_token": authToken.IDToken.Token,
|
||||||
"state": state,
|
"state": state,
|
||||||
"scope": scope,
|
"scope": strings.Join(scope, " "),
|
||||||
"token_type": "Bearer",
|
"token_type": "Bearer",
|
||||||
"expires_in": authToken.AccessToken.ExpiresAt,
|
"expires_in": authToken.AccessToken.ExpiresAt,
|
||||||
}
|
}
|
||||||
@@ -296,7 +305,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
res["refresh_token"] = authToken.RefreshToken.Token
|
res["refresh_token"] = authToken.RefreshToken.Token
|
||||||
params += "&refresh_token=" + authToken.RefreshToken.Token
|
params += "&refresh_token=" + authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
if responseMode == constants.ResponseModeQuery {
|
if responseMode == constants.ResponseModeQuery {
|
||||||
@@ -326,7 +335,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
|
|
||||||
func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge string) error {
|
func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge string) error {
|
||||||
if strings.TrimSpace(state) == "" {
|
if strings.TrimSpace(state) == "" {
|
||||||
return fmt.Errorf("invalid state. state is required to prevent csrf attack", responseMode)
|
return fmt.Errorf("invalid state. state is required to prevent csrf attack")
|
||||||
}
|
}
|
||||||
if responseType != constants.ResponseTypeCode && responseType != constants.ResponseTypeToken && responseType != constants.ResponseTypeIDToken {
|
if responseType != constants.ResponseTypeCode && responseType != constants.ResponseTypeToken && responseType != constants.ResponseTypeIDToken {
|
||||||
return fmt.Errorf("invalid response type %s. 'code' & 'token' are valid response_type", responseMode)
|
return fmt.Errorf("invalid response type %s. 'code' & 'token' are valid response_type", responseMode)
|
||||||
@@ -349,14 +358,13 @@ func handleResponse(gc *gin.Context, responseMode, loginURI, redirectURI string,
|
|||||||
isAuthenticationRequired = true
|
isAuthenticationRequired = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if isAuthenticationRequired {
|
if isAuthenticationRequired && responseMode != constants.ResponseModeWebMessage {
|
||||||
gc.Redirect(http.StatusFound, loginURI)
|
gc.Redirect(http.StatusFound, loginURI)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch responseMode {
|
switch responseMode {
|
||||||
case constants.ResponseModeQuery, constants.ResponseModeFragment:
|
case constants.ResponseModeQuery, constants.ResponseModeFragment:
|
||||||
|
|
||||||
gc.Redirect(http.StatusFound, redirectURI)
|
gc.Redirect(http.StatusFound, redirectURI)
|
||||||
return
|
return
|
||||||
case constants.ResponseModeWebMessage:
|
case constants.ResponseModeWebMessage:
|
||||||
|
@@ -2,7 +2,7 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/99designs/gqlgen/graphql/handler"
|
"github.com/99designs/gqlgen/graphql/handler"
|
||||||
graph "github.com/authorizerdev/authorizer/server/graph"
|
"github.com/authorizerdev/authorizer/server/graph"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/generated"
|
"github.com/authorizerdev/authorizer/server/graph/generated"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
@@ -27,10 +27,8 @@ func JWKsHandler() gin.HandlerFunc {
|
|||||||
c.JSON(500, gin.H{
|
c.JSON(500, gin.H{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
"keys": []map[string]string{
|
"keys": []map[string]string{
|
||||||
data,
|
data,
|
||||||
|
@@ -47,7 +47,14 @@ func LogoutHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.DeleteUserSession(sessionData.Subject, sessionData.Nonce)
|
userID := sessionData.Subject
|
||||||
|
loginMethod := sessionData.LoginMethod
|
||||||
|
sessionToken := userID
|
||||||
|
if loginMethod != "" {
|
||||||
|
sessionToken = loginMethod + ":" + userID
|
||||||
|
}
|
||||||
|
|
||||||
|
memorystore.Provider.DeleteUserSession(sessionToken, sessionData.Nonce)
|
||||||
cookie.DeleteSession(gc)
|
cookie.DeleteSession(gc)
|
||||||
|
|
||||||
if redirectURL != "" {
|
if redirectURL != "" {
|
||||||
|
@@ -5,7 +5,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -70,6 +70,8 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||||||
user, err = processAppleUserInfo(oauthCode)
|
user, err = processAppleUserInfo(oauthCode)
|
||||||
case constants.AuthRecipeMethodTwitter:
|
case constants.AuthRecipeMethodTwitter:
|
||||||
user, err = processTwitterUserInfo(oauthCode, sessionState)
|
user, err = processTwitterUserInfo(oauthCode, sessionState)
|
||||||
|
case constants.AuthRecipeMethodMicrosoft:
|
||||||
|
user, err = processMicrosoftUserInfo(oauthCode)
|
||||||
default:
|
default:
|
||||||
log.Info("Invalid oauth provider")
|
log.Info("Invalid oauth provider")
|
||||||
err = fmt.Errorf(`invalid oauth provider`)
|
err = fmt.Errorf(`invalid oauth provider`)
|
||||||
@@ -247,12 +249,12 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||||||
|
|
||||||
sessionKey := provider + ":" + user.ID
|
sessionKey := provider + ":" + user.ID
|
||||||
cookie.SetSession(ctx, authToken.FingerPrintHash)
|
cookie.SetSession(ctx, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt)
|
||||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt)
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
params += `&refresh_token=` + authToken.RefreshToken.Token
|
params += `&refresh_token=` + authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@@ -312,7 +314,7 @@ func processGoogleUserInfo(code string) (models.User, error) {
|
|||||||
|
|
||||||
func processGithubUserInfo(code string) (models.User, error) {
|
func processGithubUserInfo(code string) (models.User, error) {
|
||||||
user := models.User{}
|
user := models.User{}
|
||||||
oauth2Token, err := oauth.OAuthProviders.GithubConfig.Exchange(oauth2.NoContext, code)
|
oauth2Token, err := oauth.OAuthProviders.GithubConfig.Exchange(context.TODO(), code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to exchange code for token: ", err)
|
log.Debug("Failed to exchange code for token: ", err)
|
||||||
return user, fmt.Errorf("invalid github exchange code: %s", err.Error())
|
return user, fmt.Errorf("invalid github exchange code: %s", err.Error())
|
||||||
@@ -334,7 +336,7 @@ func processGithubUserInfo(code string) (models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
body, err := ioutil.ReadAll(response.Body)
|
body, err := io.ReadAll(response.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to read github user info response body: ", err)
|
log.Debug("Failed to read github user info response body: ", err)
|
||||||
return user, fmt.Errorf("failed to read github response body: %s", err.Error())
|
return user, fmt.Errorf("failed to read github response body: %s", err.Error())
|
||||||
@@ -383,7 +385,7 @@ func processGithubUserInfo(code string) (models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
body, err := ioutil.ReadAll(response.Body)
|
body, err := io.ReadAll(response.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to read github user email response body: ", err)
|
log.Debug("Failed to read github user email response body: ", err)
|
||||||
return user, fmt.Errorf("failed to read github response body: %s", err.Error())
|
return user, fmt.Errorf("failed to read github response body: %s", err.Error())
|
||||||
@@ -419,7 +421,7 @@ func processGithubUserInfo(code string) (models.User, error) {
|
|||||||
|
|
||||||
func processFacebookUserInfo(code string) (models.User, error) {
|
func processFacebookUserInfo(code string) (models.User, error) {
|
||||||
user := models.User{}
|
user := models.User{}
|
||||||
oauth2Token, err := oauth.OAuthProviders.FacebookConfig.Exchange(oauth2.NoContext, code)
|
oauth2Token, err := oauth.OAuthProviders.FacebookConfig.Exchange(context.TODO(), code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Invalid facebook exchange code: ", err)
|
log.Debug("Invalid facebook exchange code: ", err)
|
||||||
return user, fmt.Errorf("invalid facebook exchange code: %s", err.Error())
|
return user, fmt.Errorf("invalid facebook exchange code: %s", err.Error())
|
||||||
@@ -438,7 +440,7 @@ func processFacebookUserInfo(code string) (models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
body, err := ioutil.ReadAll(response.Body)
|
body, err := io.ReadAll(response.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to read facebook response: ", err)
|
log.Debug("Failed to read facebook response: ", err)
|
||||||
return user, fmt.Errorf("failed to read facebook response body: %s", err.Error())
|
return user, fmt.Errorf("failed to read facebook response body: %s", err.Error())
|
||||||
@@ -470,7 +472,7 @@ func processFacebookUserInfo(code string) (models.User, error) {
|
|||||||
|
|
||||||
func processLinkedInUserInfo(code string) (models.User, error) {
|
func processLinkedInUserInfo(code string) (models.User, error) {
|
||||||
user := models.User{}
|
user := models.User{}
|
||||||
oauth2Token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(oauth2.NoContext, code)
|
oauth2Token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(context.TODO(), code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to exchange code for token: ", err)
|
log.Debug("Failed to exchange code for token: ", err)
|
||||||
return user, fmt.Errorf("invalid linkedin exchange code: %s", err.Error())
|
return user, fmt.Errorf("invalid linkedin exchange code: %s", err.Error())
|
||||||
@@ -493,7 +495,7 @@ func processLinkedInUserInfo(code string) (models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
body, err := ioutil.ReadAll(response.Body)
|
body, err := io.ReadAll(response.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to read linkedin user info response body: ", err)
|
log.Debug("Failed to read linkedin user info response body: ", err)
|
||||||
return user, fmt.Errorf("failed to read linkedin response body: %s", err.Error())
|
return user, fmt.Errorf("failed to read linkedin response body: %s", err.Error())
|
||||||
@@ -523,7 +525,7 @@ func processLinkedInUserInfo(code string) (models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
body, err = ioutil.ReadAll(response.Body)
|
body, err = io.ReadAll(response.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to read linkedin email info response body: ", err)
|
log.Debug("Failed to read linkedin email info response body: ", err)
|
||||||
return user, fmt.Errorf("failed to read linkedin email response body: %s", err.Error())
|
return user, fmt.Errorf("failed to read linkedin email response body: %s", err.Error())
|
||||||
@@ -552,7 +554,7 @@ func processLinkedInUserInfo(code string) (models.User, error) {
|
|||||||
|
|
||||||
func processAppleUserInfo(code string) (models.User, error) {
|
func processAppleUserInfo(code string) (models.User, error) {
|
||||||
user := models.User{}
|
user := models.User{}
|
||||||
oauth2Token, err := oauth.OAuthProviders.AppleConfig.Exchange(oauth2.NoContext, code)
|
oauth2Token, err := oauth.OAuthProviders.AppleConfig.Exchange(context.TODO(), code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to exchange code for token: ", err)
|
log.Debug("Failed to exchange code for token: ", err)
|
||||||
return user, fmt.Errorf("invalid apple exchange code: %s", err.Error())
|
return user, fmt.Errorf("invalid apple exchange code: %s", err.Error())
|
||||||
@@ -605,7 +607,7 @@ func processAppleUserInfo(code string) (models.User, error) {
|
|||||||
|
|
||||||
func processTwitterUserInfo(code, verifier string) (models.User, error) {
|
func processTwitterUserInfo(code, verifier string) (models.User, error) {
|
||||||
user := models.User{}
|
user := models.User{}
|
||||||
oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(oauth2.NoContext, code, oauth2.SetAuthURLParam("code_verifier", verifier))
|
oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(context.TODO(), code, oauth2.SetAuthURLParam("code_verifier", verifier))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to exchange code for token: ", err)
|
log.Debug("Failed to exchange code for token: ", err)
|
||||||
return user, fmt.Errorf("invalid twitter exchange code: %s", err.Error())
|
return user, fmt.Errorf("invalid twitter exchange code: %s", err.Error())
|
||||||
@@ -628,7 +630,7 @@ func processTwitterUserInfo(code, verifier string) (models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
body, err := ioutil.ReadAll(response.Body)
|
body, err := io.ReadAll(response.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to read Twitter user info response body: ", err)
|
log.Debug("Failed to read Twitter user info response body: ", err)
|
||||||
return user, fmt.Errorf("failed to read Twitter response body: %s", err.Error())
|
return user, fmt.Errorf("failed to read Twitter response body: %s", err.Error())
|
||||||
@@ -669,3 +671,37 @@ func processTwitterUserInfo(code, verifier string) (models.User, error) {
|
|||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process microsoft user information
|
||||||
|
func processMicrosoftUserInfo(code string) (models.User, error) {
|
||||||
|
user := models.User{}
|
||||||
|
ctx := context.Background()
|
||||||
|
oauth2Token, err := oauth.OAuthProviders.MicrosoftConfig.Exchange(ctx, code)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to exchange code for token: ", err)
|
||||||
|
return user, fmt.Errorf("invalid google exchange code: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
verifier := oauth.OIDCProviders.MicrosoftOIDC.Verifier(&oidc.Config{ClientID: oauth.OAuthProviders.MicrosoftConfig.ClientID})
|
||||||
|
|
||||||
|
// Extract the ID Token from OAuth2 token.
|
||||||
|
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||||
|
if !ok {
|
||||||
|
log.Debug("Failed to extract ID Token from OAuth2 token")
|
||||||
|
return user, fmt.Errorf("unable to extract id_token")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse and verify ID Token payload.
|
||||||
|
idToken, err := verifier.Verify(ctx, rawIDToken)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to verify ID Token: ", err)
|
||||||
|
return user, fmt.Errorf("unable to verify id_token: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := idToken.Claims(&user); err != nil {
|
||||||
|
log.Debug("Failed to parse ID Token claims: ", err)
|
||||||
|
return user, fmt.Errorf("unable to extract claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
@@ -209,6 +209,24 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
|||||||
// check: https://github.com/golang/oauth2/issues/449
|
// check: https://github.com/golang/oauth2/issues/449
|
||||||
url := oauth.OAuthProviders.AppleConfig.AuthCodeURL(oauthStateString, oauth2.SetAuthURLParam("response_mode", "form_post")) + "&scope=name email"
|
url := oauth.OAuthProviders.AppleConfig.AuthCodeURL(oauthStateString, oauth2.SetAuthURLParam("response_mode", "form_post")) + "&scope=name email"
|
||||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
|
case constants.AuthRecipeMethodMicrosoft:
|
||||||
|
if oauth.OAuthProviders.MicrosoftConfig == nil {
|
||||||
|
log.Debug("Microsoft OAuth provider is not configured")
|
||||||
|
isProviderConfigured = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodMicrosoft)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error setting state: ", err)
|
||||||
|
c.JSON(500, gin.H{
|
||||||
|
"error": "internal server error",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// during the init of OAuthProvider authorizer url might be empty
|
||||||
|
oauth.OAuthProviders.MicrosoftConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodMicrosoft
|
||||||
|
url := oauth.OAuthProviders.MicrosoftConfig.AuthCodeURL(oauthStateString)
|
||||||
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
default:
|
default:
|
||||||
log.Debug("Invalid oauth provider: ", provider)
|
log.Debug("Invalid oauth provider: ", provider)
|
||||||
c.JSON(422, gin.H{
|
c.JSON(422, gin.H{
|
||||||
|
@@ -20,9 +20,11 @@ func OpenIDConfigurationHandler() gin.HandlerFunc {
|
|||||||
"token_endpoint": issuer + "/oauth/token",
|
"token_endpoint": issuer + "/oauth/token",
|
||||||
"userinfo_endpoint": issuer + "/userinfo",
|
"userinfo_endpoint": issuer + "/userinfo",
|
||||||
"jwks_uri": issuer + "/.well-known/jwks.json",
|
"jwks_uri": issuer + "/.well-known/jwks.json",
|
||||||
|
"registration_endpoint": issuer + "/app",
|
||||||
"response_types_supported": []string{"code", "token", "id_token"},
|
"response_types_supported": []string{"code", "token", "id_token"},
|
||||||
"scopes_supported": []string{"openid", "email", "profile", "email_verified", "given_name", "family_name", "nick_name", "picture"},
|
"scopes_supported": []string{"openid", "email", "profile"},
|
||||||
"response_modes_supported": []string{"query", "fragment", "form_post", "web_message"},
|
"response_modes_supported": []string{"query", "fragment", "form_post", "web_message"},
|
||||||
|
"subject_types_supported": "public",
|
||||||
"id_token_signing_alg_values_supported": []string{jwtType},
|
"id_token_signing_alg_values_supported": []string{jwtType},
|
||||||
"claims_supported": []string{"aud", "exp", "iss", "iat", "sub", "given_name", "family_name", "middle_name", "nickname", "preferred_username", "picture", "email", "email_verified", "roles", "role", "gender", "birthdate", "phone_number", "phone_number_verified", "nonce", "updated_at", "created_at", "revoked_timestamp", "login_method", "signup_methods", "token_type"},
|
"claims_supported": []string{"aud", "exp", "iss", "iat", "sub", "given_name", "family_name", "middle_name", "nickname", "preferred_username", "picture", "email", "email_verified", "roles", "role", "gender", "birthdate", "phone_number", "phone_number_verified", "nonce", "updated_at", "created_at", "revoked_timestamp", "login_method", "signup_methods", "token_type"},
|
||||||
})
|
})
|
||||||
|
@@ -247,8 +247,8 @@ func TokenHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt)
|
||||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt)
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
|
||||||
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||||
@@ -259,14 +259,14 @@ func TokenHandler() gin.HandlerFunc {
|
|||||||
res := map[string]interface{}{
|
res := map[string]interface{}{
|
||||||
"access_token": authToken.AccessToken.Token,
|
"access_token": authToken.AccessToken.Token,
|
||||||
"id_token": authToken.IDToken.Token,
|
"id_token": authToken.IDToken.Token,
|
||||||
"scope": scope,
|
"scope": strings.Join(scope, " "),
|
||||||
"roles": roles,
|
"roles": roles,
|
||||||
"expires_in": expiresIn,
|
"expires_in": expiresIn,
|
||||||
}
|
}
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
res["refresh_token"] = authToken.RefreshToken.Token
|
res["refresh_token"] = authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
gc.JSON(http.StatusOK, res)
|
gc.JSON(http.StatusOK, res)
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -39,7 +40,27 @@ func UserInfoHandler() gin.HandlerFunc {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
apiUser := user.AsAPIUser()
|
||||||
gc.JSON(http.StatusOK, user.AsAPIUser())
|
userBytes, err := json.Marshal(apiUser)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error marshalling user: ", err)
|
||||||
|
gc.JSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := map[string]interface{}{}
|
||||||
|
err = json.Unmarshal(userBytes, &res)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error un-marshalling user: ", err)
|
||||||
|
gc.JSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// add sub field to user as per openid standards
|
||||||
|
// https://github.com/authorizerdev/authorizer/issues/327
|
||||||
|
res["sub"] = userID
|
||||||
|
gc.JSON(http.StatusOK, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,21 +24,22 @@ import (
|
|||||||
// It verifies email based on JWT token in query string
|
// It verifies email based on JWT token in query string
|
||||||
func VerifyEmailHandler() gin.HandlerFunc {
|
func VerifyEmailHandler() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
redirectURL := strings.TrimSpace(c.Query("redirect_uri"))
|
||||||
errorRes := gin.H{
|
errorRes := gin.H{
|
||||||
"error": "invalid_token",
|
"error": "token is required",
|
||||||
}
|
}
|
||||||
tokenInQuery := c.Query("token")
|
tokenInQuery := c.Query("token")
|
||||||
if tokenInQuery == "" {
|
if tokenInQuery == "" {
|
||||||
log.Debug("Token is empty")
|
log.Debug("Token is empty")
|
||||||
c.JSON(400, errorRes)
|
utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
verificationRequest, err := db.Provider.GetVerificationRequestByToken(c, tokenInQuery)
|
verificationRequest, err := db.Provider.GetVerificationRequestByToken(c, tokenInQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error getting verification request: ", err)
|
log.Debug("Error getting verification request: ", err)
|
||||||
errorRes["error_description"] = err.Error()
|
errorRes["error"] = err.Error()
|
||||||
c.JSON(400, errorRes)
|
utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,23 +48,23 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
|||||||
claim, err := token.ParseJWTToken(tokenInQuery)
|
claim, err := token.ParseJWTToken(tokenInQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error parsing token: ", err)
|
log.Debug("Error parsing token: ", err)
|
||||||
errorRes["error_description"] = err.Error()
|
errorRes["error"] = err.Error()
|
||||||
c.JSON(400, errorRes)
|
utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil {
|
if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil {
|
||||||
log.Debug("Error validating jwt claims: ", err)
|
log.Debug("Error validating jwt claims: ", err)
|
||||||
errorRes["error_description"] = err.Error()
|
errorRes["error"] = err.Error()
|
||||||
c.JSON(400, errorRes)
|
utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.Provider.GetUserByEmail(c, verificationRequest.Email)
|
user, err := db.Provider.GetUserByEmail(c, verificationRequest.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error getting user: ", err)
|
log.Debug("Error getting user: ", err)
|
||||||
errorRes["error_description"] = err.Error()
|
errorRes["error"] = err.Error()
|
||||||
c.JSON(400, errorRes)
|
utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +80,6 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
|||||||
db.Provider.DeleteVerificationRequest(c, verificationRequest)
|
db.Provider.DeleteVerificationRequest(c, verificationRequest)
|
||||||
|
|
||||||
state := strings.TrimSpace(c.Query("state"))
|
state := strings.TrimSpace(c.Query("state"))
|
||||||
redirectURL := strings.TrimSpace(c.Query("redirect_uri"))
|
|
||||||
rolesString := strings.TrimSpace(c.Query("roles"))
|
rolesString := strings.TrimSpace(c.Query("roles"))
|
||||||
var roles []string
|
var roles []string
|
||||||
if rolesString == "" {
|
if rolesString == "" {
|
||||||
@@ -125,8 +125,8 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
|||||||
authToken, err := token.CreateAuthToken(c, user, roles, scope, loginMethod, nonce, code)
|
authToken, err := token.CreateAuthToken(c, user, roles, scope, loginMethod, nonce, code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error creating auth token: ", err)
|
log.Debug("Error creating auth token: ", err)
|
||||||
errorRes["error_description"] = err.Error()
|
errorRes["error"] = err.Error()
|
||||||
c.JSON(500, errorRes)
|
utils.HandleRedirectORJsonResponse(c, http.StatusInternalServerError, errorRes, generateRedirectURL(redirectURL, errorRes))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
|||||||
// if code != "" {
|
// if code != "" {
|
||||||
// if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
|
// if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
|
||||||
// log.Debug("Error setting code state ", err)
|
// log.Debug("Error setting code state ", err)
|
||||||
// errorRes["error_description"] = err.Error()
|
// errorRes["error"] = err.Error()
|
||||||
// c.JSON(500, errorRes)
|
// c.JSON(500, errorRes)
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
@@ -154,12 +154,12 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
|||||||
|
|
||||||
sessionKey := loginMethod + ":" + user.ID
|
sessionKey := loginMethod + ":" + user.ID
|
||||||
cookie.SetSession(c, authToken.FingerPrintHash)
|
cookie.SetSession(c, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt)
|
||||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt)
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
params = params + `&refresh_token=` + authToken.RefreshToken.Token
|
params = params + `&refresh_token=` + authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
if redirectURL == "" {
|
if redirectURL == "" {
|
||||||
@@ -189,3 +189,21 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
|||||||
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
|
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateRedirectURL(url string, res map[string]interface{}) string {
|
||||||
|
redirectURL := url
|
||||||
|
if redirectURL == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var paramsArr []string
|
||||||
|
for key, value := range res {
|
||||||
|
paramsArr = append(paramsArr, key+"="+value.(string))
|
||||||
|
}
|
||||||
|
params := strings.Join(paramsArr, "&")
|
||||||
|
if strings.Contains(redirectURL, "?") {
|
||||||
|
redirectURL = redirectURL + "&" + params
|
||||||
|
} else {
|
||||||
|
redirectURL = redirectURL + "?" + strings.TrimPrefix(params, "&")
|
||||||
|
}
|
||||||
|
return redirectURL
|
||||||
|
}
|
||||||
|
@@ -26,6 +26,7 @@ func InitMemStore() error {
|
|||||||
|
|
||||||
// boolean envs
|
// boolean envs
|
||||||
constants.EnvKeyDisableBasicAuthentication: false,
|
constants.EnvKeyDisableBasicAuthentication: false,
|
||||||
|
constants.EnvKeyDisableMobileBasicAuthentication: false,
|
||||||
constants.EnvKeyDisableMagicLinkLogin: false,
|
constants.EnvKeyDisableMagicLinkLogin: false,
|
||||||
constants.EnvKeyDisableEmailVerification: false,
|
constants.EnvKeyDisableEmailVerification: false,
|
||||||
constants.EnvKeyDisableLoginPage: false,
|
constants.EnvKeyDisableLoginPage: false,
|
||||||
|
14
server/memorystore/providers/inmemory/provider_test.go
Normal file
14
server/memorystore/providers/inmemory/provider_test.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package inmemory
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore/providers"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInMemoryProvider(t *testing.T) {
|
||||||
|
p, err := NewInMemoryProvider()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
providers.ProviderTests(t, p)
|
||||||
|
}
|
@@ -8,44 +8,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// SetUserSession sets the user session for given user identifier in form recipe:user_id
|
// SetUserSession sets the user session for given user identifier in form recipe:user_id
|
||||||
func (c *provider) SetUserSession(userId, key, token string) error {
|
func (c *provider) SetUserSession(userId, key, token string, expiration int64) error {
|
||||||
c.sessionStore.Set(userId, key, token)
|
c.sessionStore.Set(userId, key, token, expiration)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllUserSessions returns all the user sessions token from the in-memory store.
|
|
||||||
func (c *provider) GetAllUserSessions(userId string) (map[string]string, error) {
|
|
||||||
data := c.sessionStore.GetAll(userId)
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserSession returns value for given session token
|
// GetUserSession returns value for given session token
|
||||||
func (c *provider) GetUserSession(userId, sessionToken string) (string, error) {
|
func (c *provider) GetUserSession(userId, sessionToken string) (string, error) {
|
||||||
return c.sessionStore.Get(userId, sessionToken), nil
|
val := c.sessionStore.Get(userId, sessionToken)
|
||||||
|
if val == "" {
|
||||||
|
return "", fmt.Errorf("Not found")
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAllUserSessions deletes all the user sessions from in-memory store.
|
// DeleteAllUserSessions deletes all the user sessions from in-memory store.
|
||||||
func (c *provider) DeleteAllUserSessions(userId string) error {
|
func (c *provider) DeleteAllUserSessions(userId string) error {
|
||||||
namespaces := []string{
|
c.sessionStore.RemoveAll(userId)
|
||||||
constants.AuthRecipeMethodBasicAuth,
|
|
||||||
constants.AuthRecipeMethodMagicLinkLogin,
|
|
||||||
constants.AuthRecipeMethodApple,
|
|
||||||
constants.AuthRecipeMethodFacebook,
|
|
||||||
constants.AuthRecipeMethodGithub,
|
|
||||||
constants.AuthRecipeMethodGoogle,
|
|
||||||
constants.AuthRecipeMethodLinkedIn,
|
|
||||||
constants.AuthRecipeMethodTwitter,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, namespace := range namespaces {
|
|
||||||
c.sessionStore.RemoveAll(namespace + ":" + userId)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUserSession deletes the user session from the in-memory store.
|
// DeleteUserSession deletes the user session from the in-memory store.
|
||||||
func (c *provider) DeleteUserSession(userId, sessionToken string) error {
|
func (c *provider) DeleteUserSession(userId, sessionToken string) error {
|
||||||
c.sessionStore.Remove(userId, sessionToken)
|
c.sessionStore.Remove(userId, constants.TokenTypeSessionToken+"_"+sessionToken)
|
||||||
|
c.sessionStore.Remove(userId, constants.TokenTypeAccessToken+"_"+sessionToken)
|
||||||
|
c.sessionStore.Remove(userId, constants.TokenTypeRefreshToken+"_"+sessionToken)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user