diff --git a/.dockerignore b/.dockerignore index 5773072bc..0b168cd02 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,6 +7,12 @@ ROADMAP.md build .env data.db -app/node_modules -app/build +web/app/node_modules +web/app/build +web/app/.vite +web/dashboard/node_modules +web/dashboard/build +web/dashboard/.vite certs/ +*.log +.DS_Store diff --git a/.gitignore b/.gitignore index 8009af8c0..9b21a6753 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,10 @@ server/server server/.env data -app/node_modules -app/build -dashboard/node_modules -dashboard/build +web/app/node_modules +web/app/build +web/dashboard/node_modules +web/dashboard/build build .env data.db @@ -20,3 +20,4 @@ certs/ *-wal .idea *.iml +node_modules/* \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 2c3aacba3..cc6fbe903 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,35 +1,54 @@ -FROM golang:1.21.3-alpine3.18 as go-builder +FROM golang:1.25.5-alpine3.23 as go-builder WORKDIR /authorizer -COPY server server -COPY Makefile . + +# Copy go mod files for dependency resolution +COPY go.mod go.sum ./ + +# Download dependencies +RUN go mod download + +# Copy source code +COPY main.go ./ +COPY cmd/ ./cmd/ +COPY internal/ ./internal/ +COPY gqlgen.yml ./ ARG VERSION="latest" ENV VERSION="$VERSION" RUN echo "$VERSION" -RUN apk add build-base &&\ - make clean && make && \ +# Build the server binary +RUN apk add build-base && \ + go build -ldflags "-w -X main.VERSION=$(VERSION)" -o build/server . && \ chmod 777 build/server -FROM node:20-alpine3.18 as node-builder +FROM node:25-alpine3.22 as node-builder WORKDIR /authorizer -COPY app app -COPY dashboard dashboard -COPY Makefile . -RUN apk add build-base &&\ - make build-app && \ - make build-dashboard +# Copy package files first for better layer caching +COPY web/app/package*.json web/app/ +COPY web/dashboard/package*.json web/dashboard/ +# Install dependencies +RUN cd web/app && npm ci && \ + cd ../dashboard && npm ci +# Copy source files +COPY web/app web/app +COPY web/dashboard web/dashboard +# Build applications +RUN cd web/app && npm run build && \ + cd ../dashboard && npm run build -FROM alpine:3.18 +FROM alpine:3.23 RUN adduser -D -h /authorizer -u 1000 -k /dev/null authorizer WORKDIR /authorizer -RUN mkdir app dashboard -COPY --from=node-builder --chown=nobody:nobody /authorizer/app/build app/build -COPY --from=node-builder --chown=nobody:nobody /authorizer/app/favicon_io app/favicon_io -COPY --from=node-builder --chown=nobody:nobody /authorizer/dashboard/build dashboard/build -COPY --from=node-builder --chown=nobody:nobody /authorizer/dashboard/favicon_io dashboard/favicon_io +RUN mkdir -p web/app web/dashboard +COPY --from=node-builder --chown=nobody:nobody /authorizer/web/app/build web/app/build +COPY --from=node-builder --chown=nobody:nobody /authorizer/web/app/favicon_io web/app/favicon_io +COPY --from=node-builder --chown=nobody:nobody /authorizer/web/dashboard/build web/dashboard/build +COPY --from=node-builder --chown=nobody:nobody /authorizer/web/dashboard/favicon_io web/dashboard/favicon_io COPY --from=go-builder --chown=nobody:nobody /authorizer/build build -COPY templates templates -EXPOSE 8080 +COPY web/templates web/templates +EXPOSE 8080 8081 USER authorizer -CMD [ "./build/server" ] +# Use ENTRYPOINT to allow passing CLI arguments +ENTRYPOINT [ "./build/server" ] +CMD [] diff --git a/Makefile b/Makefile index e617e6157..a1946802b 100644 --- a/Makefile +++ b/Makefile @@ -10,13 +10,41 @@ build: -output="../build/{{.OS}}/{{.Arch}}/server" \ ./... build-app: - cd app && npm i && npm run build + cd web/app && npm ci && npm run build build-dashboard: - cd dashboard && npm i && npm run build + cd web/dashboard && npm ci && npm run build clean: rm -rf build +dev: + go run main.go --database-type=sqlite --database-url=test.db --jwt-type=HS256 --jwt-secret=test --admin-secret=admin --client-id=123456 --client-secret=secret +# test: +# 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 && cd server && go clean --testcache && TEST_DBS="sqlite" go test -p 1 -v ./test test: - 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 && cd server && go clean --testcache && TEST_DBS="sqlite" go test -p 1 -v ./test + docker rm -vf authorizer_postgres + docker rm -vf authorizer_scylla_db + docker rm -vf authorizer_mongodb_db + docker rm -vf authorizer_arangodb + docker rm -vf authorizer_dynamodb + docker rm -vf authorizer_couchbase + docker rm -vf authorizer_redis + docker run -d --name authorizer_redis -p 6380:6379 redis + docker run --name authorizer_postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=postgres -d postgres + docker run -d --name authorizer_scylla_db -p 9042:9042 scylladb/scylla + docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15 + docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.10.3 + docker run -d --name authorizer_dynamodb -p 8000:8000 amazon/dynamodb-local:latest + docker run -d --name authorizer_couchbase -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 + + go test -v ./... + + docker rm -vf authorizer_postgres + docker rm -vf authorizer_scylla_db + docker rm -vf authorizer_mongodb_db + docker rm -vf authorizer_arangodb + docker rm -vf authorizer_dynamodb + docker rm -vf authorizer_couchbase + docker rm -vf authorizer_redis test-mongodb: docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15 cd server && go clean --testcache && TEST_DBS="mongodb" go test -p 1 -v ./test @@ -53,7 +81,7 @@ test-all-db: docker rm -vf dynamodb-local-test docker rm -vf couchbase-local-test generate-graphql: - cd server && go run github.com/99designs/gqlgen generate && go mod tidy + go run github.com/99designs/gqlgen --verbose 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' {} \; diff --git a/ROADMAP.md b/ROADMAP.md deleted file mode 100644 index 9ce680eae..000000000 --- a/ROADMAP.md +++ /dev/null @@ -1,55 +0,0 @@ -# Roadmap for authorizer - -This document contains detailed information about the project scope and future roadmap - -## V 0.1.0 [To be released by 20-August-2021] - -- [x] Create server - - [x] Use golang as server side language - - [x] Use [gorm](https://github.com/go-gorm/gorm) as ORM - - [x] Configure https://github.com/99designs/gqlgen for generating graphql schemas - - [x] Configure https://github.com/gin-gonic/gin for creating http server - - [x] Define base schema for user - - [x] Define the auth schemes and variables required for that - - [x] Basic Auth (Username & Password based) - - [x] Google Login - - [x] Github Login - - [ ] Twitter Login - - [ ] Facebook Login - - [ ] Login with magic link (Send magic link mail) - - [x] Add [mailing server](https://github.com/emersion/go-smtp) to send the magic link - - [x] Allow configuring the master password to access the console (If not set UI console can be accessed by anyone) - - [x] Allow configuring mailing server - - [x] Allow configuring HSA Keys for oauth - - [ ] Allow configuring RSA keys for oauth - - [x] Allow configuring the DB client - - [x] Allow configuring the Secret - - [x] Allow configuring callback urls - - [x] Allow configuring redis, should be optional if not used use the memory to store session -- [x] Create Graphql mutations and query for following - - [x] Login mutation - - [x] Logout muttion - - [x] Token query :- Authorize [Currently checks for valid token & if token is present in session] - - [x] Should authorize using cookies - - [x] Should authorize using Authorization header - - [ ] Role based access [Checks for particular role in JWT] - - [x] Signup - - [x] Forgot password - - [x] Update profile -- [ ] Create a UI console to configure the above parts [For now using graphql playground] - - [ ] Create react app - - [ ] Allow user to configure above mentioned envs - - [ ] Allow user to add user - - [ ] Allow user to view users - - [ ] Allow user to define the JWT token field -- [x] A component library for react - - [x] Create AuthorizerProvider -> gives token, user, loading, setters - - [x] Create Authorizer component -> Complete Login/Signup & Forgot password solution - - [x] Create AuthorizerResetPassword component -> Component that can be used to verify forgot password token and reset the password -- [ ] Create a sdks - - [ ] NodeJS sdk which acts as a middleware and can be used to authenticate & authorize users - - [ ] Golang sdk which acts as a middleware and can be used to authenticate & authorize users -- [x] Create docker image -- [x] Create docker-compose file to quickly start this -- [x] Create heroku button -- [ ] Create a website diff --git a/TODO.md b/TODO.md deleted file mode 100644 index c7a6cfa08..000000000 --- a/TODO.md +++ /dev/null @@ -1,49 +0,0 @@ -# Task List - -## Implement better way of handling jwt tokens - -Check: https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/#server-side-rendering-ssr - -- [x] Set finger print in response cookie (https://github.com/hasura/jwt-guide/blob/60a7a86146d604fc48a799fffdee712be1c52cd0/lib/setFingerprintCookieAndSignJwt.ts#L8) -- [x] Save refresh token in session store -- [x] refresh token should be made more secure with the help of secure token rotation. Every time new token is requested new refresh token should be generated -- [x] Return jwt in response -- [x] To get session send finger print and refresh token [if they are valid -> a new access token is generated and sent to user] -- [x] Refresh token should be long living token (refresh token + finger print hash should be verified) - -## Open ID compatible claims and schema - -- [x] Rename `schema.graphqls` and re generate schema -- [x] Rename to snake case [files + schema] -- [x] Refactor db models -- [x] Check extra data in oauth profile and save accordingly -- [x] Update all the resolver to make them compatible with schema changes -- [x] Update JWT claims -- [x] Write integration tests for all resolvers - -## Feature Multiple sessions - -- Multiple sessions for users to login use hMset from redis for this - user_id access_token1 long_live_token1 - user_id access_token2 long_live_token2 - -# Feature roles - -For the first version we will only support setting roles master list via env - -- [x] Support following ENV - - [x] `ROLES` -> comma separated list of role names - - [x] `DEFAULT_ROLE` -> default role to assign to users -- [x] Add roles input for signup -- [x] Add roles to update profile mutation -- [x] Add roles input for login -- [x] Return roles to user -- [x] Return roles in users list for super admin -- [x] Add roles to the JWT token generation -- [x] Validate token should also validate the role, if roles to validate again is present in request - -# Misc - -- [x] Fix email template -- [x] Add support for organization name in .env -- [x] Add support for organization logo in .env diff --git a/app/esbuild.config.js b/app/esbuild.config.js deleted file mode 100644 index b018f0780..000000000 --- a/app/esbuild.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const __is_prod__ = process.env.NODE_ENV === 'production'; -require('esbuild').build({ - entryPoints: ['src/index.tsx'], - chunkNames: '[name]-[hash]', - bundle: true, - minify: __is_prod__, - outdir: 'build', - splitting: true, - format: 'esm', - watch: !__is_prod__, -}); diff --git a/app/package-lock.json b/app/package-lock.json deleted file mode 100644 index b0236f651..000000000 --- a/app/package-lock.json +++ /dev/null @@ -1,879 +0,0 @@ -{ - "name": "app", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "app", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@authorizerdev/authorizer-react": "^1.3.2", - "@types/react": "^17.0.15", - "@types/react-dom": "^17.0.9", - "esbuild": "^0.12.17", - "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" - }, - "devDependencies": { - "@types/react-router-dom": "^5.1.8", - "@types/styled-components": "^5.1.11", - "prettier": "2.7.1" - } - }, - "node_modules/@authorizerdev/authorizer-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-2.0.3.tgz", - "integrity": "sha512-uencwr3Ea8mwfxVKDFf2ITRCRSmzvua+O2voRuiWQORtRQTgZQjkN3M+IEkEj+WP9M1iFIl+NDgzECsp8ptC/A==", - "dependencies": { - "cross-fetch": "^3.1.5" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/authorizerdev" - } - }, - "node_modules/@authorizerdev/authorizer-react": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.3.2.tgz", - "integrity": "sha512-3kMAygHBCa8Fc9Oo0lz1k88r+Pd6kx1PSn3NMYLwxQXy2jRt4xWn7iuGn+SDGFs3DzofaN71I61gRwQ+6dO1rw==", - "dependencies": { - "@authorizerdev/authorizer-js": "^2.0.3", - "validator": "^13.11.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": ">=16" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", - "dependencies": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz", - "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@emotion/is-prop-valid": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", - "dependencies": { - "@emotion/memoize": "0.7.4" - } - }, - "node_modules/@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" - }, - "node_modules/@emotion/stylis": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", - "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" - }, - "node_modules/@emotion/unitless": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@types/history": { - "version": "4.7.9", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz", - "integrity": "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==", - "dev": true - }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", - "dev": true, - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" - }, - "node_modules/@types/react": { - "version": "17.0.15", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.15.tgz", - "integrity": "sha512-uTKHDK9STXFHLaKv6IMnwp52fm0hwU+N89w/p9grdUqcFA6WuqDyPhaWopbNyE1k/VhgzmHl8pu1L4wITtmlLw==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", - "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react-router": { - "version": "5.1.16", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz", - "integrity": "sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg==", - "dev": true, - "dependencies": { - "@types/history": "*", - "@types/react": "*" - } - }, - "node_modules/@types/react-router-dom": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.8.tgz", - "integrity": "sha512-03xHyncBzG0PmDmf8pf3rehtjY0NpUj7TIN46FrT5n1ZWHPZvXz32gUyNboJ+xsL8cpg8bQVLcllptcQHvocrw==", - "dev": true, - "dependencies": { - "@types/history": "*", - "@types/react": "*", - "@types/react-router": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "node_modules/@types/styled-components": { - "version": "5.1.25", - "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.25.tgz", - "integrity": "sha512-fgwl+0Pa8pdkwXRoVPP9JbqF0Ivo9llnmsm+7TCI330kbPIFd9qv1Lrhr37shf4tnxCOSu+/IgqM7uJXLWZZNQ==", - "dev": true, - "dependencies": { - "@types/hoist-non-react-statics": "*", - "@types/react": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/babel-plugin-styled-components": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.2.tgz", - "integrity": "sha512-7eG5NE8rChnNTDxa6LQfynwgHTVOYYaHJbUYSlOhk8QBXIQiMBKq4gyfHBBKPrxUcVBXVJL61ihduCpCQbuNbw==", - "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" - }, - "peerDependencies": { - "styled-components": ">= 2" - } - }, - "node_modules/babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" - }, - "node_modules/camelize": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", - "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/cross-fetch": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", - "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", - "dependencies": { - "node-fetch": "^2.6.12" - } - }, - "node_modules/css-color-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", - "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=", - "engines": { - "node": ">=4" - } - }, - "node_modules/css-to-react-native": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", - "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", - "dependencies": { - "camelize": "^1.0.0", - "css-color-keywords": "^1.0.0", - "postcss-value-parser": "^4.0.2" - } - }, - "node_modules/csstype": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", - "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" - }, - "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/esbuild": { - "version": "0.12.17", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.17.tgz", - "integrity": "sha512-GshKJyVYUnlSXIZj/NheC2O0Kblh42CS7P1wJyTbbIHevTG4jYMS9NNw8EOd8dDWD0dzydYHS01MpZoUcQXB4g==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "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" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dependencies": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" - }, - "peerDependencies": { - "prop-types": "^15.0.0", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "node_modules/react-router": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", - "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", - "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" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/react-router-dom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", - "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", - "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" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/react-router/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, - "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" - }, - "node_modules/styled-components": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz", - "integrity": "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==", - "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" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/styled-components" - }, - "peerDependencies": { - "react": ">= 16.8.0", - "react-dom": ">= 16.8.0", - "react-is": ">= 16.8.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tiny-invariant": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", - "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" - }, - "node_modules/tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "engines": { - "node": ">=4" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/typescript": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", - "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/validator": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", - "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - } -} diff --git a/app/package.json b/app/package.json deleted file mode 100644 index a3167c3e5..000000000 --- a/app/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "app", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "build": "rm -rf build && NODE_ENV=production node ./esbuild.config.js", - "start": "NODE_ENV=development node ./esbuild.config.js", - "format": "prettier --write 'src/**/*.(ts|tsx|js|jsx)'" - }, - "keywords": [], - "author": "Lakhan Samani", - "license": "ISC", - "dependencies": { - "@authorizerdev/authorizer-react": "^1.3.2", - "@types/react": "^17.0.15", - "@types/react-dom": "^17.0.9", - "esbuild": "^0.12.17", - "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" - }, - "devDependencies": { - "@types/react-router-dom": "^5.1.8", - "@types/styled-components": "^5.1.11", - "prettier": "2.7.1" - } -} diff --git a/app/pnpm-lock.yaml b/app/pnpm-lock.yaml deleted file mode 100644 index 87aacf458..000000000 --- a/app/pnpm-lock.yaml +++ /dev/null @@ -1,626 +0,0 @@ -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 diff --git a/app/src/index.tsx b/app/src/index.tsx deleted file mode 100644 index 5d76a18a8..000000000 --- a/app/src/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './App'; -import './index.css'; - -ReactDOM.render(, document.getElementById('root')); diff --git a/app/tsconfig.json b/app/tsconfig.json deleted file mode 100644 index 99dc84c6e..000000000 --- a/app/tsconfig.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ - // "lib": ["es2018", "dom"], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - // "outDir": "./", /* Redirect output structure to the directory. */ - "rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ - - /* Module Resolution Options */ - // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - - /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - - /* Advanced Options */ - "skipLibCheck": true, /* Skip type checking of declaration files. */ - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ - } -} diff --git a/app/yarn.lock b/app/yarn.lock deleted file mode 100644 index f09e1cfff..000000000 --- a/app/yarn.lock +++ /dev/null @@ -1,619 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@authorizerdev/authorizer-js@^2.0.3": - version "2.0.3" - resolved "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-2.0.3.tgz" - integrity sha512-uencwr3Ea8mwfxVKDFf2ITRCRSmzvua+O2voRuiWQORtRQTgZQjkN3M+IEkEj+WP9M1iFIl+NDgzECsp8ptC/A== - dependencies: - cross-fetch "^3.1.5" - -"@authorizerdev/authorizer-react@^1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.3.2.tgz" - integrity sha512-3kMAygHBCa8Fc9Oo0lz1k88r+Pd6kx1PSn3NMYLwxQXy2jRt4xWn7iuGn+SDGFs3DzofaN71I61gRwQ+6dO1rw== - dependencies: - "@authorizerdev/authorizer-js" "^2.0.3" - validator "^13.11.0" - -"@babel/code-frame@^7.22.13": - version "7.22.13" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz" - integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== - dependencies: - "@babel/highlight" "^7.22.13" - chalk "^2.4.2" - -"@babel/generator@^7.23.0": - version "7.23.0" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz" - integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== - dependencies: - "@babel/types" "^7.23.0" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/helper-annotate-as-pure@^7.16.0": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz" - integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.0": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz" - integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/highlight@^7.22.13": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz" - integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.22.15", "@babel/parser@^7.23.0": - version "7.23.0" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz" - integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== - -"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1": - version "7.14.8" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz" - integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.22.15": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz" - integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/traverse@^7.4.5": - version "7.23.2" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz" - integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.23.0" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.0" - "@babel/types" "^7.23.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.16.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0": - version "7.23.0" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz" - integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== - dependencies: - "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@emotion/is-prop-valid@^0.8.8": - version "0.8.8" - resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz" - integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== - dependencies: - "@emotion/memoize" "0.7.4" - -"@emotion/memoize@0.7.4": - version "0.7.4" - resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz" - integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== - -"@emotion/stylis@^0.8.4": - version "0.8.5" - resolved "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz" - integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== - -"@emotion/unitless@^0.7.4": - version "0.7.5" - resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz" - integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== - -"@jridgewell/gen-mapping@^0.3.2": - version "0.3.3" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== - -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.20" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz" - integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@types/history@*": - version "4.7.9" - resolved "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz" - integrity sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ== - -"@types/hoist-non-react-statics@*": - version "3.3.1" - resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== - dependencies: - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - -"@types/prop-types@*": - version "15.7.4" - resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz" - integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== - -"@types/react-dom@^17.0.9": - version "17.0.9" - resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz" - integrity sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg== - dependencies: - "@types/react" "*" - -"@types/react-router-dom@^5.1.8": - version "5.1.8" - resolved "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.8.tgz" - integrity sha512-03xHyncBzG0PmDmf8pf3rehtjY0NpUj7TIN46FrT5n1ZWHPZvXz32gUyNboJ+xsL8cpg8bQVLcllptcQHvocrw== - dependencies: - "@types/history" "*" - "@types/react" "*" - "@types/react-router" "*" - -"@types/react-router@*": - version "5.1.16" - resolved "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz" - integrity sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg== - dependencies: - "@types/history" "*" - "@types/react" "*" - -"@types/react@*", "@types/react@^17.0.15": - version "17.0.15" - resolved "https://registry.npmjs.org/@types/react/-/react-17.0.15.tgz" - integrity sha512-uTKHDK9STXFHLaKv6IMnwp52fm0hwU+N89w/p9grdUqcFA6WuqDyPhaWopbNyE1k/VhgzmHl8pu1L4wITtmlLw== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - -"@types/scheduler@*": - version "0.16.2" - resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== - -"@types/styled-components@^5.1.11": - version "5.1.25" - resolved "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.25.tgz" - integrity sha512-fgwl+0Pa8pdkwXRoVPP9JbqF0Ivo9llnmsm+7TCI330kbPIFd9qv1Lrhr37shf4tnxCOSu+/IgqM7uJXLWZZNQ== - dependencies: - "@types/hoist-non-react-statics" "*" - "@types/react" "*" - csstype "^3.0.2" - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -"babel-plugin-styled-components@>= 1.12.0": - version "2.0.2" - resolved "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.2.tgz" - integrity sha512-7eG5NE8rChnNTDxa6LQfynwgHTVOYYaHJbUYSlOhk8QBXIQiMBKq4gyfHBBKPrxUcVBXVJL61ihduCpCQbuNbw== - 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: - version "6.18.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz" - integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= - -camelize@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz" - integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -cross-fetch@^3.1.5: - version "3.1.8" - resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz" - integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== - dependencies: - node-fetch "^2.6.12" - -css-color-keywords@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz" - integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU= - -css-to-react-native@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz" - integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ== - dependencies: - camelize "^1.0.0" - css-color-keywords "^1.0.0" - postcss-value-parser "^4.0.2" - -csstype@^3.0.2: - version "3.0.8" - resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz" - integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw== - -debug@^4.1.0: - version "4.3.3" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -esbuild@^0.12.17: - version "0.12.17" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.12.17.tgz" - integrity sha512-GshKJyVYUnlSXIZj/NheC2O0Kblh42CS7P1wJyTbbIHevTG4jYMS9NNw8EOd8dDWD0dzydYHS01MpZoUcQXB4g== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -history@^4.9.0: - version "4.10.1" - resolved "https://registry.npmjs.org/history/-/history-4.10.1.tgz" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - 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: - version "3.3.2" - resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -lodash@^4.17.11: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -mini-create-react-context@^0.4.0: - version "0.4.1" - resolved "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz" - integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== - dependencies: - "@babel/runtime" "^7.12.1" - tiny-warning "^1.0.3" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -node-fetch@^2.6.12: - version "2.7.0" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - -postcss-value-parser@^4.0.2: - version "4.2.0" - resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" - integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== - -prettier@2.7.1: - version "2.7.1" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz" - integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== - -prop-types@^15.0.0, prop-types@^15.6.2: - version "15.7.2" - resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== - 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": - version "17.0.2" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" - -react-is@^16.6.0: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-is@^16.7.0: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-is@^16.8.1: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-is@^17.0.2, "react-is@>= 16.8.0": - version "17.0.2" - resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - -react-router-dom@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz" - integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== - 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: - version "5.2.0" - resolved "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz" - integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== - 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: - version "17.0.2" - resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== - -resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -shallowequal@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz" - integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== - -styled-components@^5.3.0, "styled-components@>= 2": - version "5.3.3" - resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz" - integrity sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw== - 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: - version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -tiny-invariant@^1.0.2: - version "1.1.0" - resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz" - integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== - -tiny-warning@^1.0.0, tiny-warning@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -typescript@^4.3.5: - version "4.3.5" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz" - integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== - -validator@^13.11.0: - version "13.11.0" - resolved "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz" - integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== - -value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 000000000..804ef31d7 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,334 @@ +package cmd + +import ( + "context" + "os" + "os/signal" + "strings" + "time" + + "github.com/rs/zerolog" + "github.com/spf13/cobra" + "golang.org/x/sync/errgroup" + + "github.com/authorizerdev/authorizer/internal/authenticators" + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/email" + "github.com/authorizerdev/authorizer/internal/events" + "github.com/authorizerdev/authorizer/internal/http_handlers" + "github.com/authorizerdev/authorizer/internal/memory_store" + "github.com/authorizerdev/authorizer/internal/oauth" + "github.com/authorizerdev/authorizer/internal/server" + "github.com/authorizerdev/authorizer/internal/sms" + "github.com/authorizerdev/authorizer/internal/storage" + "github.com/authorizerdev/authorizer/internal/token" +) + +var ( + RootCmd = cobra.Command{ + Use: "authorizer", + Run: runRoot, + } + rootArgs struct { + logLevel string + config config.Config + server server.Config + } +) + +func init() { + f := RootCmd.Flags() + + // Server flags + f.StringVar(&rootArgs.server.Host, "host", "0.0.0.0", "Host address to listen on") + f.IntVar(&rootArgs.server.HTTPPort, "http-port", 8080, "Port to serve HTTP requests on") + f.IntVar(&rootArgs.server.MetricsPort, "metrics-port", 8081, "Port to serve metrics requests on") + + // Logging flags + f.StringVar(&rootArgs.logLevel, "log-level", "debug", "Log level to use") + + // Env + f.StringVar(&rootArgs.config.Env, "env", "", "Environment of the authorizer instance") + + // Http routes + f.BoolVar(&rootArgs.config.EnableLoginPage, "enable-login-page", true, "Enable login page") + f.BoolVar(&rootArgs.config.EnablePlayground, "enable-playground", true, "Enable playground") + + // Organization flags + f.StringVar(&rootArgs.config.OrganizationLogo, "organization-logo", "https://authorizer.dev/images/logo.png", "Logo of the organization") + f.StringVar(&rootArgs.config.OrganizationName, "organization-name", "Authorizer", "Name of the organization") + + // OAuth flags + f.StringVar(&rootArgs.config.ClientID, "client-id", "", "Client ID for the OAuth") + f.StringVar(&rootArgs.config.ClientSecret, "client-secret", "", "Client secret for the OAuth") + f.StringVar(&rootArgs.config.DefaultAuthorizeResponseMode, "default-authorize-response-mode", constants.ResponseModeQuery, "Default response mode for the authorize endpoint") + f.StringVar(&rootArgs.config.DefaultAuthorizeResponseType, "default-authorize-response-type", constants.ResponseTypeToken, "Default response type for the authorize endpoint") + + // Admin flags + f.StringVar(&rootArgs.config.AdminSecret, "admin-secret", "password", "Secret for the admin") + + // Allowed origins + f.StringSliceVar(&rootArgs.config.AllowedOrigins, "allowed-origins", []string{"*"}, "Allowed origins") + + // Database flags + f.StringVar(&rootArgs.config.DatabaseType, "database-type", "", "Type of database to use") + f.StringVar(&rootArgs.config.DatabaseURL, "database-url", "", "URL of the database") + f.StringVar(&rootArgs.config.DatabaseName, "database-name", "", "Name of the database") + f.StringVar(&rootArgs.config.DatabaseUsername, "database-username", "", "Username for the database") + f.StringVar(&rootArgs.config.DatabasePassword, "database-password", "", "Password for the database") + f.StringVar(&rootArgs.config.DatabaseHost, "database-host", "", "Host for the database") + f.IntVar(&rootArgs.config.DatabasePort, "database-port", 0, "Port for the database") + f.StringVar(&rootArgs.config.DatabaseCert, "database-cert", "", "Certificate for the database") + f.StringVar(&rootArgs.config.DatabaseCACert, "database-ca-cert", "", "CA certificate for the database") + f.StringVar(&rootArgs.config.DatabaseCertKey, "database-cert-key", "", "Certificate key for the database") + f.StringVar(&rootArgs.config.CouchBaseBucket, "couchbase-bucket", "", "Bucket for the database") + f.StringVar(&rootArgs.config.CouchBaseRamQuota, "couchbase-ram-quota", "", "RAM quota for the database") + f.StringVar(&rootArgs.config.CouchBaseScope, "couchbase-scope", "", "Scope for the database") + f.StringVar(&rootArgs.config.AWSRegion, "aws-region", "", "Region for the dynamodb database") + f.StringVar(&rootArgs.config.AWSAccessKeyID, "aws-access-key-id", "", "Access key ID for the dynamodb database") + f.StringVar(&rootArgs.config.AWSSecretAccessKey, "aws-secret-access-key", "", "Secret access key for the dynamodb database") + + // Memory store flags + f.StringVar(&rootArgs.config.RedisURL, "redis-url", "", "URL of the redis server") + + // Email flags + f.StringVar(&rootArgs.config.SMTPHost, "smtp-host", "", "Host for the SMTP server") + f.IntVar(&rootArgs.config.SMTPPort, "smtp-port", 0, "Port for the SMTP server") + f.StringVar(&rootArgs.config.SMTPUsername, "smtp-username", "", "Username for the SMTP server") + f.StringVar(&rootArgs.config.SMTPPassword, "smtp-password", "", "Password for the SMTP server") + f.StringVar(&rootArgs.config.SMTPSenderEmail, "smtp-sender-email", "", "Sender email for the SMTP server") + f.StringVar(&rootArgs.config.SMTPSenderName, "smtp-sender-name", "", "Sender name for the SMTP server") + f.StringVar(&rootArgs.config.SMTPLocalName, "smtp-local-name", "", "Local name for the SMTP server") + f.BoolVar(&rootArgs.config.SkipTLSVerification, "skip-tls-verification", false, "Skip TLS verification for the SMTP server") + + // Auth flags + f.StringSliceVar(&rootArgs.config.DefaultRoles, "default-roles", []string{"user"}, "Default user roles to assign") + f.StringSliceVar(&rootArgs.config.Roles, "roles", []string{"user"}, "Roles to assign") + f.StringSliceVar(&rootArgs.config.ProtectedRoles, "protected-roles", []string{}, "Roles that cannot be deleted") + f.BoolVar(&rootArgs.config.EnableStrongPassword, "enable-strong-password", true, "Enable strong password requirement") + f.BoolVar(&rootArgs.config.EnableTOTPLogin, "enable-totp-login", false, "Enable TOTP login") + f.BoolVar(&rootArgs.config.EnableBasicAuthentication, "enable-basic-authentication", true, "Enable basic authentication") + f.BoolVar(&rootArgs.config.EnableEmailVerification, "enable-email-verification", false, "Enable email verification") + f.BoolVar(&rootArgs.config.EnableMobileBasicAuthentication, "enable-mobile-basic-authentication", true, "Enable mobile basic authentication") + f.BoolVar(&rootArgs.config.EnablePhoneVerification, "enable-phone-verification", false, "Enable phone verification") + f.BoolVar(&rootArgs.config.EnableMagicLinkLogin, "enable-magic-link-login", false, "Enable magic link login") + f.BoolVar(&rootArgs.config.EnforceMFA, "enforce-mfa", true, "Enforce MFA for all users") + f.BoolVar(&rootArgs.config.EnableMFA, "enable-mfa", false, "Enable MFA for all users") + f.BoolVar(&rootArgs.config.EnableEmailOTP, "enable-email-otp", false, "Enable email OTP") + f.BoolVar(&rootArgs.config.EnableSMSOTP, "enable-sms-otp", false, "Enable SMS OTP") + f.BoolVar(&rootArgs.config.EnableSignup, "enable-signup", true, "Enable signup") + + // Cookies flags + f.BoolVar(&rootArgs.config.AppCookieSecure, "app-cookie-secure", true, "Application secure cookie flag") + f.BoolVar(&rootArgs.config.AdminCookieSecure, "admin-cookie-secure", true, "Admin secure cookie flag") + + // JWT flags + f.StringVar(&rootArgs.config.JWTType, "jwt-type", "", "Type of JWT to use") + f.StringVar(&rootArgs.config.JWTSecret, "jwt-secret", "", "Secret for the JWT") + f.StringVar(&rootArgs.config.JWTPrivateKey, "jwt-private-key", "", "Private key for the JWT") + f.StringVar(&rootArgs.config.JWTPublicKey, "jwt-public-key", "", "Public key for the JWT") + f.StringVar(&rootArgs.config.JWTRoleClaim, "jwt-role-claim", "role", "Role claim for the JWT") + f.StringVar(&rootArgs.config.CustomAccessTokenScript, "custom-access-token-script", "", "Custom access token script") + + // Twilio flags + f.StringVar(&rootArgs.config.TwilioAccountSID, "twilio-account-sid", "", "Account SID for Twilio") + f.StringVar(&rootArgs.config.TwilioAPIKey, "twilio-api-key", "", "API key for Twilio") + f.StringVar(&rootArgs.config.TwilioAPISecret, "twilio-api-secret", "", "API secret for Twilio") + f.StringVar(&rootArgs.config.TwilioSender, "twilio-sender", "", "Sender for Twilio") + + // Oauth provider flags + f.StringVar(&rootArgs.config.GoogleClientID, "google-client-id", "", "Client ID for Google") + f.StringVar(&rootArgs.config.GoogleClientSecret, "google-client-secret", "", "Client secret for Google") + f.StringSliceVar(&rootArgs.config.GoogleScopes, "google-scopes", []string{"openid", "profile", "email"}, "Scopes for Google") + f.StringVar(&rootArgs.config.GithubClientID, "github-client-id", "", "Client ID for Github") + f.StringVar(&rootArgs.config.GithubClientSecret, "github-client-secret", "", "Client secret for Github") + f.StringSliceVar(&rootArgs.config.GithubScopes, "github-scopes", []string{"read:user", "user:email"}, "Scopes for Github") + f.StringVar(&rootArgs.config.FacebookClientID, "facebook-client-id", "", "Client ID for Facebook") + f.StringVar(&rootArgs.config.FacebookClientSecret, "facebook-client-secret", "", "Client secret for Facebook") + f.StringSliceVar(&rootArgs.config.FacebookScopes, "facebook-scopes", []string{"public_profile", "email"}, "Scopes for Facebook") + f.StringVar(&rootArgs.config.MicrosoftClientID, "microsoft-client-id", "", "Client ID for Microsoft") + f.StringVar(&rootArgs.config.MicrosoftClientSecret, "microsoft-client-secret", "", "Client secret for Microsoft") + f.StringVar(&rootArgs.config.MicrosoftTenantID, "microsoft-tenant-id", "common", "Tenant ID for Microsoft") + f.StringSliceVar(&rootArgs.config.MicrosoftScopes, "microsoft-scopes", []string{"openid", "profile", "email"}, "Scopes for Microsoft") + f.StringVar(&rootArgs.config.TwitchClientID, "twitch-client-id", "", "Client ID for Twitch") + f.StringVar(&rootArgs.config.TwitchClientSecret, "twitch-client-secret", "", "Client secret for Twitch") + f.StringSliceVar(&rootArgs.config.TwitchScopes, "twitch-scopes", []string{"openid", "user:read:email"}, "Scopes for Twitch") + f.StringVar(&rootArgs.config.LinkedinClientID, "linkedin-client-id", "", "Client ID for Linkedin") + f.StringVar(&rootArgs.config.LinkedinClientSecret, "linkedin-client-secret", "", "Client secret for Linkedin") + f.StringSliceVar(&rootArgs.config.LinkedinScopes, "linkedin-scopes", []string{"r_liteprofile", "r_emailaddress"}, "Scopes for Linkedin") + f.StringVar(&rootArgs.config.AppleClientID, "apple-client-id", "", "Client ID for Apple") + f.StringVar(&rootArgs.config.AppleClientSecret, "apple-client-secret", "", "Client secret for Apple") + f.StringSliceVar(&rootArgs.config.AppleScopes, "apple-scopes", []string{"email", "name"}, "Scopes for Apple") + f.StringVar(&rootArgs.config.DiscordClientID, "discord-client-id", "", "Client ID for Discord") + f.StringVar(&rootArgs.config.DiscordClientSecret, "discord-client-secret", "", "Client secret for Discord") + f.StringSliceVar(&rootArgs.config.DiscordScopes, "discord-scopes", []string{"identify", "email"}, "Scopes for Discord") + f.StringVar(&rootArgs.config.TwitterClientID, "twitter-client-id", "", "Client ID for Twitter") + f.StringVar(&rootArgs.config.TwitterClientSecret, "twitter-client-secret", "", "Client secret for Twitter") + f.StringSliceVar(&rootArgs.config.TwitterScopes, "twitter-scopes", []string{"tweet.read", "users.read"}, "Scopes for Twitter") + f.StringVar(&rootArgs.config.RobloxClientID, "roblox-client-id", "", "Client ID for Roblox") + f.StringVar(&rootArgs.config.RobloxClientSecret, "roblox-client-secret", "", "Client secret for Roblox") + f.StringSliceVar(&rootArgs.config.RobloxScopes, "roblox-scopes", []string{"openid", "profile"}, "Scopes for Roblox") + + // URLs + f.StringVar(&rootArgs.config.ResetPasswordURL, "reset-password-url", "", "URL for reset password") + + // Deprecated flags + f.MarkDeprecated("database_url", "use --database-url instead") + f.MarkDeprecated("database_type", "use --database-type instead") + f.MarkDeprecated("env_file", "no more supported") + f.MarkDeprecated("log_level", "use --log-level instead") + f.MarkDeprecated("redis_url", "use --redis-url instead") +} + +// Run the service +func runRoot(c *cobra.Command, args []string) { + // Prepare logger + ctx := context.Background() + // Parse the log level + zeroLogLevel, err := zerolog.ParseLevel(rootArgs.logLevel) + if err != nil { + // If the log level is invalid, set it to debug + zeroLogLevel = zerolog.DebugLevel + } + // Create a new console writer + // consoleWriter := zerolog.New(os.Stdout) + // consoleWriter.NoColor = true + // consoleWriter.TimeFormat = time.RFC3339 + // consoleWriter.TimeLocation = time.UTC + zerolog.TimestampFunc = func() time.Time { + return time.Now().UTC() + } + log := zerolog.New(os.Stdout). + Level(zeroLogLevel). + With().Timestamp().Logger() + + // Storage provider + storageProvider, err := storage.New(&rootArgs.config, &storage.Dependencies{ + Log: &log, + }) + if err != nil { + log.Fatal().Err(err).Msg("failed to create storage provider") + } + + // Authenticator provider + authenticatorProvider, err := authenticators.New(&rootArgs.config, &authenticators.Dependencies{ + Log: &log, + StorageProvider: storageProvider, + }) + if err != nil { + log.Fatal().Err(err).Msg("failed to create authenticator provider") + } + + // Email provider + emailProvider, err := email.New(&rootArgs.config, &email.Dependencies{ + Log: &log, + StorageProvider: storageProvider, + }) + if err != nil { + log.Fatal().Err(err).Msg("failed to create email provider") + } + + // Events provider + eventsProvider, err := events.New(&rootArgs.config, &events.Dependencies{ + Log: &log, + StorageProvider: storageProvider, + }) + if err != nil { + log.Fatal().Err(err).Msg("failed to create events provider") + } + + // Memory store provider + memoryStoreProvider, err := memory_store.New(&rootArgs.config, &memory_store.Dependencies{ + Log: &log, + }) + if err != nil { + log.Fatal().Err(err).Msg("failed to create memory store provider") + } + + // SMS provider + smsProvider, err := sms.New(&rootArgs.config, &sms.Dependencies{ + Log: &log, + }) + if err != nil { + log.Fatal().Err(err).Msg("failed to create sms provider") + } + + // Token provider + tokenProvider, err := token.New(&rootArgs.config, &token.Dependencies{ + Log: &log, + MemoryStoreProvider: memoryStoreProvider, + }) + if err != nil { + log.Fatal().Err(err).Msg("failed to create token provider") + } + // OAuth provider + oauthProvider, err := oauth.New(&rootArgs.config, &oauth.Dependencies{ + Log: &log, + }) + if err != nil { + log.Fatal().Err(err).Msg("failed to create oauth provider") + } + + // Ensure client ID and secret are set for authorizer instance + if strings.TrimSpace(rootArgs.config.ClientID) == "" { + log.Fatal().Msg("client ID missing in rootArgs") + } + + if strings.TrimSpace(rootArgs.config.ClientSecret) == "" { + log.Fatal().Msg("client secret missing in rootArgs") + } + + httpProvider, err := http_handlers.New(&rootArgs.config, &http_handlers.Dependencies{ + Log: &log, + AuthenticatorProvider: authenticatorProvider, + EmailProvider: emailProvider, + EventsProvider: eventsProvider, + MemoryStoreProvider: memoryStoreProvider, + SMSProvider: smsProvider, + StorageProvider: storageProvider, + TokenProvider: tokenProvider, + OAuthProvider: oauthProvider, + }) + if err != nil { + log.Fatal().Err(err).Msg("failed to create http provider") + } + // Prepare server + deps := &server.Dependencies{ + Log: &log, + HTTPProvider: httpProvider, + } + // Create the server + svr, err := server.New(&rootArgs.server, deps) + if err != nil { + log.Fatal().Err(err).Msg("failed to create server") + } + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + g, ctx := errgroup.WithContext(ctx) + g.Go(func() error { + return svr.Run(ctx) + }) + + // Setup signal handler to allow for graceful termination + sigCtx, stop := signal.NotifyContext(ctx, os.Interrupt) + + // Wait for interrupt or failure in errgroup. + select { + case <-sigCtx.Done(): + log.Info().Msg("Signal received, shutting down...") + // Unregister signal handlers. + // Next interrupt signal will kill us. + cancel() + stop() + case <-ctx.Done(): + // Errgroup context canceled + } + + // Wait for all routines to end + if err := g.Wait(); err != nil { + log.Fatal().Err(err).Msg("Application failed") + } + log.Info().Msg("Application terminated") +} diff --git a/dashboard/esbuild.config.js b/dashboard/esbuild.config.js deleted file mode 100644 index 40fe8390f..000000000 --- a/dashboard/esbuild.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const __is_prod__ = process.env.NODE_ENV === 'production'; -require('esbuild').build({ - entryPoints: ['src/index.tsx'], - chunkNames: '[name]-[hash]', - bundle: true, - minify: __is_prod__, - outdir: 'build', - splitting: true, - format: 'esm', - watch: !__is_prod__, - logLevel: 'info', -}); diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json deleted file mode 100644 index 0e1bbfb49..000000000 --- a/dashboard/package-lock.json +++ /dev/null @@ -1,3092 +0,0 @@ -{ - "name": "dashboard", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "dashboard", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@chakra-ui/react": "^1.7.3", - "@emotion/core": "^11.0.0", - "@emotion/react": "^11.7.1", - "@emotion/styled": "^11.6.0", - "@types/react": "^17.0.38", - "@types/react-dom": "^17.0.11", - "@types/react-router-dom": "^5.3.2", - "dayjs": "^1.10.7", - "esbuild": "^0.14.9", - "focus-visible": "^5.2.0", - "framer-motion": "^5.5.5", - "graphql": "^16.2.0", - "lodash": "^4.17.21", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "react-draft-wysiwyg": "^1.15.0", - "react-dropzone": "^12.0.4", - "react-email-editor": "^1.6.1", - "react-icons": "^4.3.1", - "react-router-dom": "^6.2.1", - "typescript": "^4.5.4", - "urql": "^2.0.6" - }, - "devDependencies": { - "@types/react-email-editor": "^1.1.7", - "prettier": "2.7.1" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", - "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", - "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", - "peer": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.3", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.3", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.3", - "@babel/types": "^7.23.3", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "peer": true - }, - "node_modules/@babel/generator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", - "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", - "peer": true, - "dependencies": { - "@babel/types": "^7.23.3", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "peer": true, - "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "peer": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "peer": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "peer": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz", - "integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "peer": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "peer": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", - "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", - "peer": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", - "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", - "peer": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.5.tgz", - "integrity": "sha512-42OGssv9NPk4QHKVgIHlzeLgPOW5rGgfV5jzG90AhcXXIv6hu/eqj63w4VgvRxdvZY3AlYeDgPiSJ3BqAd1Y6Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", - "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", - "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.3", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.3", - "@babel/types": "^7.23.3", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", - "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@chakra-ui/accordion": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/accordion/-/accordion-1.4.2.tgz", - "integrity": "sha512-BAGMvcm2sFE5Ft7jwC9nF03/Yv7qztuhzwKBBy4iL0p1nCPh6kV54RBXUcoj3VWe+yrmNiAVYKRTdqQBTJFwOw==", - "dependencies": { - "@chakra-ui/descendant": "2.1.1", - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/icon": "2.0.0", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/transition": "1.4.2", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/alert": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/alert/-/alert-1.3.2.tgz", - "integrity": "sha512-+OMeVeGtydpj6nry0zH7qFDt36zEaxckRnufx1BGiCfWdUg6ahVwKXl8qX93Q8w82od7eAoBKMgGJz7IVL5NPw==", - "dependencies": { - "@chakra-ui/icon": "2.0.0", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/anatomy": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/anatomy/-/anatomy-1.2.1.tgz", - "integrity": "sha512-kNS+FiEDTSnwpQUW4dEjZ5745xhkvB0XtmqjY1wpclUSpFfptLZM9QIHPTnBt2bzM9R+idmRRP+WkTt6kyTrLw==", - "dependencies": { - "@chakra-ui/theme-tools": "^1.3.1" - } - }, - "node_modules/@chakra-ui/avatar": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/avatar/-/avatar-1.3.1.tgz", - "integrity": "sha512-WI0/kcpTJViOH093V0bz8EB+e/rc+gjF+T5DkOuh1YWFxRRG5v+4Yd3PdEJtQgzWtBVhlbGWmE7WvBizyKwFCA==", - "dependencies": { - "@chakra-ui/image": "1.1.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/breadcrumb": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/breadcrumb/-/breadcrumb-1.3.1.tgz", - "integrity": "sha512-b1IoBmtr5FcP2fn5NRbdOdQo2c866OQ/WhcTcZ6UKae1jjik+36/qWE+X+RKzxC6FLfqo5qayV5zSgsnZym7Pg==", - "dependencies": { - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/button": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/button/-/button-1.5.1.tgz", - "integrity": "sha512-BvP29quEhP6OTgDiRsugD6adgkeOTEQpoDsZUVEmHnNVrbFfdsICEKKQTtDJ2iPf+hmpFrtnpN50vCLdAANKcw==", - "dependencies": { - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/spinner": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/checkbox": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/checkbox/-/checkbox-1.6.1.tgz", - "integrity": "sha512-Z5ZMeUYIRjRbi/knhYhSQshZH7OnROA7ezl9a9oVSKRF7iLMNMibQSlQLXmqUWaTKSgrS37cpKAzfgEuemyiUQ==", - "dependencies": { - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1", - "@chakra-ui/visually-hidden": "1.1.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "framer-motion": "3.x || 4.x || 5.x", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/clickable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/clickable/-/clickable-1.2.1.tgz", - "integrity": "sha512-B0CIbKzDMwzG1APeTpW9H2Jl8dkarI1Qstb3hDOy23O+N5TU6lpDdVnXQ7fpFJS6mu5JjFqtkwzGAVZnkkv1rw==", - "dependencies": { - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/close-button": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/close-button/-/close-button-1.2.2.tgz", - "integrity": "sha512-SqeLib0qgMjK3OsO1g5OnAHUmdCC8GMjToNEea7TeSrA44bH9EXVhFTkMMu2PnDVHbQmi4Ee1cuulNJt0UhQ3g==", - "dependencies": { - "@chakra-ui/icon": "2.0.0", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/color-mode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/color-mode/-/color-mode-1.3.2.tgz", - "integrity": "sha512-/rWcbrzbaWCyyUnT07Qjz0xf/ltHS31CHOKtVCWr2uTgfn2gOQpdxsKRbjrLYPOYZGTMdINUHNiAsqQjLoAoTQ==", - "dependencies": { - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/react-env": "1.1.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/control-box": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/control-box/-/control-box-1.1.1.tgz", - "integrity": "sha512-ZFbh85pzzZoiSjGnvLUzMB5BoA8Xm6TBMWvMtzLY5xiFGb9/mBeRDH2KFjr1GJzoqleWKkQwvFD6JM0kXcekpg==", - "dependencies": { - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/counter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/counter/-/counter-1.2.1.tgz", - "integrity": "sha512-Gm4njMzEsDyAzdQtExn40TvmupzkPBrT5DiCu0DlxYqpLqCfqV49HgJHEG5oW3WV+WaC9mzg7VV+idKYh/d+Gg==", - "dependencies": { - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/css-reset": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz", - "integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg==", - "peerDependencies": { - "@emotion/react": ">=10.0.35", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/descendant": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/descendant/-/descendant-2.1.1.tgz", - "integrity": "sha512-JasdVaN4MjL7QFo1vMnADy6EtFAlPKT1kTJ1LwMtl9AaF9VFLBsfGxm0L+WQK+3NJMuCSDBXWJB8mV4AQ11Edg==", - "dependencies": { - "@chakra-ui/react-utils": "^1.2.1" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/editable": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/editable/-/editable-1.3.1.tgz", - "integrity": "sha512-MwyTtsnHNqmKmHv9SH3KIHWa06D4gBwcuTawTiSnYBUJL6My8ry/Wdca1to9So2tD6hcjz3TPTzOJOlyv0eiZg==", - "dependencies": { - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/focus-lock": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/focus-lock/-/focus-lock-1.2.1.tgz", - "integrity": "sha512-HYu39nvfaXUrBx+dIDJkFgebNCGEi9oZTfLUKzIJC+zPkmReTDSXV0dzSb/8vCAOq5fph1gFKsdbGy2U98P8GQ==", - "dependencies": { - "@chakra-ui/utils": "1.9.1", - "react-focus-lock": "2.5.2" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/form-control": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/form-control/-/form-control-1.5.2.tgz", - "integrity": "sha512-uWv0/f+JEM0ZE5Hnj3TzCnJ09EB+A+DSs9QgyECOuxx9Ju6gnns2uaRki2BfxksQL9ZZomPCkMtXazY9Wa81ag==", - "dependencies": { - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/icon": "2.0.0", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/hooks": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/hooks/-/hooks-1.7.1.tgz", - "integrity": "sha512-hgN19X6GUKQYAHczmFY+GAT8vl9h+X+nGWrIAnmvZ6BgUXxDajnTNhZeWhj0ZkR+7A7dCE6Y/3X44GafUgChMw==", - "dependencies": { - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1", - "compute-scroll-into-view": "1.0.14", - "copy-to-clipboard": "3.3.1" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/icon": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@chakra-ui/icon/-/icon-2.0.0.tgz", - "integrity": "sha512-/GuU+xIcOIy9uSUUUCu249ZJB/nLDbjWGkfpoSdBwqT4+ytJrKt+0Ckh3Ub14sz3BJD+Z6IiIt6ySOA9+7lbsA==", - "dependencies": { - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/image": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/image/-/image-1.1.1.tgz", - "integrity": "sha512-bz1pn08XlXcO3r1KnpdjQgN3R2soiTx10sG2d5Pw9BdGdySf7Y73wiLh+Tan1xJHp6p2KH1hz4f7uKXXDn7Qmw==", - "dependencies": { - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/input": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/input/-/input-1.3.2.tgz", - "integrity": "sha512-VMxmQgFiQ2UnBlkgLX/336G0IfYfw8YWF2ZoEFj5WL9kDSrrL1FXSBgjFGxrper74G4W20tESBCfU1S891y6cg==", - "dependencies": { - "@chakra-ui/form-control": "1.5.2", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/layout": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@chakra-ui/layout/-/layout-1.6.0.tgz", - "integrity": "sha512-WUfQ104y1wNueU33/hPlZsMzYJGjO0dXMpVkQf5ZNhNX3IGDO+5+MO2x2xloP+j45yNPi3p8ti/HBnm3dXI+3Q==", - "dependencies": { - "@chakra-ui/icon": "2.0.0", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/live-region": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/live-region/-/live-region-1.1.1.tgz", - "integrity": "sha512-BSdI5gLIffNRETEp6W18kBNg9tL0ZLLzfWGRnuO9tEbox7NrcgqIeLF8mNKwhDOZz88NKHtUOPVzjAUKW1SryQ==", - "dependencies": { - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/media-query": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/media-query/-/media-query-1.2.2.tgz", - "integrity": "sha512-xSmDVleE1drWiGH/MX3RqyVm29x/8Vf6G0UGaI2kCpbNmon+Q1zHW/yDHvptIuctLrPHYO8LOBxuUjfnIXwC2g==", - "dependencies": { - "@chakra-ui/react-env": "1.1.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "@chakra-ui/theme": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/menu": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/menu/-/menu-1.8.2.tgz", - "integrity": "sha512-u2GfkwTqbWa8L/7i/kOFbU3JANiT2HStR+gsYKuiuOPiuBcUb8OlgfJfP70OtVKegNKmVEMjvzXtld3wCCo/1g==", - "dependencies": { - "@chakra-ui/clickable": "1.2.1", - "@chakra-ui/descendant": "2.1.1", - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/popper": "2.4.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/transition": "1.4.2", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "framer-motion": "3.x || 4.x || 5.x", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/modal": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/modal/-/modal-1.10.2.tgz", - "integrity": "sha512-ZlmYetPHwHW4CAM09j4/+Ui54dXR1nzU6mOwhWe4/IzLvEyoEU6fHJeKyGxVUpYTG/7wltG/wKFRJpYa77tiBg==", - "dependencies": { - "@chakra-ui/close-button": "1.2.2", - "@chakra-ui/focus-lock": "1.2.1", - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/portal": "1.3.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/transition": "1.4.2", - "@chakra-ui/utils": "1.9.1", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.4.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "framer-motion": "3.x || 4.x || 5.x", - "react": ">=16.8.6", - "react-dom": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/number-input": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/number-input/-/number-input-1.3.2.tgz", - "integrity": "sha512-7x7AoqwPXU1odyDcqIwjBwf0MJUwYMM2fa+6YZ52F941GKlvkDiiJOhK6xfhhBzkLUQD6DN8zgAmmGhaZ6UQXw==", - "dependencies": { - "@chakra-ui/counter": "1.2.1", - "@chakra-ui/form-control": "1.5.2", - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/icon": "2.0.0", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/pin-input": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/pin-input/-/pin-input-1.7.1.tgz", - "integrity": "sha512-eFFc5sofiyion+NxELWfCzD23XHIBDrJcfKKbNxt8jdXg9Ek4mFpmvnxBVrK0DIz6cVYgKY8c364OmxNUf4IyA==", - "dependencies": { - "@chakra-ui/descendant": "2.1.1", - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/popover": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@chakra-ui/popover/-/popover-1.11.0.tgz", - "integrity": "sha512-cCHXAfhIRir+M0ehlYIjDw3mHpiCxDTJ9WV0H1zHQV8nDYVIlZw3nEntaq8oJrv0wpIzq2WCW5ss+bBR7nLZ1A==", - "dependencies": { - "@chakra-ui/close-button": "1.2.2", - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/popper": "2.4.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "framer-motion": "3.x || 4.x || 5.x", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/popper": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/popper/-/popper-2.4.1.tgz", - "integrity": "sha512-cuwnwXx6RUXZGGynVOGG8fEIiMNBXUCy3UqWQD1eEd8200eWQobgNk4Z0YwzKuSzJwp0Auy+j5iKefi5FSkyog==", - "dependencies": { - "@chakra-ui/react-utils": "1.2.1", - "@popperjs/core": "^2.9.3" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/portal": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/portal/-/portal-1.3.1.tgz", - "integrity": "sha512-6UOGZCfujgdijcPs/JTEY5IB5WtKvUbfrSQYsG5CDa+guIwvnoP5qZ+rH6BR6DSSM8Wr/1n+WrtanhfFZShHKA==", - "dependencies": { - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "react": ">=16.8.6", - "react-dom": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/progress": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/progress/-/progress-1.2.1.tgz", - "integrity": "sha512-213nN8nbODvD/A23vAtg+r3bRKKatWQHafgmLzeznUcxa/+ac0eVurIS8XSYLRkY4EXQ505re3ZkLhDd98a7QA==", - "dependencies": { - "@chakra-ui/theme-tools": "1.3.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/provider": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@chakra-ui/provider/-/provider-1.7.3.tgz", - "integrity": "sha512-D1SrQ7do4yzAv9/OTF3yj/BkLm7kFo5DdeuOCyvXGpVJumnvbtjltRmC7rFQH4R+y9qXPvfQP4LKMNBqSxPNng==", - "dependencies": { - "@chakra-ui/css-reset": "1.1.1", - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/portal": "1.3.1", - "@chakra-ui/react-env": "1.1.1", - "@chakra-ui/system": "1.8.3", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@emotion/react": "^11.0.0", - "@emotion/styled": "^11.0.0", - "react": ">=16.8.6", - "react-dom": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/radio": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@chakra-ui/radio/-/radio-1.4.3.tgz", - "integrity": "sha512-TQdyfdUD3BLklOP67n82JN8ksQv1BYjvaYsK0m6WCa0LDJr9aCC+XtUPgVq/1L2t4HqHdiGOrGBooF4vvy/+BA==", - "dependencies": { - "@chakra-ui/form-control": "1.5.2", - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1", - "@chakra-ui/visually-hidden": "1.1.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/react": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@chakra-ui/react/-/react-1.7.3.tgz", - "integrity": "sha512-6mrfDUOa9MoQ44Xvi7xgdDq48jTTTjW9BupCGf2R3DI+z6RbUKIHzbcoDJZt2HGY6j9EarMVNRoQJzvzGUKpoQ==", - "dependencies": { - "@chakra-ui/accordion": "1.4.2", - "@chakra-ui/alert": "1.3.2", - "@chakra-ui/avatar": "1.3.1", - "@chakra-ui/breadcrumb": "1.3.1", - "@chakra-ui/button": "1.5.1", - "@chakra-ui/checkbox": "1.6.1", - "@chakra-ui/close-button": "1.2.2", - "@chakra-ui/control-box": "1.1.1", - "@chakra-ui/counter": "1.2.1", - "@chakra-ui/css-reset": "1.1.1", - "@chakra-ui/editable": "1.3.1", - "@chakra-ui/form-control": "1.5.2", - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/icon": "2.0.0", - "@chakra-ui/image": "1.1.1", - "@chakra-ui/input": "1.3.2", - "@chakra-ui/layout": "1.6.0", - "@chakra-ui/live-region": "1.1.1", - "@chakra-ui/media-query": "1.2.2", - "@chakra-ui/menu": "1.8.2", - "@chakra-ui/modal": "1.10.2", - "@chakra-ui/number-input": "1.3.2", - "@chakra-ui/pin-input": "1.7.1", - "@chakra-ui/popover": "1.11.0", - "@chakra-ui/popper": "2.4.1", - "@chakra-ui/portal": "1.3.1", - "@chakra-ui/progress": "1.2.1", - "@chakra-ui/provider": "1.7.3", - "@chakra-ui/radio": "1.4.3", - "@chakra-ui/react-env": "1.1.1", - "@chakra-ui/select": "1.2.2", - "@chakra-ui/skeleton": "1.2.3", - "@chakra-ui/slider": "1.5.2", - "@chakra-ui/spinner": "1.2.1", - "@chakra-ui/stat": "1.2.2", - "@chakra-ui/switch": "1.3.1", - "@chakra-ui/system": "1.8.3", - "@chakra-ui/table": "1.3.1", - "@chakra-ui/tabs": "1.6.1", - "@chakra-ui/tag": "1.2.2", - "@chakra-ui/textarea": "1.2.2", - "@chakra-ui/theme": "1.12.2", - "@chakra-ui/toast": "1.5.0", - "@chakra-ui/tooltip": "1.4.2", - "@chakra-ui/transition": "1.4.2", - "@chakra-ui/utils": "1.9.1", - "@chakra-ui/visually-hidden": "1.1.1" - }, - "peerDependencies": { - "@emotion/react": "^11.0.0", - "@emotion/styled": "^11.0.0", - "framer-motion": "3.x || 4.x || 5.x", - "react": ">=16.8.6", - "react-dom": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/react-env": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/react-env/-/react-env-1.1.1.tgz", - "integrity": "sha512-Lgmb0y4kv0ffsGMelAOaYOd4tYZAv4FYWgV86ckGMjmYQWA8drv4v/lHTNltixxWMmBEpjcHALpJuS6yAZYHug==", - "dependencies": { - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/react-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/react-utils/-/react-utils-1.2.1.tgz", - "integrity": "sha512-bV8FRaXiOgGxOg03iTNin/B02I+tHH9PQtqUTl3U7cJaoI+5AUYhrqXvl1Ya2/R7zxSFrb/gBVDTgbZiVkJ+Dg==", - "dependencies": { - "@chakra-ui/utils": "^1.9.1" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/select": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/select/-/select-1.2.2.tgz", - "integrity": "sha512-EchJW3St1DtSWHe//DHwKjGsQYL2zbKcNCLnJWQKGMPZsQhAD2wsm4xjowFrV8AkY7jbVM/U2v68puN7YTC3hg==", - "dependencies": { - "@chakra-ui/form-control": "1.5.2", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/skeleton": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@chakra-ui/skeleton/-/skeleton-1.2.3.tgz", - "integrity": "sha512-u5ASkzPiBjfvKxKuBienUfmyYDTHziSWQ8Ny6k83LbwLv9IcmBNGsSkmsp7hesgi9cMHGBQ3hY2GTqG9ljndIg==", - "dependencies": { - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/media-query": "1.2.2", - "@chakra-ui/system": "1.8.3", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/slider": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/slider/-/slider-1.5.2.tgz", - "integrity": "sha512-zP07TMew61GkJe47Nu7zEg/SUEwPHpN4alW6VUM6Y8UaVpQaDx7InarbWTc/bXdTP03SfE+hQ6WD9Oy7noe4hQ==", - "dependencies": { - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/spinner": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/spinner/-/spinner-1.2.1.tgz", - "integrity": "sha512-CQsUJNJWWSot1ku5Se41Nz1dXIDhk+/7FIhTbfRHSjtYZnAab3CPMHBkTGqwbJxQ9oHYgk9Rso3cfG+/ra6aTQ==", - "dependencies": { - "@chakra-ui/utils": "1.9.1", - "@chakra-ui/visually-hidden": "1.1.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/stat": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/stat/-/stat-1.2.2.tgz", - "integrity": "sha512-0StsPDC56MjzhdlBl0R8wU0uwj9L1tvhQzge/ELSDn4tQDI7VovrxpFzVH0qsj7EZDwZa0BRQaSrstzWvgmJ/Q==", - "dependencies": { - "@chakra-ui/icon": "2.0.0", - "@chakra-ui/utils": "1.9.1", - "@chakra-ui/visually-hidden": "1.1.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/styled-system": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@chakra-ui/styled-system/-/styled-system-1.15.0.tgz", - "integrity": "sha512-LnsKeiYkUuJ+NMTwueiX0Mj8CW9XAMJrJxpQm/X3GY5L5PO7Hv6wW725Ovqdy4mhG3IK7S8444FthpsDv/luHw==", - "dependencies": { - "@chakra-ui/utils": "1.9.1", - "csstype": "^3.0.9" - } - }, - "node_modules/@chakra-ui/switch": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/switch/-/switch-1.3.1.tgz", - "integrity": "sha512-92hXJ2/ozj7B3cJNT259mFNoad7Ck892uHTuEQ/GIdXb25doE6F1wCp0TreOnGiEgU5YSaxpdrcZjA0QODP//w==", - "dependencies": { - "@chakra-ui/checkbox": "1.6.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/system": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@chakra-ui/system/-/system-1.8.3.tgz", - "integrity": "sha512-6MaevsT7A2ifgOGQQCQsfvzPVd0kEXqFrX1Oxd842bawaqthmbFdo2bBTdaia/+Ivq/8Xot2uAQSbU+3NuRiUA==", - "dependencies": { - "@chakra-ui/color-mode": "1.3.2", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/styled-system": "1.15.0", - "@chakra-ui/utils": "1.9.1", - "react-fast-compare": "3.2.0" - }, - "peerDependencies": { - "@emotion/react": "^11.0.0", - "@emotion/styled": "^11.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/table": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/table/-/table-1.3.1.tgz", - "integrity": "sha512-+ia/7zs7AGj01lon301EEx+mK4918yGc0K6e68Kxomex8tnxkwbskFWs6hX+6Kzbj56ZBm99eLlKpo2iGYX0HA==", - "dependencies": { - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/tabs": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/tabs/-/tabs-1.6.1.tgz", - "integrity": "sha512-p7HdHcleJWNwteWYVPt2KF52YbS5pIIfs/IpgtnYZRsJbqvRVxSwgg5Wsn+vuxFXBKW0cA2rDGbyzsZ+ChtEXQ==", - "dependencies": { - "@chakra-ui/clickable": "1.2.1", - "@chakra-ui/descendant": "2.1.1", - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/tag": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/tag/-/tag-1.2.2.tgz", - "integrity": "sha512-H25y9nEyUAUdwQDND9P4mMXKf1wf9UH4A3DyP237qVKIyYBpa4aCH8eJU4dunh2yIzASB0DWcr7lsul/HAHxmg==", - "dependencies": { - "@chakra-ui/icon": "2.0.0", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/textarea": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/textarea/-/textarea-1.2.2.tgz", - "integrity": "sha512-DoLdKxHk0DyrQDnj1la9wjl2AW3/SK62nfWDYLAm0ouFsw1VKPw9nU+Yyj0dPruQTzI19nLaYF26i97rtnT27g==", - "dependencies": { - "@chakra-ui/form-control": "1.5.2", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/theme": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/theme/-/theme-1.12.2.tgz", - "integrity": "sha512-LVjSf16yYHD40ILrsDEd3idVQRvJSY7JY8lvTGWo2p6v+JQESWF+zXlYi9Le+TXRpZuFvJuuQ1SEvoqVwdcJ8Q==", - "dependencies": { - "@chakra-ui/anatomy": "1.2.1", - "@chakra-ui/theme-tools": "1.3.1", - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0" - } - }, - "node_modules/@chakra-ui/theme-tools": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/theme-tools/-/theme-tools-1.3.1.tgz", - "integrity": "sha512-D8arJ5uFGuYZrrFGpXqgov8FhsJYWRyar5oBZY5TJR9gsVYBlJ8Ai91pwM/NflCFqzerTOgyt7bNSGQMdZ8ghA==", - "dependencies": { - "@chakra-ui/utils": "1.9.1", - "@ctrl/tinycolor": "^3.4.0" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0" - } - }, - "node_modules/@chakra-ui/toast": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@chakra-ui/toast/-/toast-1.5.0.tgz", - "integrity": "sha512-rTsFx/Qos5oVPN6aZMbT/wTxwZlFNSXQqrTpJYaRcRFQGzxIDDxmGkKYfPnyJjRP9i6EqynJhXEIyhMA0xO0dw==", - "dependencies": { - "@chakra-ui/alert": "1.3.2", - "@chakra-ui/close-button": "1.2.2", - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/theme": "1.12.2", - "@chakra-ui/transition": "1.4.2", - "@chakra-ui/utils": "1.9.1", - "@reach/alert": "0.13.2" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "framer-motion": "3.x || 4.x || 5.x", - "react": ">=16.8.6", - "react-dom": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/tooltip": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/tooltip/-/tooltip-1.4.2.tgz", - "integrity": "sha512-+wyYXG8qenKkFy2YSFfOBf3rlWADnu6S9EUxP+3Rmm78unOWXDuTJWzqy2QlXs2BwoQoifaz1LVwzmMb7WLVgQ==", - "dependencies": { - "@chakra-ui/hooks": "1.7.1", - "@chakra-ui/popper": "2.4.1", - "@chakra-ui/portal": "1.3.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/utils": "1.9.1", - "@chakra-ui/visually-hidden": "1.1.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "framer-motion": "3.x || 4.x || 5.x", - "react": ">=16.8.6", - "react-dom": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/transition": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@chakra-ui/transition/-/transition-1.4.2.tgz", - "integrity": "sha512-S+BNmpErHlntl//uaqv0sJegzMsQms0OnJapeZaRsvZL4s1SVYrR8kMrXigkdpeh4lAUqGsLpQHPKkzaKGbBOw==", - "dependencies": { - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "framer-motion": "3.x || 4.x || 5.x", - "react": ">=16.8.6" - } - }, - "node_modules/@chakra-ui/utils": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/utils/-/utils-1.9.1.tgz", - "integrity": "sha512-Tue8JfpzOqeHd8vSqAnX1l/Y3Gg456+BXFP/TH6mCIeqMAMbrvv25vDskds0wlXRjMYdmpqHxCEzkalFrscGHA==", - "dependencies": { - "@types/lodash.mergewith": "4.6.6", - "css-box-model": "1.2.1", - "framesync": "5.3.0", - "lodash.mergewith": "4.6.2" - } - }, - "node_modules/@chakra-ui/visually-hidden": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@chakra-ui/visually-hidden/-/visually-hidden-1.1.1.tgz", - "integrity": "sha512-AGK9YBQS2FW/1e5tfivS8VVXn8y2uTyJ9ACOnGiLm9FNdth9pR0fGil9axlcmhZpEYcSRlnCuma3nkqaCjJnAA==", - "dependencies": { - "@chakra-ui/utils": "1.9.1" - }, - "peerDependencies": { - "@chakra-ui/system": ">=1.0.0", - "react": ">=16.8.6" - } - }, - "node_modules/@ctrl/tinycolor": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz", - "integrity": "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/@emotion/babel-plugin": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz", - "integrity": "sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ==", - "dependencies": { - "@babel/helper-module-imports": "^7.12.13", - "@babel/plugin-syntax-jsx": "^7.12.13", - "@babel/runtime": "^7.13.10", - "@emotion/hash": "^0.8.0", - "@emotion/memoize": "^0.7.5", - "@emotion/serialize": "^1.0.2", - "babel-plugin-macros": "^2.6.1", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.0.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@emotion/cache": { - "version": "11.7.1", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz", - "integrity": "sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==", - "dependencies": { - "@emotion/memoize": "^0.7.4", - "@emotion/sheet": "^1.1.0", - "@emotion/utils": "^1.0.0", - "@emotion/weak-memoize": "^0.2.5", - "stylis": "4.0.13" - } - }, - "node_modules/@emotion/core": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/@emotion/core/-/core-11.0.0.tgz", - "integrity": "sha512-w4sE3AmHmyG6RDKf6mIbtHpgJUSJ2uGvPQb8VXFL7hFjMPibE8IiehG8cMX3Ztm4svfCQV6KqusQbeIOkurBcA==" - }, - "node_modules/@emotion/hash": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", - "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" - }, - "node_modules/@emotion/is-prop-valid": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.1.tgz", - "integrity": "sha512-bW1Tos67CZkOURLc0OalnfxtSXQJMrAMV0jZTVGJUPSOd4qgjF3+tTD5CwJM13PHA8cltGW1WGbbvV9NpvUZPw==", - "dependencies": { - "@emotion/memoize": "^0.7.4" - } - }, - "node_modules/@emotion/memoize": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", - "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" - }, - "node_modules/@emotion/react": { - "version": "11.7.1", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.7.1.tgz", - "integrity": "sha512-DV2Xe3yhkF1yT4uAUoJcYL1AmrnO5SVsdfvu+fBuS7IbByDeTVx9+wFmvx9Idzv7/78+9Mgx2Hcmr7Fex3tIyw==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@emotion/cache": "^11.7.1", - "@emotion/serialize": "^1.0.2", - "@emotion/sheet": "^1.1.0", - "@emotion/utils": "^1.0.0", - "@emotion/weak-memoize": "^0.2.5", - "hoist-non-react-statics": "^3.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/serialize": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz", - "integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==", - "dependencies": { - "@emotion/hash": "^0.8.0", - "@emotion/memoize": "^0.7.4", - "@emotion/unitless": "^0.7.5", - "@emotion/utils": "^1.0.0", - "csstype": "^3.0.2" - } - }, - "node_modules/@emotion/sheet": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz", - "integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" - }, - "node_modules/@emotion/styled": { - "version": "11.6.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.6.0.tgz", - "integrity": "sha512-mxVtVyIOTmCAkFbwIp+nCjTXJNgcz4VWkOYQro87jE2QBTydnkiYusMrRGFtzuruiGK4dDaNORk4gH049iiQuw==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@emotion/babel-plugin": "^11.3.0", - "@emotion/is-prop-valid": "^1.1.1", - "@emotion/serialize": "^1.0.2", - "@emotion/utils": "^1.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "@emotion/react": "^11.0.0-rc.0", - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/unitless": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" - }, - "node_modules/@emotion/utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz", - "integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==" - }, - "node_modules/@emotion/weak-memoize": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", - "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" - }, - "node_modules/@graphql-typed-document-node/core": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz", - "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==", - "peerDependencies": { - "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "peer": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "peer": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@popperjs/core": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.0.tgz", - "integrity": "sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@reach/alert": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@reach/alert/-/alert-0.13.2.tgz", - "integrity": "sha512-LDz83AXCrClyq/MWe+0vaZfHp1Ytqn+kgL5VxG7rirUvmluWaj/snxzfNPWn0Ma4K2YENmXXRC/iHt5X95SqIg==", - "dependencies": { - "@reach/utils": "0.13.2", - "@reach/visually-hidden": "0.13.2", - "prop-types": "^15.7.2", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "react": "^16.8.0 || 17.x", - "react-dom": "^16.8.0 || 17.x" - } - }, - "node_modules/@reach/utils": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@reach/utils/-/utils-0.13.2.tgz", - "integrity": "sha512-3ir6cN60zvUrwjOJu7C6jec/samqAeyAB12ZADK+qjnmQPdzSYldrFWwDVV5H0WkhbYXR3uh+eImu13hCetNPQ==", - "dependencies": { - "@types/warning": "^3.0.0", - "tslib": "^2.1.0", - "warning": "^4.0.3" - }, - "peerDependencies": { - "react": "^16.8.0 || 17.x", - "react-dom": "^16.8.0 || 17.x" - } - }, - "node_modules/@reach/visually-hidden": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@reach/visually-hidden/-/visually-hidden-0.13.2.tgz", - "integrity": "sha512-sPZwNS0/duOuG0mYwE5DmgEAzW9VhgU3aIt1+mrfT/xiT9Cdncqke+kRBQgU708q/Ttm9tWsoHni03nn/SuPTQ==", - "dependencies": { - "prop-types": "^15.7.2", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "react": "^16.8.0 || 17.x", - "react-dom": "^16.8.0 || 17.x" - } - }, - "node_modules/@types/history": { - "version": "4.7.9", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz", - "integrity": "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==" - }, - "node_modules/@types/lodash": { - "version": "4.14.178", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", - "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==" - }, - "node_modules/@types/lodash.mergewith": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/@types/lodash.mergewith/-/lodash.mergewith-4.6.6.tgz", - "integrity": "sha512-RY/8IaVENjG19rxTZu9Nukqh0W2UrYgmBj5sdns4hWRZaV8PqR7wIKHFKzvOTjo4zVRV7sVI+yFhAJql12Kfqg==", - "dependencies": { - "@types/lodash": "*" - } - }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" - }, - "node_modules/@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" - }, - "node_modules/@types/react": { - "version": "17.0.38", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.38.tgz", - "integrity": "sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "17.0.11", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz", - "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react-email-editor": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@types/react-email-editor/-/react-email-editor-1.1.7.tgz", - "integrity": "sha512-OURTAgaE9pjA6KiU97k13fPdoglI1ZyowUuZ0nu5tTSyrw5PiZoYzYEf9y25YTjmw/ohxT5yqoP0tt+AjSh1qQ==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react-router": { - "version": "5.1.17", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz", - "integrity": "sha512-RNSXOyb3VyRs/EOGmjBhhGKTbnN6fHWvy5FNLzWfOWOGjgVUKqJZXfpKzLmgoU8h6Hj8mpALj/mbXQASOb92wQ==", - "dependencies": { - "@types/history": "*", - "@types/react": "*" - } - }, - "node_modules/@types/react-router-dom": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.2.tgz", - "integrity": "sha512-ELEYRUie2czuJzaZ5+ziIp9Hhw+juEw8b7C11YNA4QdLCVbQ3qLi2l4aq8XnlqM7V31LZX8dxUuFUCrzHm6sqQ==", - "dependencies": { - "@types/history": "*", - "@types/react": "*", - "@types/react-router": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "node_modules/@types/warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI=" - }, - "node_modules/@urql/core": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/@urql/core/-/core-2.3.6.tgz", - "integrity": "sha512-PUxhtBh7/8167HJK6WqBv6Z0piuiaZHQGYbhwpNL9aIQmLROPEdaUYkY4wh45wPQXcTpnd11l0q3Pw+TI11pdw==", - "dependencies": { - "@graphql-typed-document-node/core": "^3.1.0", - "wonka": "^4.0.14" - }, - "peerDependencies": { - "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/aria-hidden": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.1.3.tgz", - "integrity": "sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA==", - "dependencies": { - "tslib": "^1.0.0" - }, - "engines": { - "node": ">=8.5.0" - } - }, - "node_modules/aria-hidden/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "peer": true - }, - "node_modules/attr-accept": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", - "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/babel-plugin-macros": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", - "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", - "dependencies": { - "@babel/runtime": "^7.7.2", - "cosmiconfig": "^6.0.0", - "resolve": "^1.12.0" - } - }, - "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001561", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz", - "integrity": "sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/compute-scroll-into-view": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz", - "integrity": "sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ==" - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/copy-to-clipboard": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz", - "integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==", - "dependencies": { - "toggle-selection": "^1.0.6" - } - }, - "node_modules/core-js": { - "version": "3.33.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.33.2.tgz", - "integrity": "sha512-XeBzWI6QL3nJQiHmdzbAOiMYqjrb7hwU7A39Qhvd/POSa/t9E1AeZyEZx3fNvp/vtM8zXwhoL0FsiS0hD0pruQ==", - "hasInstallScript": true, - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cross-fetch": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", - "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", - "peer": true, - "dependencies": { - "node-fetch": "^2.6.12" - } - }, - "node_modules/css-box-model": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", - "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", - "dependencies": { - "tiny-invariant": "^1.0.6" - } - }, - "node_modules/csstype": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" - }, - "node_modules/dayjs": { - "version": "1.10.7", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", - "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==" - }, - "node_modules/debounce": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", - "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "peer": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" - }, - "node_modules/draft-js": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.11.7.tgz", - "integrity": "sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg==", - "peer": true, - "dependencies": { - "fbjs": "^2.0.0", - "immutable": "~3.7.4", - "object-assign": "^4.1.1" - }, - "peerDependencies": { - "react": ">=0.14.0", - "react-dom": ">=0.14.0" - } - }, - "node_modules/draft-js/node_modules/immutable": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", - "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==", - "peer": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/draftjs-utils": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz", - "integrity": "sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg==", - "peerDependencies": { - "draft-js": "^0.11.x", - "immutable": "3.x.x || 4.x.x" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.581", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.581.tgz", - "integrity": "sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw==", - "peer": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/esbuild": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.9.tgz", - "integrity": "sha512-uuT3kFsfUvzNW6I2RKKIHuCvutY/U9KFcAP6emUm98WvBhyhEr5vGkZLeN3r3vXfoykl+7xekAH8Ky09LXBd0Q==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "optionalDependencies": { - "esbuild-android-arm64": "0.14.9", - "esbuild-darwin-64": "0.14.9", - "esbuild-darwin-arm64": "0.14.9", - "esbuild-freebsd-64": "0.14.9", - "esbuild-freebsd-arm64": "0.14.9", - "esbuild-linux-32": "0.14.9", - "esbuild-linux-64": "0.14.9", - "esbuild-linux-arm": "0.14.9", - "esbuild-linux-arm64": "0.14.9", - "esbuild-linux-mips64le": "0.14.9", - "esbuild-linux-ppc64le": "0.14.9", - "esbuild-linux-s390x": "0.14.9", - "esbuild-netbsd-64": "0.14.9", - "esbuild-openbsd-64": "0.14.9", - "esbuild-sunos-64": "0.14.9", - "esbuild-windows-32": "0.14.9", - "esbuild-windows-64": "0.14.9", - "esbuild-windows-arm64": "0.14.9" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.9.tgz", - "integrity": "sha512-VpSCuUR07G4Re/5QzqtdxS5ZgxkCRyzu4Kf5SH1/EkXzRGeoWQt8xirkOMK58pfmg/FlS/fQNgwl3Txej4LoVg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/esbuild-darwin-64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.9.tgz", - "integrity": "sha512-F/RcRHMG5ccAL8n9VIy8ZC4D0IHZrN/1IhHQbY4qPXrMlh42FucR0TW4lr3vdHF3caaId1jdDSQQJ7jXR+ZC5Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.9.tgz", - "integrity": "sha512-3ue+1T4FR5TaAu4/V1eFMG8Uwn0pgAwQZb/WwL1X78d5Cy8wOVQ67KNH1lsjU+y/9AcwMKZ9x0GGNxBB4a1Rbw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.9.tgz", - "integrity": "sha512-0YEjWt6ijaf5Y3Q50YS1lZxuWZWMV/T7atQEuQnF8ioq5jamrVr8j1TZ9+rxcLgH1lBMsXj8IwW+6BleXredEg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.9.tgz", - "integrity": "sha512-82w5qMgEeYvf8+vX/2KE5TOZf8rv8VK4TFiK6lDzdgdwwmBU5C8kdT3rO5Llan2K2LKndrou1eyi/fHwFcwPJQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/esbuild-linux-32": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.9.tgz", - "integrity": "sha512-eu8J8HNpco7Mkd7T7djQRzGBeuve41kbXRxFHOwwbZXMNQojXjBqLuradi5i/Vsw+CA4G/yVpmJI2S75Cit2mQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.9.tgz", - "integrity": "sha512-WoEI+R6/PLZAxS7XagfQMFgRtLUi5cjqqU9VCfo3tnWmAXh/wt8QtUfCVVCcXVwZLS/RNvI19CtfjlrJU61nOg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.9.tgz", - "integrity": "sha512-d3k1ZPREjaKYyhsS8x3jvc4ekjIZ8SmuihP60mrN1f6p5y07NKWw9i0OWD1p6hy+7g6cjMWq00tstMIikGB9Yg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.9.tgz", - "integrity": "sha512-joUE0yQgWMDkQqBx3+6SdNCVZ10F1O4+WM94moghvhdTzkYpECIc/WvfqMF/w0V8Hecw3QJ7vugO7jsFlXXd4Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.9.tgz", - "integrity": "sha512-ZAuheiDRo2c4rxx8GUTEwPvos0zUwCYjP9K2WfCSmDL6m3RpaObCQhZghrDuoIUwvc/D6SWuABsKE9VzogsltQ==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.9.tgz", - "integrity": "sha512-Pm8FeG5l314k3a2mbu3SAc5E2eLFuGUsGiSlw8V6xtA4whxJ7rit7951w9jBhz+1Vqqtqprg2IYTng3j2CGhVw==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.9.tgz", - "integrity": "sha512-G8FNZygV82N1/LOfPD8ZX7Mn1dPpKKPrZc93ebSJ8/VgNIafOAhV5vaeK1lhcx6ZSu+jJU/UyQQMG1CIvHRIaw==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.9.tgz", - "integrity": "sha512-b7vPrn5XN0GRtNAQ3w+gq8AwUfWSRBkcPAdA5UUT5rkrw7wKFyMqi2/zREBc/Knu5YOsLmZPQSoM8QL6qy79cg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ] - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.9.tgz", - "integrity": "sha512-w95Rt/vmVhZWfzZmeoMIHxbFiOFDmxC7GEdnCbDTXX2vlwKu+CIDIKOgWW+R1T2JqTNo5tu9dRkngKZMfbUo/A==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.9.tgz", - "integrity": "sha512-mzgmQZAVGo+uLkQXTY0viqVSEQKesmR5OEMMq1jM/2jucbZUcyaq8dVKRIWJJEzwNgZ6MpeOpshUtOzGxxy8ag==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ] - }, - "node_modules/esbuild-windows-32": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.9.tgz", - "integrity": "sha512-sYHEJLwdDJpjjSUyIGqPC1GRXl0Z/YT1K85Tcrv4iqZEXFR0rT7sTV+E0XC911FbTJHfuAdUJixkwAQeLMdrUg==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/esbuild-windows-64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.9.tgz", - "integrity": "sha512-xJTpyFzpH51LGlVR2C3P+Gpnjujsx5kEtJj5V/x8TyD94VW+EpszyND/pay15CIF64pWywyQt2jmGUDl6kzkEw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.9.tgz", - "integrity": "sha512-NKPPsYVlHqdF0yMuMJrjuAzqS/BHrMXZ8TN1Du+Pgi8KkmxzNXRPDHQV0NPPJ+Z7Lp09joEHSz1zrvQRs1j6jw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fbjs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz", - "integrity": "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ==", - "peer": true, - "dependencies": { - "core-js": "^3.6.4", - "cross-fetch": "^3.0.4", - "fbjs-css-vars": "^1.0.0", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - } - }, - "node_modules/fbjs-css-vars": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", - "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==", - "peer": true - }, - "node_modules/file-selector": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.4.0.tgz", - "integrity": "sha512-iACCiXeMYOvZqlF1kTiYINzgepRBymz1wwjiuup9u9nayhb6g4fSwiyJ/6adli+EPwrWtpgQAh2PoS7HukEGEg==", - "dependencies": { - "tslib": "^2.0.3" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" - }, - "node_modules/focus-lock": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-0.9.2.tgz", - "integrity": "sha512-YtHxjX7a0IC0ZACL5wsX8QdncXofWpGPNoVMuI/nZUrPGp6LmNI6+D5j0pPj+v8Kw5EpweA+T5yImK0rnWf7oQ==", - "dependencies": { - "tslib": "^2.0.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/focus-visible": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/focus-visible/-/focus-visible-5.2.0.tgz", - "integrity": "sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ==" - }, - "node_modules/framer-motion": { - "version": "5.5.5", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-5.5.5.tgz", - "integrity": "sha512-+LPAF5ddo02qKh+MK4h1ChwqUFvrLkK1NDWwrHy+MuCVmQDGgiFNHvwqOSklTDGkEtbio3dCOEDy23+ZyNAa9g==", - "dependencies": { - "framesync": "6.0.1", - "hey-listen": "^1.0.8", - "popmotion": "11.0.3", - "react-merge-refs": "^1.1.0", - "react-use-measure": "^2.1.1", - "style-value-types": "5.0.0", - "tslib": "^2.1.0" - }, - "optionalDependencies": { - "@emotion/is-prop-valid": "^0.8.2" - }, - "peerDependencies": { - "@react-three/fiber": "*", - "react": ">=16.8 || ^17.0.0", - "react-dom": ">=16.8 || ^17.0.0", - "three": "^0.135.0" - }, - "peerDependenciesMeta": { - "@react-three/fiber": { - "optional": true - }, - "three": { - "optional": true - } - } - }, - "node_modules/framer-motion/node_modules/@emotion/is-prop-valid": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", - "optional": true, - "dependencies": { - "@emotion/memoize": "0.7.4" - } - }, - "node_modules/framer-motion/node_modules/@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", - "optional": true - }, - "node_modules/framer-motion/node_modules/framesync": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz", - "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/framesync": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/framesync/-/framesync-5.3.0.tgz", - "integrity": "sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/graphql": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.2.0.tgz", - "integrity": "sha512-MuQd7XXrdOcmfwuLwC2jNvx0n3rxIuNYOxUtiee5XOmfrWo613ar2U8pE7aHAKh8VwfpifubpD9IP+EdEAEOsA==", - "engines": { - "node": "^12.22.0 || ^14.16.0 || >=16.0.0" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/hey-listen": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", - "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==" - }, - "node_modules/history": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz", - "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==", - "dependencies": { - "@babel/runtime": "^7.7.6" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/html-to-draftjs": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/html-to-draftjs/-/html-to-draftjs-1.5.0.tgz", - "integrity": "sha512-kggLXBNciKDwKf+KYsuE+V5gw4dZ7nHyGMX9m0wy7urzWjKGWyNFetmArRLvRV0VrxKN70WylFsJvMTJx02OBQ==", - "peerDependencies": { - "draft-js": "^0.10.x || ^0.11.x", - "immutable": "3.x.x || 4.x.x" - } - }, - "node_modules/immutable": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", - "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", - "peer": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "node_modules/is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "peer": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "peer": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", - "dependencies": { - "uc.micro": "^1.0.1" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.mergewith": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", - "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "peer": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "peer": true - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "peer": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "peer": true - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "peer": true - }, - "node_modules/popmotion": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz", - "integrity": "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==", - "dependencies": { - "framesync": "6.0.1", - "hey-listen": "^1.0.8", - "style-value-types": "5.0.0", - "tslib": "^2.1.0" - } - }, - "node_modules/popmotion/node_modules/framesync": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz", - "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "peer": true, - "dependencies": { - "asap": "~2.0.3" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-clientside-effect": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz", - "integrity": "sha512-2bL8qFW1TGBHozGGbVeyvnggRpMjibeZM2536AKNENLECutp2yfs44IL8Hmpn8qjFQ2K7A9PnYf3vc7aQq/cPA==", - "dependencies": { - "@babel/runtime": "^7.12.13" - }, - "peerDependencies": { - "react": "^15.3.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/react-draft-wysiwyg": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/react-draft-wysiwyg/-/react-draft-wysiwyg-1.15.0.tgz", - "integrity": "sha512-p1cYZcWc6/ALFBVksbFoCM3b29fGQDlZLIMrXng0TU/UElxIOF2/AWWo4L5auIYVhmqKTZ0NkNjnXOzGGuxyeA==", - "dependencies": { - "classnames": "^2.2.6", - "draftjs-utils": "^0.10.2", - "html-to-draftjs": "^1.5.0", - "linkify-it": "^2.2.0", - "prop-types": "^15.7.2" - }, - "peerDependencies": { - "draft-js": "^0.10.x || ^0.11.x", - "immutable": "3.x.x || 4.x.x", - "react": "0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x", - "react-dom": "0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x" - } - }, - "node_modules/react-dropzone": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-12.0.4.tgz", - "integrity": "sha512-fcqHEYe1MzAghU6/Hz86lHDlBNsA+lO48nAcm7/wA+kIzwS6uuJbUG33tBZjksj7GAZ1iUQ6NHwjUURPmSGang==", - "dependencies": { - "attr-accept": "^2.2.2", - "file-selector": "^0.4.0", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">= 10.13" - }, - "peerDependencies": { - "react": ">= 16.8" - } - }, - "node_modules/react-email-editor": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/react-email-editor/-/react-email-editor-1.6.1.tgz", - "integrity": "sha512-pEWpRmTY0ok03cwTGqEOoEldnzThhuRGTrcMnv8W3/jc5MTfcr9USU/IQ9HrVvFStLKoxYBIQnSKY+iCYWOtSQ==", - "peerDependencies": { - "react": "15.x || 16.x || 17.x" - } - }, - "node_modules/react-fast-compare": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" - }, - "node_modules/react-focus-lock": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.5.2.tgz", - "integrity": "sha512-WzpdOnEqjf+/A3EH9opMZWauag7gV0BxFl+EY4ElA4qFqYsUsBLnmo2sELbN5OC30S16GAWMy16B9DLPpdJKAQ==", - "dependencies": { - "@babel/runtime": "^7.0.0", - "focus-lock": "^0.9.1", - "prop-types": "^15.6.2", - "react-clientside-effect": "^1.2.5", - "use-callback-ref": "^1.2.5", - "use-sidecar": "^1.0.5" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0" - } - }, - "node_modules/react-icons": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz", - "integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==", - "peerDependencies": { - "react": "*" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-merge-refs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz", - "integrity": "sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/react-remove-scroll": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.4.1.tgz", - "integrity": "sha512-K7XZySEzOHMTq7dDwcHsZA6Y7/1uX5RsWhRXVYv8rdh+y9Qz2nMwl9RX/Mwnj/j7JstCGmxyfyC0zbVGXYh3mA==", - "dependencies": { - "react-remove-scroll-bar": "^2.1.0", - "react-style-singleton": "^2.1.0", - "tslib": "^1.0.0", - "use-callback-ref": "^1.2.3", - "use-sidecar": "^1.0.1" - }, - "engines": { - "node": ">=8.5.0" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0", - "react": "^16.8.0 || ^17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-remove-scroll-bar": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.2.0.tgz", - "integrity": "sha512-UU9ZBP1wdMR8qoUs7owiVcpaPwsQxUDC2lypP6mmixaGlARZa7ZIBx1jcuObLdhMOvCsnZcvetOho0wzPa9PYg==", - "dependencies": { - "react-style-singleton": "^2.1.0", - "tslib": "^1.0.0" - }, - "engines": { - "node": ">=8.5.0" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0", - "react": "^16.8.0 || ^17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-remove-scroll-bar/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/react-remove-scroll/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/react-router": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz", - "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==", - "dependencies": { - "history": "^5.2.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz", - "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==", - "dependencies": { - "history": "^5.2.0", - "react-router": "6.2.1" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/react-style-singleton": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.1.1.tgz", - "integrity": "sha512-jNRp07Jza6CBqdRKNgGhT3u9umWvils1xsuMOjZlghBDH2MU0PL2WZor4PGYjXpnRCa9DQSlHMs/xnABWOwYbA==", - "dependencies": { - "get-nonce": "^1.0.0", - "invariant": "^2.2.4", - "tslib": "^1.0.0" - }, - "engines": { - "node": ">=8.5.0" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0", - "react": "^16.8.0 || ^17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-style-singleton/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/react-use-measure": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", - "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", - "dependencies": { - "debounce": "^1.2.1" - }, - "peerDependencies": { - "react": ">=16.13", - "react-dom": ">=16.13" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "peer": true - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/style-value-types": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz", - "integrity": "sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==", - "dependencies": { - "hey-listen": "^1.0.8", - "tslib": "^2.1.0" - } - }, - "node_modules/stylis": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", - "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tiny-invariant": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", - "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "engines": { - "node": ">=4" - } - }, - "node_modules/toggle-selection": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "peer": true - }, - "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "node_modules/typescript": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", - "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/ua-parser-js": { - "version": "0.7.37", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", - "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - }, - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" - } - ], - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" - }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/urql": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/urql/-/urql-2.0.6.tgz", - "integrity": "sha512-ovK9mx7YxD/CKUwVZGbEDBzZjbCcNsr1990nIhDCKe3Ij/0gNcIa+0EIyXKceOPuYDYKavIoaNQV2kOZjQxFcw==", - "dependencies": { - "@urql/core": "^2.3.6", - "wonka": "^4.0.14" - }, - "peerDependencies": { - "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", - "react": ">= 16.8.0" - } - }, - "node_modules/use-callback-ref": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz", - "integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==", - "engines": { - "node": ">=8.5.0" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0", - "react": "^16.8.0 || ^17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-sidecar": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.0.5.tgz", - "integrity": "sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA==", - "dependencies": { - "detect-node-es": "^1.1.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=8.5.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0" - } - }, - "node_modules/use-sidecar/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "peer": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "peer": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/wonka": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/wonka/-/wonka-4.0.15.tgz", - "integrity": "sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==" - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "peer": true - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "engines": { - "node": ">= 6" - } - } - } -} diff --git a/dashboard/package.json b/dashboard/package.json deleted file mode 100644 index 13b022e54..000000000 --- a/dashboard/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "dashboard", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "build": "rm -rf build && NODE_ENV=production node ./esbuild.config.js", - "start": "NODE_ENV=development node ./esbuild.config.js", - "format": "prettier --write --use-tabs 'src/**/*.(ts|tsx|js|jsx)'" - }, - "keywords": [], - "author": "Lakhan Samani", - "license": "ISC", - "dependencies": { - "@chakra-ui/react": "^1.7.3", - "@emotion/core": "^11.0.0", - "@emotion/react": "^11.7.1", - "@emotion/styled": "^11.6.0", - "@types/react": "^17.0.38", - "@types/react-dom": "^17.0.11", - "@types/react-router-dom": "^5.3.2", - "dayjs": "^1.10.7", - "esbuild": "^0.14.9", - "focus-visible": "^5.2.0", - "framer-motion": "^5.5.5", - "graphql": "^16.2.0", - "lodash": "^4.17.21", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "react-draft-wysiwyg": "^1.15.0", - "react-dropzone": "^12.0.4", - "react-email-editor": "^1.6.1", - "react-icons": "^4.3.1", - "react-router-dom": "^6.2.1", - "typescript": "^4.5.4", - "urql": "^2.0.6" - }, - "devDependencies": { - "@types/react-email-editor": "^1.1.7", - "prettier": "2.7.1" - } -} diff --git a/dashboard/src/index.tsx b/dashboard/src/index.tsx deleted file mode 100644 index c463e63ea..000000000 --- a/dashboard/src/index.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './App'; - -ReactDOM.render( -
- -
, - document.getElementById('root'), -); diff --git a/dashboard/src/pages/Environment.tsx b/dashboard/src/pages/Environment.tsx deleted file mode 100644 index f163c4fa3..000000000 --- a/dashboard/src/pages/Environment.tsx +++ /dev/null @@ -1,348 +0,0 @@ -import React, { useEffect } from 'react'; -import { useParams } from 'react-router-dom'; -import { Box, Flex, Stack, Button, useToast } from '@chakra-ui/react'; -import { useClient } from 'urql'; -import { FaSave } from 'react-icons/fa'; -import _ from 'lodash'; -import { EnvVariablesQuery } from '../graphql/queries'; -import { - SelectInputType, - HiddenInputType, - TextInputType, - HMACEncryptionType, - RSAEncryptionType, - ECDSAEncryptionType, - envVarTypes, - envSubViews, -} from '../constants'; -import { UpdateEnvVariables } from '../graphql/mutation'; -import { getObjectDiff, capitalizeFirstLetter } from '../utils'; -import OAuthConfig from '../components/EnvComponents/OAuthConfig'; -import Roles from '../components/EnvComponents/Roles'; -import JWTConfigurations from '../components/EnvComponents/JWTConfiguration'; -import SessionStorage from '../components/EnvComponents/SessionStorage'; -import EmailConfigurations from '../components/EnvComponents/EmailConfiguration'; -import DomainWhiteListing from '../components/EnvComponents/DomainWhitelisting'; -import OrganizationInfo from '../components/EnvComponents/OrganizationInfo'; -import AccessToken from '../components/EnvComponents/AccessToken'; -import Features from '../components/EnvComponents/Features'; -import SecurityAdminSecret from '../components/EnvComponents/SecurityAdminSecret'; -import DatabaseCredentials from '../components/EnvComponents/DatabaseCredentials'; - -const Environment = () => { - const client = useClient(); - const toast = useToast(); - const [adminSecret, setAdminSecret] = React.useState< - Record - >({ - value: '', - disableInputField: true, - }); - const [loading, setLoading] = React.useState(true); - const [envVariables, setEnvVariables] = React.useState({ - GOOGLE_CLIENT_ID: '', - GOOGLE_CLIENT_SECRET: '', - GITHUB_CLIENT_ID: '', - GITHUB_CLIENT_SECRET: '', - FACEBOOK_CLIENT_ID: '', - FACEBOOK_CLIENT_SECRET: '', - LINKEDIN_CLIENT_ID: '', - LINKEDIN_CLIENT_SECRET: '', - APPLE_CLIENT_ID: '', - APPLE_CLIENT_SECRET: '', - DISCORD_CLIENT_ID: '', - DISCORD_CLIENT_SECRET: '', - TWITTER_CLIENT_ID: '', - TWITTER_CLIENT_SECRET: '', - MICROSOFT_CLIENT_ID: '', - MICROSOFT_CLIENT_SECRET: '', - MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: '', - TWITCH_CLIENT_ID: '', - TWITCH_CLIENT_SECRET: '', - ROBLOX_CLIENT_ID: '', - ROBLOX_CLIENT_SECRET: '', - ROLES: [], - DEFAULT_ROLES: [], - PROTECTED_ROLES: [], - JWT_TYPE: '', - JWT_SECRET: '', - JWT_ROLE_CLAIM: '', - JWT_PRIVATE_KEY: '', - JWT_PUBLIC_KEY: '', - REDIS_URL: '', - SMTP_HOST: '', - SMTP_PORT: '', - SMTP_USERNAME: '', - SMTP_PASSWORD: '', - SMTP_LOCAL_NAME: '', - SENDER_EMAIL: '', - SENDER_NAME: '', - ALLOWED_ORIGINS: [], - ORGANIZATION_NAME: '', - ORGANIZATION_LOGO: '', - CUSTOM_ACCESS_TOKEN_SCRIPT: '', - ADMIN_SECRET: '', - APP_COOKIE_SECURE: false, - ADMIN_COOKIE_SECURE: false, - DISABLE_LOGIN_PAGE: false, - DISABLE_MAGIC_LINK_LOGIN: false, - DISABLE_EMAIL_VERIFICATION: false, - DISABLE_BASIC_AUTHENTICATION: false, - DISABLE_MOBILE_BASIC_AUTHENTICATION: false, - DISABLE_SIGN_UP: false, - DISABLE_STRONG_PASSWORD: false, - OLD_ADMIN_SECRET: '', - DATABASE_NAME: '', - DATABASE_TYPE: '', - DATABASE_URL: '', - ACCESS_TOKEN_EXPIRY_TIME: '', - DISABLE_MULTI_FACTOR_AUTHENTICATION: false, - ENFORCE_MULTI_FACTOR_AUTHENTICATION: false, - DEFAULT_AUTHORIZE_RESPONSE_TYPE: '', - DEFAULT_AUTHORIZE_RESPONSE_MODE: '', - DISABLE_PLAYGROUND: false, - DISABLE_TOTP_LOGIN: false, - DISABLE_MAIL_OTP_LOGIN: true, - }); - - const [fieldVisibility, setFieldVisibility] = React.useState< - Record - >({ - GOOGLE_CLIENT_SECRET: false, - GITHUB_CLIENT_SECRET: false, - FACEBOOK_CLIENT_SECRET: false, - LINKEDIN_CLIENT_SECRET: false, - APPLE_CLIENT_SECRET: false, - DISCORD_CLIENT_SECRET: false, - TWITTER_CLIENT_SECRET: false, - TWITCH_CLIENT_SECRET: false, - JWT_SECRET: false, - SMTP_PASSWORD: false, - ADMIN_SECRET: false, - OLD_ADMIN_SECRET: false, - }); - - const { sec } = useParams(); - - async function getData() { - const { - data: { _env: envData }, - } = await client.query(EnvVariablesQuery).toPromise(); - setLoading(false); - - setEnvVariables({ - ...envData, - OLD_ADMIN_SECRET: envData.ADMIN_SECRET, - ADMIN_SECRET: '', - }); - setAdminSecret({ - value: '', - disableInputField: true, - }); - } - - useEffect(() => { - getData(); - }, [sec]); - - const validateAdminSecretHandler = (event: any) => { - if (envVariables.OLD_ADMIN_SECRET === event.target.value) { - setAdminSecret({ - ...adminSecret, - value: event.target.value, - disableInputField: false, - }); - } else { - setAdminSecret({ - ...adminSecret, - value: event.target.value, - disableInputField: true, - }); - } - if (envVariables.ADMIN_SECRET !== '') { - setEnvVariables({ ...envVariables, ADMIN_SECRET: '' }); - } - }; - - const saveHandler = async () => { - setLoading(true); - const { - data: { _env: envData }, - } = await client.query(EnvVariablesQuery).toPromise(); - const diff = getObjectDiff(envVariables, envData); - const updatedEnvVariables = diff.reduce( - (acc: any, property: string) => ({ - ...acc, - // @ts-ignore - [property]: envVariables[property], - }), - {}, - ); - if ( - updatedEnvVariables[HiddenInputType.ADMIN_SECRET] === '' || - updatedEnvVariables[HiddenInputType.OLD_ADMIN_SECRET] !== - envData.ADMIN_SECRET - ) { - delete updatedEnvVariables.OLD_ADMIN_SECRET; - delete updatedEnvVariables.ADMIN_SECRET; - } - - delete updatedEnvVariables.DATABASE_URL; - delete updatedEnvVariables.DATABASE_TYPE; - delete updatedEnvVariables.DATABASE_NAME; - - const res = await client - .mutation(UpdateEnvVariables, { params: updatedEnvVariables }) - .toPromise(); - - setLoading(false); - - if (res.error) { - toast({ - title: capitalizeFirstLetter(res.error.message), - isClosable: true, - status: 'error', - position: 'bottom-right', - }); - - return; - } - - setAdminSecret({ - value: '', - disableInputField: true, - }); - - getData(); - - toast({ - title: `Successfully updated ${ - Object.keys(updatedEnvVariables).length - } variables`, - isClosable: true, - status: 'success', - position: 'top-right', - }); - }; - - const renderComponent = (tab: any) => { - switch (tab) { - case envSubViews.INSTANCE_INFO: - return ( - - ); - case envSubViews.ROLES: - return ( - - ); - case envSubViews.JWT_CONFIG: - return ( - - ); - case envSubViews.SESSION_STORAGE: - return ( - - ); - case envSubViews.EMAIL_CONFIG: - return ( - - ); - case envSubViews.WHITELIST_VARIABLES: - return ( - - ); - case envSubViews.ORGANIZATION_INFO: - return ( - - ); - case envSubViews.ACCESS_TOKEN: - return ( - - ); - case envSubViews.FEATURES: - return ( - - ); - case envSubViews.ADMIN_SECRET: - return ( - - ); - case envSubViews.DB_CRED: - return ( - - ); - default: - return ( - - ); - } - }; - return ( - - {renderComponent(sec)} - - - - - - - ); -}; - -export default Environment; diff --git a/dashboard/yarn.lock b/dashboard/yarn.lock deleted file mode 100644 index 641f7bfab..000000000 --- a/dashboard/yarn.lock +++ /dev/null @@ -1,1887 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.22.13": - version "7.22.13" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz" - integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== - dependencies: - "@babel/highlight" "^7.22.13" - chalk "^2.4.2" - -"@babel/compat-data@^7.22.9": - version "7.23.3" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz" - integrity sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ== - -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0": - version "7.23.3" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz" - integrity sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.23.3" - "@babel/helper-compilation-targets" "^7.22.15" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.23.2" - "@babel/parser" "^7.23.3" - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.23.3" - "@babel/types" "^7.23.3" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@^7.23.3": - version "7.23.3" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz" - integrity sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg== - dependencies: - "@babel/types" "^7.23.3" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/helper-compilation-targets@^7.22.15": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz" - integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== - dependencies: - "@babel/compat-data" "^7.22.9" - "@babel/helper-validator-option" "^7.22.15" - browserslist "^4.21.9" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.22.15": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== - dependencies: - "@babel/types" "^7.22.15" - -"@babel/helper-module-transforms@^7.23.3": - version "7.23.3" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz" - integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.20" - -"@babel/helper-plugin-utils@^7.16.5": - version "7.16.5" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz" - integrity sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ== - -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz" - integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-option@^7.22.15": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz" - integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== - -"@babel/helpers@^7.23.2": - version "7.23.2" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz" - integrity sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ== - dependencies: - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.23.2" - "@babel/types" "^7.23.0" - -"@babel/highlight@^7.22.13": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz" - integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.22.15", "@babel/parser@^7.23.3": - version "7.23.3" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz" - integrity sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw== - -"@babel/plugin-syntax-jsx@^7.12.13": - version "7.16.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.5.tgz" - integrity sha512-42OGssv9NPk4QHKVgIHlzeLgPOW5rGgfV5jzG90AhcXXIv6hu/eqj63w4VgvRxdvZY3AlYeDgPiSJ3BqAd1Y6Q== - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.13.10", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6": - version "7.16.5" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz" - integrity sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.22.15": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz" - integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/traverse@^7.23.2", "@babel/traverse@^7.23.3": - version "7.23.3" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz" - integrity sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.23.3" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.3" - "@babel/types" "^7.23.3" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.3": - version "7.23.3" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz" - integrity sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw== - dependencies: - "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@chakra-ui/accordion@1.4.2": - version "1.4.2" - resolved "https://registry.npmjs.org/@chakra-ui/accordion/-/accordion-1.4.2.tgz" - integrity sha512-BAGMvcm2sFE5Ft7jwC9nF03/Yv7qztuhzwKBBy4iL0p1nCPh6kV54RBXUcoj3VWe+yrmNiAVYKRTdqQBTJFwOw== - dependencies: - "@chakra-ui/descendant" "2.1.1" - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/icon" "2.0.0" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/transition" "1.4.2" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/alert@1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@chakra-ui/alert/-/alert-1.3.2.tgz" - integrity sha512-+OMeVeGtydpj6nry0zH7qFDt36zEaxckRnufx1BGiCfWdUg6ahVwKXl8qX93Q8w82od7eAoBKMgGJz7IVL5NPw== - dependencies: - "@chakra-ui/icon" "2.0.0" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/anatomy@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/anatomy/-/anatomy-1.2.1.tgz" - integrity sha512-kNS+FiEDTSnwpQUW4dEjZ5745xhkvB0XtmqjY1wpclUSpFfptLZM9QIHPTnBt2bzM9R+idmRRP+WkTt6kyTrLw== - dependencies: - "@chakra-ui/theme-tools" "^1.3.1" - -"@chakra-ui/avatar@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/avatar/-/avatar-1.3.1.tgz" - integrity sha512-WI0/kcpTJViOH093V0bz8EB+e/rc+gjF+T5DkOuh1YWFxRRG5v+4Yd3PdEJtQgzWtBVhlbGWmE7WvBizyKwFCA== - dependencies: - "@chakra-ui/image" "1.1.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/breadcrumb@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/breadcrumb/-/breadcrumb-1.3.1.tgz" - integrity sha512-b1IoBmtr5FcP2fn5NRbdOdQo2c866OQ/WhcTcZ6UKae1jjik+36/qWE+X+RKzxC6FLfqo5qayV5zSgsnZym7Pg== - dependencies: - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/button@1.5.1": - version "1.5.1" - resolved "https://registry.npmjs.org/@chakra-ui/button/-/button-1.5.1.tgz" - integrity sha512-BvP29quEhP6OTgDiRsugD6adgkeOTEQpoDsZUVEmHnNVrbFfdsICEKKQTtDJ2iPf+hmpFrtnpN50vCLdAANKcw== - dependencies: - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/spinner" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/checkbox@1.6.1": - version "1.6.1" - resolved "https://registry.npmjs.org/@chakra-ui/checkbox/-/checkbox-1.6.1.tgz" - integrity sha512-Z5ZMeUYIRjRbi/knhYhSQshZH7OnROA7ezl9a9oVSKRF7iLMNMibQSlQLXmqUWaTKSgrS37cpKAzfgEuemyiUQ== - dependencies: - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - "@chakra-ui/visually-hidden" "1.1.1" - -"@chakra-ui/clickable@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/clickable/-/clickable-1.2.1.tgz" - integrity sha512-B0CIbKzDMwzG1APeTpW9H2Jl8dkarI1Qstb3hDOy23O+N5TU6lpDdVnXQ7fpFJS6mu5JjFqtkwzGAVZnkkv1rw== - dependencies: - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/close-button@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/close-button/-/close-button-1.2.2.tgz" - integrity sha512-SqeLib0qgMjK3OsO1g5OnAHUmdCC8GMjToNEea7TeSrA44bH9EXVhFTkMMu2PnDVHbQmi4Ee1cuulNJt0UhQ3g== - dependencies: - "@chakra-ui/icon" "2.0.0" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/color-mode@1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@chakra-ui/color-mode/-/color-mode-1.3.2.tgz" - integrity sha512-/rWcbrzbaWCyyUnT07Qjz0xf/ltHS31CHOKtVCWr2uTgfn2gOQpdxsKRbjrLYPOYZGTMdINUHNiAsqQjLoAoTQ== - dependencies: - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/react-env" "1.1.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/control-box@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/control-box/-/control-box-1.1.1.tgz" - integrity sha512-ZFbh85pzzZoiSjGnvLUzMB5BoA8Xm6TBMWvMtzLY5xiFGb9/mBeRDH2KFjr1GJzoqleWKkQwvFD6JM0kXcekpg== - dependencies: - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/counter@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/counter/-/counter-1.2.1.tgz" - integrity sha512-Gm4njMzEsDyAzdQtExn40TvmupzkPBrT5DiCu0DlxYqpLqCfqV49HgJHEG5oW3WV+WaC9mzg7VV+idKYh/d+Gg== - dependencies: - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/css-reset@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz" - integrity sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg== - -"@chakra-ui/descendant@2.1.1": - version "2.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/descendant/-/descendant-2.1.1.tgz" - integrity sha512-JasdVaN4MjL7QFo1vMnADy6EtFAlPKT1kTJ1LwMtl9AaF9VFLBsfGxm0L+WQK+3NJMuCSDBXWJB8mV4AQ11Edg== - dependencies: - "@chakra-ui/react-utils" "^1.2.1" - -"@chakra-ui/editable@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/editable/-/editable-1.3.1.tgz" - integrity sha512-MwyTtsnHNqmKmHv9SH3KIHWa06D4gBwcuTawTiSnYBUJL6My8ry/Wdca1to9So2tD6hcjz3TPTzOJOlyv0eiZg== - dependencies: - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/focus-lock@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/focus-lock/-/focus-lock-1.2.1.tgz" - integrity sha512-HYu39nvfaXUrBx+dIDJkFgebNCGEi9oZTfLUKzIJC+zPkmReTDSXV0dzSb/8vCAOq5fph1gFKsdbGy2U98P8GQ== - dependencies: - "@chakra-ui/utils" "1.9.1" - react-focus-lock "2.5.2" - -"@chakra-ui/form-control@1.5.2": - version "1.5.2" - resolved "https://registry.npmjs.org/@chakra-ui/form-control/-/form-control-1.5.2.tgz" - integrity sha512-uWv0/f+JEM0ZE5Hnj3TzCnJ09EB+A+DSs9QgyECOuxx9Ju6gnns2uaRki2BfxksQL9ZZomPCkMtXazY9Wa81ag== - dependencies: - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/icon" "2.0.0" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/hooks@1.7.1": - version "1.7.1" - resolved "https://registry.npmjs.org/@chakra-ui/hooks/-/hooks-1.7.1.tgz" - integrity sha512-hgN19X6GUKQYAHczmFY+GAT8vl9h+X+nGWrIAnmvZ6BgUXxDajnTNhZeWhj0ZkR+7A7dCE6Y/3X44GafUgChMw== - dependencies: - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - compute-scroll-into-view "1.0.14" - copy-to-clipboard "3.3.1" - -"@chakra-ui/icon@2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@chakra-ui/icon/-/icon-2.0.0.tgz" - integrity sha512-/GuU+xIcOIy9uSUUUCu249ZJB/nLDbjWGkfpoSdBwqT4+ytJrKt+0Ckh3Ub14sz3BJD+Z6IiIt6ySOA9+7lbsA== - dependencies: - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/image@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/image/-/image-1.1.1.tgz" - integrity sha512-bz1pn08XlXcO3r1KnpdjQgN3R2soiTx10sG2d5Pw9BdGdySf7Y73wiLh+Tan1xJHp6p2KH1hz4f7uKXXDn7Qmw== - dependencies: - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/input@1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@chakra-ui/input/-/input-1.3.2.tgz" - integrity sha512-VMxmQgFiQ2UnBlkgLX/336G0IfYfw8YWF2ZoEFj5WL9kDSrrL1FXSBgjFGxrper74G4W20tESBCfU1S891y6cg== - dependencies: - "@chakra-ui/form-control" "1.5.2" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/layout@1.6.0": - version "1.6.0" - resolved "https://registry.npmjs.org/@chakra-ui/layout/-/layout-1.6.0.tgz" - integrity sha512-WUfQ104y1wNueU33/hPlZsMzYJGjO0dXMpVkQf5ZNhNX3IGDO+5+MO2x2xloP+j45yNPi3p8ti/HBnm3dXI+3Q== - dependencies: - "@chakra-ui/icon" "2.0.0" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/live-region@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/live-region/-/live-region-1.1.1.tgz" - integrity sha512-BSdI5gLIffNRETEp6W18kBNg9tL0ZLLzfWGRnuO9tEbox7NrcgqIeLF8mNKwhDOZz88NKHtUOPVzjAUKW1SryQ== - dependencies: - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/media-query@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/media-query/-/media-query-1.2.2.tgz" - integrity sha512-xSmDVleE1drWiGH/MX3RqyVm29x/8Vf6G0UGaI2kCpbNmon+Q1zHW/yDHvptIuctLrPHYO8LOBxuUjfnIXwC2g== - dependencies: - "@chakra-ui/react-env" "1.1.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/menu@1.8.2": - version "1.8.2" - resolved "https://registry.npmjs.org/@chakra-ui/menu/-/menu-1.8.2.tgz" - integrity sha512-u2GfkwTqbWa8L/7i/kOFbU3JANiT2HStR+gsYKuiuOPiuBcUb8OlgfJfP70OtVKegNKmVEMjvzXtld3wCCo/1g== - dependencies: - "@chakra-ui/clickable" "1.2.1" - "@chakra-ui/descendant" "2.1.1" - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/popper" "2.4.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/transition" "1.4.2" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/modal@1.10.2": - version "1.10.2" - resolved "https://registry.npmjs.org/@chakra-ui/modal/-/modal-1.10.2.tgz" - integrity sha512-ZlmYetPHwHW4CAM09j4/+Ui54dXR1nzU6mOwhWe4/IzLvEyoEU6fHJeKyGxVUpYTG/7wltG/wKFRJpYa77tiBg== - dependencies: - "@chakra-ui/close-button" "1.2.2" - "@chakra-ui/focus-lock" "1.2.1" - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/portal" "1.3.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/transition" "1.4.2" - "@chakra-ui/utils" "1.9.1" - aria-hidden "^1.1.1" - react-remove-scroll "2.4.1" - -"@chakra-ui/number-input@1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@chakra-ui/number-input/-/number-input-1.3.2.tgz" - integrity sha512-7x7AoqwPXU1odyDcqIwjBwf0MJUwYMM2fa+6YZ52F941GKlvkDiiJOhK6xfhhBzkLUQD6DN8zgAmmGhaZ6UQXw== - dependencies: - "@chakra-ui/counter" "1.2.1" - "@chakra-ui/form-control" "1.5.2" - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/icon" "2.0.0" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/pin-input@1.7.1": - version "1.7.1" - resolved "https://registry.npmjs.org/@chakra-ui/pin-input/-/pin-input-1.7.1.tgz" - integrity sha512-eFFc5sofiyion+NxELWfCzD23XHIBDrJcfKKbNxt8jdXg9Ek4mFpmvnxBVrK0DIz6cVYgKY8c364OmxNUf4IyA== - dependencies: - "@chakra-ui/descendant" "2.1.1" - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/popover@1.11.0": - version "1.11.0" - resolved "https://registry.npmjs.org/@chakra-ui/popover/-/popover-1.11.0.tgz" - integrity sha512-cCHXAfhIRir+M0ehlYIjDw3mHpiCxDTJ9WV0H1zHQV8nDYVIlZw3nEntaq8oJrv0wpIzq2WCW5ss+bBR7nLZ1A== - dependencies: - "@chakra-ui/close-button" "1.2.2" - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/popper" "2.4.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/popper@2.4.1": - version "2.4.1" - resolved "https://registry.npmjs.org/@chakra-ui/popper/-/popper-2.4.1.tgz" - integrity sha512-cuwnwXx6RUXZGGynVOGG8fEIiMNBXUCy3UqWQD1eEd8200eWQobgNk4Z0YwzKuSzJwp0Auy+j5iKefi5FSkyog== - dependencies: - "@chakra-ui/react-utils" "1.2.1" - "@popperjs/core" "^2.9.3" - -"@chakra-ui/portal@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/portal/-/portal-1.3.1.tgz" - integrity sha512-6UOGZCfujgdijcPs/JTEY5IB5WtKvUbfrSQYsG5CDa+guIwvnoP5qZ+rH6BR6DSSM8Wr/1n+WrtanhfFZShHKA== - dependencies: - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/progress@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/progress/-/progress-1.2.1.tgz" - integrity sha512-213nN8nbODvD/A23vAtg+r3bRKKatWQHafgmLzeznUcxa/+ac0eVurIS8XSYLRkY4EXQ505re3ZkLhDd98a7QA== - dependencies: - "@chakra-ui/theme-tools" "1.3.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/provider@1.7.3": - version "1.7.3" - resolved "https://registry.npmjs.org/@chakra-ui/provider/-/provider-1.7.3.tgz" - integrity sha512-D1SrQ7do4yzAv9/OTF3yj/BkLm7kFo5DdeuOCyvXGpVJumnvbtjltRmC7rFQH4R+y9qXPvfQP4LKMNBqSxPNng== - dependencies: - "@chakra-ui/css-reset" "1.1.1" - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/portal" "1.3.1" - "@chakra-ui/react-env" "1.1.1" - "@chakra-ui/system" "1.8.3" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/radio@1.4.3": - version "1.4.3" - resolved "https://registry.npmjs.org/@chakra-ui/radio/-/radio-1.4.3.tgz" - integrity sha512-TQdyfdUD3BLklOP67n82JN8ksQv1BYjvaYsK0m6WCa0LDJr9aCC+XtUPgVq/1L2t4HqHdiGOrGBooF4vvy/+BA== - dependencies: - "@chakra-ui/form-control" "1.5.2" - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - "@chakra-ui/visually-hidden" "1.1.1" - -"@chakra-ui/react-env@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/react-env/-/react-env-1.1.1.tgz" - integrity sha512-Lgmb0y4kv0ffsGMelAOaYOd4tYZAv4FYWgV86ckGMjmYQWA8drv4v/lHTNltixxWMmBEpjcHALpJuS6yAZYHug== - dependencies: - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/react-utils@^1.2.1", "@chakra-ui/react-utils@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/react-utils/-/react-utils-1.2.1.tgz" - integrity sha512-bV8FRaXiOgGxOg03iTNin/B02I+tHH9PQtqUTl3U7cJaoI+5AUYhrqXvl1Ya2/R7zxSFrb/gBVDTgbZiVkJ+Dg== - dependencies: - "@chakra-ui/utils" "^1.9.1" - -"@chakra-ui/react@^1.7.3": - version "1.7.3" - resolved "https://registry.npmjs.org/@chakra-ui/react/-/react-1.7.3.tgz" - integrity sha512-6mrfDUOa9MoQ44Xvi7xgdDq48jTTTjW9BupCGf2R3DI+z6RbUKIHzbcoDJZt2HGY6j9EarMVNRoQJzvzGUKpoQ== - dependencies: - "@chakra-ui/accordion" "1.4.2" - "@chakra-ui/alert" "1.3.2" - "@chakra-ui/avatar" "1.3.1" - "@chakra-ui/breadcrumb" "1.3.1" - "@chakra-ui/button" "1.5.1" - "@chakra-ui/checkbox" "1.6.1" - "@chakra-ui/close-button" "1.2.2" - "@chakra-ui/control-box" "1.1.1" - "@chakra-ui/counter" "1.2.1" - "@chakra-ui/css-reset" "1.1.1" - "@chakra-ui/editable" "1.3.1" - "@chakra-ui/form-control" "1.5.2" - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/icon" "2.0.0" - "@chakra-ui/image" "1.1.1" - "@chakra-ui/input" "1.3.2" - "@chakra-ui/layout" "1.6.0" - "@chakra-ui/live-region" "1.1.1" - "@chakra-ui/media-query" "1.2.2" - "@chakra-ui/menu" "1.8.2" - "@chakra-ui/modal" "1.10.2" - "@chakra-ui/number-input" "1.3.2" - "@chakra-ui/pin-input" "1.7.1" - "@chakra-ui/popover" "1.11.0" - "@chakra-ui/popper" "2.4.1" - "@chakra-ui/portal" "1.3.1" - "@chakra-ui/progress" "1.2.1" - "@chakra-ui/provider" "1.7.3" - "@chakra-ui/radio" "1.4.3" - "@chakra-ui/react-env" "1.1.1" - "@chakra-ui/select" "1.2.2" - "@chakra-ui/skeleton" "1.2.3" - "@chakra-ui/slider" "1.5.2" - "@chakra-ui/spinner" "1.2.1" - "@chakra-ui/stat" "1.2.2" - "@chakra-ui/switch" "1.3.1" - "@chakra-ui/system" "1.8.3" - "@chakra-ui/table" "1.3.1" - "@chakra-ui/tabs" "1.6.1" - "@chakra-ui/tag" "1.2.2" - "@chakra-ui/textarea" "1.2.2" - "@chakra-ui/theme" "1.12.2" - "@chakra-ui/toast" "1.5.0" - "@chakra-ui/tooltip" "1.4.2" - "@chakra-ui/transition" "1.4.2" - "@chakra-ui/utils" "1.9.1" - "@chakra-ui/visually-hidden" "1.1.1" - -"@chakra-ui/select@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/select/-/select-1.2.2.tgz" - integrity sha512-EchJW3St1DtSWHe//DHwKjGsQYL2zbKcNCLnJWQKGMPZsQhAD2wsm4xjowFrV8AkY7jbVM/U2v68puN7YTC3hg== - dependencies: - "@chakra-ui/form-control" "1.5.2" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/skeleton@1.2.3": - version "1.2.3" - resolved "https://registry.npmjs.org/@chakra-ui/skeleton/-/skeleton-1.2.3.tgz" - integrity sha512-u5ASkzPiBjfvKxKuBienUfmyYDTHziSWQ8Ny6k83LbwLv9IcmBNGsSkmsp7hesgi9cMHGBQ3hY2GTqG9ljndIg== - dependencies: - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/media-query" "1.2.2" - "@chakra-ui/system" "1.8.3" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/slider@1.5.2": - version "1.5.2" - resolved "https://registry.npmjs.org/@chakra-ui/slider/-/slider-1.5.2.tgz" - integrity sha512-zP07TMew61GkJe47Nu7zEg/SUEwPHpN4alW6VUM6Y8UaVpQaDx7InarbWTc/bXdTP03SfE+hQ6WD9Oy7noe4hQ== - dependencies: - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/spinner@1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@chakra-ui/spinner/-/spinner-1.2.1.tgz" - integrity sha512-CQsUJNJWWSot1ku5Se41Nz1dXIDhk+/7FIhTbfRHSjtYZnAab3CPMHBkTGqwbJxQ9oHYgk9Rso3cfG+/ra6aTQ== - dependencies: - "@chakra-ui/utils" "1.9.1" - "@chakra-ui/visually-hidden" "1.1.1" - -"@chakra-ui/stat@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/stat/-/stat-1.2.2.tgz" - integrity sha512-0StsPDC56MjzhdlBl0R8wU0uwj9L1tvhQzge/ELSDn4tQDI7VovrxpFzVH0qsj7EZDwZa0BRQaSrstzWvgmJ/Q== - dependencies: - "@chakra-ui/icon" "2.0.0" - "@chakra-ui/utils" "1.9.1" - "@chakra-ui/visually-hidden" "1.1.1" - -"@chakra-ui/styled-system@1.15.0": - version "1.15.0" - resolved "https://registry.npmjs.org/@chakra-ui/styled-system/-/styled-system-1.15.0.tgz" - integrity sha512-LnsKeiYkUuJ+NMTwueiX0Mj8CW9XAMJrJxpQm/X3GY5L5PO7Hv6wW725Ovqdy4mhG3IK7S8444FthpsDv/luHw== - dependencies: - "@chakra-ui/utils" "1.9.1" - csstype "^3.0.9" - -"@chakra-ui/switch@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/switch/-/switch-1.3.1.tgz" - integrity sha512-92hXJ2/ozj7B3cJNT259mFNoad7Ck892uHTuEQ/GIdXb25doE6F1wCp0TreOnGiEgU5YSaxpdrcZjA0QODP//w== - dependencies: - "@chakra-ui/checkbox" "1.6.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/system@>=1.0.0", "@chakra-ui/system@1.8.3": - version "1.8.3" - resolved "https://registry.npmjs.org/@chakra-ui/system/-/system-1.8.3.tgz" - integrity sha512-6MaevsT7A2ifgOGQQCQsfvzPVd0kEXqFrX1Oxd842bawaqthmbFdo2bBTdaia/+Ivq/8Xot2uAQSbU+3NuRiUA== - dependencies: - "@chakra-ui/color-mode" "1.3.2" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/styled-system" "1.15.0" - "@chakra-ui/utils" "1.9.1" - react-fast-compare "3.2.0" - -"@chakra-ui/table@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/table/-/table-1.3.1.tgz" - integrity sha512-+ia/7zs7AGj01lon301EEx+mK4918yGc0K6e68Kxomex8tnxkwbskFWs6hX+6Kzbj56ZBm99eLlKpo2iGYX0HA== - dependencies: - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/tabs@1.6.1": - version "1.6.1" - resolved "https://registry.npmjs.org/@chakra-ui/tabs/-/tabs-1.6.1.tgz" - integrity sha512-p7HdHcleJWNwteWYVPt2KF52YbS5pIIfs/IpgtnYZRsJbqvRVxSwgg5Wsn+vuxFXBKW0cA2rDGbyzsZ+ChtEXQ== - dependencies: - "@chakra-ui/clickable" "1.2.1" - "@chakra-ui/descendant" "2.1.1" - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/tag@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/tag/-/tag-1.2.2.tgz" - integrity sha512-H25y9nEyUAUdwQDND9P4mMXKf1wf9UH4A3DyP237qVKIyYBpa4aCH8eJU4dunh2yIzASB0DWcr7lsul/HAHxmg== - dependencies: - "@chakra-ui/icon" "2.0.0" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/textarea@1.2.2": - version "1.2.2" - resolved "https://registry.npmjs.org/@chakra-ui/textarea/-/textarea-1.2.2.tgz" - integrity sha512-DoLdKxHk0DyrQDnj1la9wjl2AW3/SK62nfWDYLAm0ouFsw1VKPw9nU+Yyj0dPruQTzI19nLaYF26i97rtnT27g== - dependencies: - "@chakra-ui/form-control" "1.5.2" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/theme-tools@^1.3.1", "@chakra-ui/theme-tools@1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/theme-tools/-/theme-tools-1.3.1.tgz" - integrity sha512-D8arJ5uFGuYZrrFGpXqgov8FhsJYWRyar5oBZY5TJR9gsVYBlJ8Ai91pwM/NflCFqzerTOgyt7bNSGQMdZ8ghA== - dependencies: - "@chakra-ui/utils" "1.9.1" - "@ctrl/tinycolor" "^3.4.0" - -"@chakra-ui/theme@>=1.0.0", "@chakra-ui/theme@1.12.2": - version "1.12.2" - resolved "https://registry.npmjs.org/@chakra-ui/theme/-/theme-1.12.2.tgz" - integrity sha512-LVjSf16yYHD40ILrsDEd3idVQRvJSY7JY8lvTGWo2p6v+JQESWF+zXlYi9Le+TXRpZuFvJuuQ1SEvoqVwdcJ8Q== - dependencies: - "@chakra-ui/anatomy" "1.2.1" - "@chakra-ui/theme-tools" "1.3.1" - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/toast@1.5.0": - version "1.5.0" - resolved "https://registry.npmjs.org/@chakra-ui/toast/-/toast-1.5.0.tgz" - integrity sha512-rTsFx/Qos5oVPN6aZMbT/wTxwZlFNSXQqrTpJYaRcRFQGzxIDDxmGkKYfPnyJjRP9i6EqynJhXEIyhMA0xO0dw== - dependencies: - "@chakra-ui/alert" "1.3.2" - "@chakra-ui/close-button" "1.2.2" - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/theme" "1.12.2" - "@chakra-ui/transition" "1.4.2" - "@chakra-ui/utils" "1.9.1" - "@reach/alert" "0.13.2" - -"@chakra-ui/tooltip@1.4.2": - version "1.4.2" - resolved "https://registry.npmjs.org/@chakra-ui/tooltip/-/tooltip-1.4.2.tgz" - integrity sha512-+wyYXG8qenKkFy2YSFfOBf3rlWADnu6S9EUxP+3Rmm78unOWXDuTJWzqy2QlXs2BwoQoifaz1LVwzmMb7WLVgQ== - dependencies: - "@chakra-ui/hooks" "1.7.1" - "@chakra-ui/popper" "2.4.1" - "@chakra-ui/portal" "1.3.1" - "@chakra-ui/react-utils" "1.2.1" - "@chakra-ui/utils" "1.9.1" - "@chakra-ui/visually-hidden" "1.1.1" - -"@chakra-ui/transition@1.4.2": - version "1.4.2" - resolved "https://registry.npmjs.org/@chakra-ui/transition/-/transition-1.4.2.tgz" - integrity sha512-S+BNmpErHlntl//uaqv0sJegzMsQms0OnJapeZaRsvZL4s1SVYrR8kMrXigkdpeh4lAUqGsLpQHPKkzaKGbBOw== - dependencies: - "@chakra-ui/utils" "1.9.1" - -"@chakra-ui/utils@^1.9.1", "@chakra-ui/utils@1.9.1": - version "1.9.1" - resolved "https://registry.npmjs.org/@chakra-ui/utils/-/utils-1.9.1.tgz" - integrity sha512-Tue8JfpzOqeHd8vSqAnX1l/Y3Gg456+BXFP/TH6mCIeqMAMbrvv25vDskds0wlXRjMYdmpqHxCEzkalFrscGHA== - dependencies: - "@types/lodash.mergewith" "4.6.6" - css-box-model "1.2.1" - framesync "5.3.0" - lodash.mergewith "4.6.2" - -"@chakra-ui/visually-hidden@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/visually-hidden/-/visually-hidden-1.1.1.tgz" - integrity sha512-AGK9YBQS2FW/1e5tfivS8VVXn8y2uTyJ9ACOnGiLm9FNdth9pR0fGil9axlcmhZpEYcSRlnCuma3nkqaCjJnAA== - dependencies: - "@chakra-ui/utils" "1.9.1" - -"@ctrl/tinycolor@^3.4.0": - version "3.4.0" - resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz" - integrity sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ== - -"@emotion/babel-plugin@^11.3.0": - version "11.7.2" - resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz" - integrity sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ== - dependencies: - "@babel/helper-module-imports" "^7.12.13" - "@babel/plugin-syntax-jsx" "^7.12.13" - "@babel/runtime" "^7.13.10" - "@emotion/hash" "^0.8.0" - "@emotion/memoize" "^0.7.5" - "@emotion/serialize" "^1.0.2" - babel-plugin-macros "^2.6.1" - convert-source-map "^1.5.0" - escape-string-regexp "^4.0.0" - find-root "^1.1.0" - source-map "^0.5.7" - stylis "4.0.13" - -"@emotion/cache@^11.7.1": - version "11.7.1" - resolved "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz" - integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A== - dependencies: - "@emotion/memoize" "^0.7.4" - "@emotion/sheet" "^1.1.0" - "@emotion/utils" "^1.0.0" - "@emotion/weak-memoize" "^0.2.5" - stylis "4.0.13" - -"@emotion/core@^11.0.0": - version "11.0.0" - resolved "https://registry.npmjs.org/@emotion/core/-/core-11.0.0.tgz" - integrity sha512-w4sE3AmHmyG6RDKf6mIbtHpgJUSJ2uGvPQb8VXFL7hFjMPibE8IiehG8cMX3Ztm4svfCQV6KqusQbeIOkurBcA== - -"@emotion/hash@^0.8.0": - version "0.8.0" - resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz" - integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== - -"@emotion/is-prop-valid@^0.8.2": - version "0.8.8" - resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz" - integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== - dependencies: - "@emotion/memoize" "0.7.4" - -"@emotion/is-prop-valid@^1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.1.tgz" - integrity sha512-bW1Tos67CZkOURLc0OalnfxtSXQJMrAMV0jZTVGJUPSOd4qgjF3+tTD5CwJM13PHA8cltGW1WGbbvV9NpvUZPw== - dependencies: - "@emotion/memoize" "^0.7.4" - -"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": - version "0.7.5" - resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz" - integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== - -"@emotion/memoize@0.7.4": - version "0.7.4" - resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz" - integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== - -"@emotion/react@^11.0.0", "@emotion/react@^11.0.0-rc.0", "@emotion/react@^11.7.1", "@emotion/react@>=10.0.35": - version "11.7.1" - resolved "https://registry.npmjs.org/@emotion/react/-/react-11.7.1.tgz" - integrity sha512-DV2Xe3yhkF1yT4uAUoJcYL1AmrnO5SVsdfvu+fBuS7IbByDeTVx9+wFmvx9Idzv7/78+9Mgx2Hcmr7Fex3tIyw== - dependencies: - "@babel/runtime" "^7.13.10" - "@emotion/cache" "^11.7.1" - "@emotion/serialize" "^1.0.2" - "@emotion/sheet" "^1.1.0" - "@emotion/utils" "^1.0.0" - "@emotion/weak-memoize" "^0.2.5" - hoist-non-react-statics "^3.3.1" - -"@emotion/serialize@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz" - integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== - dependencies: - "@emotion/hash" "^0.8.0" - "@emotion/memoize" "^0.7.4" - "@emotion/unitless" "^0.7.5" - "@emotion/utils" "^1.0.0" - csstype "^3.0.2" - -"@emotion/sheet@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz" - integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g== - -"@emotion/styled@^11.0.0", "@emotion/styled@^11.6.0": - version "11.6.0" - resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.6.0.tgz" - integrity sha512-mxVtVyIOTmCAkFbwIp+nCjTXJNgcz4VWkOYQro87jE2QBTydnkiYusMrRGFtzuruiGK4dDaNORk4gH049iiQuw== - dependencies: - "@babel/runtime" "^7.13.10" - "@emotion/babel-plugin" "^11.3.0" - "@emotion/is-prop-valid" "^1.1.1" - "@emotion/serialize" "^1.0.2" - "@emotion/utils" "^1.0.0" - -"@emotion/unitless@^0.7.5": - version "0.7.5" - resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz" - integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== - -"@emotion/utils@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz" - integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA== - -"@emotion/weak-memoize@^0.2.5": - version "0.2.5" - resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz" - integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== - -"@graphql-typed-document-node/core@^3.1.0": - version "3.1.1" - resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz" - integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg== - -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.3" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== - -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.20" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz" - integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@popperjs/core@^2.9.3": - version "2.11.0" - resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.0.tgz" - integrity sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ== - -"@reach/alert@0.13.2": - version "0.13.2" - resolved "https://registry.npmjs.org/@reach/alert/-/alert-0.13.2.tgz" - integrity sha512-LDz83AXCrClyq/MWe+0vaZfHp1Ytqn+kgL5VxG7rirUvmluWaj/snxzfNPWn0Ma4K2YENmXXRC/iHt5X95SqIg== - dependencies: - "@reach/utils" "0.13.2" - "@reach/visually-hidden" "0.13.2" - prop-types "^15.7.2" - tslib "^2.1.0" - -"@reach/utils@0.13.2": - version "0.13.2" - resolved "https://registry.npmjs.org/@reach/utils/-/utils-0.13.2.tgz" - integrity sha512-3ir6cN60zvUrwjOJu7C6jec/samqAeyAB12ZADK+qjnmQPdzSYldrFWwDVV5H0WkhbYXR3uh+eImu13hCetNPQ== - dependencies: - "@types/warning" "^3.0.0" - tslib "^2.1.0" - warning "^4.0.3" - -"@reach/visually-hidden@0.13.2": - version "0.13.2" - resolved "https://registry.npmjs.org/@reach/visually-hidden/-/visually-hidden-0.13.2.tgz" - integrity sha512-sPZwNS0/duOuG0mYwE5DmgEAzW9VhgU3aIt1+mrfT/xiT9Cdncqke+kRBQgU708q/Ttm9tWsoHni03nn/SuPTQ== - dependencies: - prop-types "^15.7.2" - tslib "^2.1.0" - -"@types/history@*": - version "4.7.9" - resolved "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz" - integrity sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ== - -"@types/lodash.mergewith@4.6.6": - version "4.6.6" - resolved "https://registry.npmjs.org/@types/lodash.mergewith/-/lodash.mergewith-4.6.6.tgz" - integrity sha512-RY/8IaVENjG19rxTZu9Nukqh0W2UrYgmBj5sdns4hWRZaV8PqR7wIKHFKzvOTjo4zVRV7sVI+yFhAJql12Kfqg== - dependencies: - "@types/lodash" "*" - -"@types/lodash@*": - version "4.14.178" - resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz" - integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== - -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - -"@types/prop-types@*": - version "15.7.4" - resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz" - integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== - -"@types/react-dom@^17.0.11": - version "17.0.11" - resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz" - integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q== - dependencies: - "@types/react" "*" - -"@types/react-email-editor@^1.1.7": - version "1.1.7" - resolved "https://registry.npmjs.org/@types/react-email-editor/-/react-email-editor-1.1.7.tgz" - integrity sha512-OURTAgaE9pjA6KiU97k13fPdoglI1ZyowUuZ0nu5tTSyrw5PiZoYzYEf9y25YTjmw/ohxT5yqoP0tt+AjSh1qQ== - dependencies: - "@types/react" "*" - -"@types/react-router-dom@^5.3.2": - version "5.3.2" - resolved "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.2.tgz" - integrity sha512-ELEYRUie2czuJzaZ5+ziIp9Hhw+juEw8b7C11YNA4QdLCVbQ3qLi2l4aq8XnlqM7V31LZX8dxUuFUCrzHm6sqQ== - dependencies: - "@types/history" "*" - "@types/react" "*" - "@types/react-router" "*" - -"@types/react-router@*": - version "5.1.17" - resolved "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz" - integrity sha512-RNSXOyb3VyRs/EOGmjBhhGKTbnN6fHWvy5FNLzWfOWOGjgVUKqJZXfpKzLmgoU8h6Hj8mpALj/mbXQASOb92wQ== - dependencies: - "@types/history" "*" - "@types/react" "*" - -"@types/react@*", "@types/react@^16.8.0 || ^17.0.0", "@types/react@^17.0.38": - version "17.0.38" - resolved "https://registry.npmjs.org/@types/react/-/react-17.0.38.tgz" - integrity sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - -"@types/scheduler@*": - version "0.16.2" - resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== - -"@types/warning@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz" - integrity sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI= - -"@urql/core@^2.3.6": - version "2.3.6" - resolved "https://registry.npmjs.org/@urql/core/-/core-2.3.6.tgz" - integrity sha512-PUxhtBh7/8167HJK6WqBv6Z0piuiaZHQGYbhwpNL9aIQmLROPEdaUYkY4wh45wPQXcTpnd11l0q3Pw+TI11pdw== - dependencies: - "@graphql-typed-document-node/core" "^3.1.0" - wonka "^4.0.14" - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -aria-hidden@^1.1.1: - version "1.1.3" - resolved "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.1.3.tgz" - integrity sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA== - dependencies: - tslib "^1.0.0" - -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz" - integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== - -attr-accept@^2.2.2: - version "2.2.2" - resolved "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz" - integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== - -babel-plugin-macros@^2.6.1: - version "2.8.0" - resolved "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz" - integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== - dependencies: - "@babel/runtime" "^7.7.2" - cosmiconfig "^6.0.0" - resolve "^1.12.0" - -browserslist@^4.21.9, "browserslist@>= 4.21.0": - version "4.22.1" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz" - integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ== - dependencies: - caniuse-lite "^1.0.30001541" - electron-to-chromium "^1.4.535" - node-releases "^2.0.13" - update-browserslist-db "^1.0.13" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -caniuse-lite@^1.0.30001541: - version "1.0.30001561" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz" - integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw== - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -classnames@^2.2.6: - version "2.3.1" - resolved "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz" - integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -compute-scroll-into-view@1.0.14: - version "1.0.14" - resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz" - integrity sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ== - -convert-source-map@^1.5.0: - version "1.8.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -copy-to-clipboard@3.3.1: - version "3.3.1" - resolved "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz" - integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== - dependencies: - toggle-selection "^1.0.6" - -core-js@^3.6.4: - version "3.33.2" - resolved "https://registry.npmjs.org/core-js/-/core-js-3.33.2.tgz" - integrity sha512-XeBzWI6QL3nJQiHmdzbAOiMYqjrb7hwU7A39Qhvd/POSa/t9E1AeZyEZx3fNvp/vtM8zXwhoL0FsiS0hD0pruQ== - -cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz" - integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" - -cross-fetch@^3.0.4: - version "3.1.8" - resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz" - integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== - dependencies: - node-fetch "^2.6.12" - -css-box-model@1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz" - integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== - dependencies: - tiny-invariant "^1.0.6" - -csstype@^3.0.2, csstype@^3.0.9: - version "3.0.10" - resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz" - integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== - -dayjs@^1.10.7: - version "1.10.7" - resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz" - integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig== - -debounce@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz" - integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== - -debug@^4.1.0: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -detect-node-es@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz" - integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== - -"draft-js@^0.10.x || ^0.11.x", draft-js@^0.11.x: - version "0.11.7" - resolved "https://registry.npmjs.org/draft-js/-/draft-js-0.11.7.tgz" - integrity sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg== - dependencies: - fbjs "^2.0.0" - immutable "~3.7.4" - object-assign "^4.1.1" - -draftjs-utils@^0.10.2: - version "0.10.2" - resolved "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz" - integrity sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg== - -electron-to-chromium@^1.4.535: - version "1.4.581" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.581.tgz" - integrity sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -esbuild-darwin-arm64@0.14.9: - version "0.14.9" - resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.9.tgz" - integrity sha512-3ue+1T4FR5TaAu4/V1eFMG8Uwn0pgAwQZb/WwL1X78d5Cy8wOVQ67KNH1lsjU+y/9AcwMKZ9x0GGNxBB4a1Rbw== - -esbuild@^0.14.9: - version "0.14.9" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.9.tgz" - integrity sha512-uuT3kFsfUvzNW6I2RKKIHuCvutY/U9KFcAP6emUm98WvBhyhEr5vGkZLeN3r3vXfoykl+7xekAH8Ky09LXBd0Q== - optionalDependencies: - esbuild-android-arm64 "0.14.9" - esbuild-darwin-64 "0.14.9" - esbuild-darwin-arm64 "0.14.9" - esbuild-freebsd-64 "0.14.9" - esbuild-freebsd-arm64 "0.14.9" - esbuild-linux-32 "0.14.9" - esbuild-linux-64 "0.14.9" - esbuild-linux-arm "0.14.9" - esbuild-linux-arm64 "0.14.9" - esbuild-linux-mips64le "0.14.9" - esbuild-linux-ppc64le "0.14.9" - esbuild-linux-s390x "0.14.9" - esbuild-netbsd-64 "0.14.9" - esbuild-openbsd-64 "0.14.9" - esbuild-sunos-64 "0.14.9" - esbuild-windows-32 "0.14.9" - esbuild-windows-64 "0.14.9" - esbuild-windows-arm64 "0.14.9" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -fbjs-css-vars@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz" - integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== - -fbjs@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz" - integrity sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ== - dependencies: - core-js "^3.6.4" - cross-fetch "^3.0.4" - fbjs-css-vars "^1.0.0" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.18" - -file-selector@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/file-selector/-/file-selector-0.4.0.tgz" - integrity sha512-iACCiXeMYOvZqlF1kTiYINzgepRBymz1wwjiuup9u9nayhb6g4fSwiyJ/6adli+EPwrWtpgQAh2PoS7HukEGEg== - dependencies: - tslib "^2.0.3" - -find-root@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== - -focus-lock@^0.9.1: - version "0.9.2" - resolved "https://registry.npmjs.org/focus-lock/-/focus-lock-0.9.2.tgz" - integrity sha512-YtHxjX7a0IC0ZACL5wsX8QdncXofWpGPNoVMuI/nZUrPGp6LmNI6+D5j0pPj+v8Kw5EpweA+T5yImK0rnWf7oQ== - dependencies: - tslib "^2.0.3" - -focus-visible@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/focus-visible/-/focus-visible-5.2.0.tgz" - integrity sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ== - -framer-motion@^5.5.5, "framer-motion@3.x || 4.x || 5.x": - version "5.5.5" - resolved "https://registry.npmjs.org/framer-motion/-/framer-motion-5.5.5.tgz" - integrity sha512-+LPAF5ddo02qKh+MK4h1ChwqUFvrLkK1NDWwrHy+MuCVmQDGgiFNHvwqOSklTDGkEtbio3dCOEDy23+ZyNAa9g== - dependencies: - framesync "6.0.1" - hey-listen "^1.0.8" - popmotion "11.0.3" - react-merge-refs "^1.1.0" - react-use-measure "^2.1.1" - style-value-types "5.0.0" - tslib "^2.1.0" - optionalDependencies: - "@emotion/is-prop-valid" "^0.8.2" - -framesync@5.3.0: - version "5.3.0" - resolved "https://registry.npmjs.org/framesync/-/framesync-5.3.0.tgz" - integrity sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA== - dependencies: - tslib "^2.1.0" - -framesync@6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz" - integrity sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA== - dependencies: - tslib "^2.1.0" - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-nonce@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz" - integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -"graphql@^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "graphql@^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", graphql@^16.2.0: - version "16.2.0" - resolved "https://registry.npmjs.org/graphql/-/graphql-16.2.0.tgz" - integrity sha512-MuQd7XXrdOcmfwuLwC2jNvx0n3rxIuNYOxUtiee5XOmfrWo613ar2U8pE7aHAKh8VwfpifubpD9IP+EdEAEOsA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hey-listen@^1.0.8: - version "1.0.8" - resolved "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz" - integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q== - -history@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/history/-/history-5.2.0.tgz" - integrity sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig== - dependencies: - "@babel/runtime" "^7.7.6" - -hoist-non-react-statics@^3.3.1: - version "3.3.2" - resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - -html-to-draftjs@^1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/html-to-draftjs/-/html-to-draftjs-1.5.0.tgz" - integrity sha512-kggLXBNciKDwKf+KYsuE+V5gw4dZ7nHyGMX9m0wy7urzWjKGWyNFetmArRLvRV0VrxKN70WylFsJvMTJx02OBQ== - -immutable@~3.7.4: - version "3.7.6" - resolved "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz" - integrity sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw== - -"immutable@3.x.x || 4.x.x": - version "4.3.4" - resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz" - integrity sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA== - -import-fresh@^3.1.0: - version "3.3.0" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-core-module@^2.2.0: - version "2.8.0" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz" - integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== - dependencies: - has "^1.0.3" - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json5@^2.2.3: - version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -linkify-it@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz" - integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw== - dependencies: - uc.micro "^1.0.1" - -lodash.mergewith@4.6.2: - version "4.6.2" - resolved "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz" - integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== - -lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -node-fetch@^2.6.12: - version "2.7.0" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - -node-releases@^2.0.13: - version "2.0.13" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz" - integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== - -object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-json@^5.0.0: - version "5.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -path-parse@^1.0.6: - version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -popmotion@11.0.3: - version "11.0.3" - resolved "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz" - integrity sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA== - dependencies: - framesync "6.0.1" - hey-listen "^1.0.8" - style-value-types "5.0.0" - tslib "^2.1.0" - -prettier@2.7.1: - version "2.7.1" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz" - integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== - -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz" - integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== - dependencies: - asap "~2.0.3" - -prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - -react-clientside-effect@^1.2.5: - version "1.2.5" - resolved "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz" - integrity sha512-2bL8qFW1TGBHozGGbVeyvnggRpMjibeZM2536AKNENLECutp2yfs44IL8Hmpn8qjFQ2K7A9PnYf3vc7aQq/cPA== - dependencies: - "@babel/runtime" "^7.12.13" - -"react-dom@^16.8.0 || 17.x", react-dom@^17.0.2, react-dom@>=0.14.0, react-dom@>=16.13, react-dom@>=16.8, "react-dom@>=16.8 || ^17.0.0", react-dom@>=16.8.6, "react-dom@0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x": - version "17.0.2" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" - -react-draft-wysiwyg@^1.15.0: - version "1.15.0" - resolved "https://registry.npmjs.org/react-draft-wysiwyg/-/react-draft-wysiwyg-1.15.0.tgz" - integrity sha512-p1cYZcWc6/ALFBVksbFoCM3b29fGQDlZLIMrXng0TU/UElxIOF2/AWWo4L5auIYVhmqKTZ0NkNjnXOzGGuxyeA== - dependencies: - classnames "^2.2.6" - draftjs-utils "^0.10.2" - html-to-draftjs "^1.5.0" - linkify-it "^2.2.0" - prop-types "^15.7.2" - -react-dropzone@^12.0.4: - version "12.0.4" - resolved "https://registry.npmjs.org/react-dropzone/-/react-dropzone-12.0.4.tgz" - integrity sha512-fcqHEYe1MzAghU6/Hz86lHDlBNsA+lO48nAcm7/wA+kIzwS6uuJbUG33tBZjksj7GAZ1iUQ6NHwjUURPmSGang== - dependencies: - attr-accept "^2.2.2" - file-selector "^0.4.0" - prop-types "^15.8.1" - -react-email-editor@^1.6.1: - version "1.6.1" - resolved "https://registry.npmjs.org/react-email-editor/-/react-email-editor-1.6.1.tgz" - integrity sha512-pEWpRmTY0ok03cwTGqEOoEldnzThhuRGTrcMnv8W3/jc5MTfcr9USU/IQ9HrVvFStLKoxYBIQnSKY+iCYWOtSQ== - -react-fast-compare@3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz" - integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== - -react-focus-lock@2.5.2: - version "2.5.2" - resolved "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.5.2.tgz" - integrity sha512-WzpdOnEqjf+/A3EH9opMZWauag7gV0BxFl+EY4ElA4qFqYsUsBLnmo2sELbN5OC30S16GAWMy16B9DLPpdJKAQ== - dependencies: - "@babel/runtime" "^7.0.0" - focus-lock "^0.9.1" - prop-types "^15.6.2" - react-clientside-effect "^1.2.5" - use-callback-ref "^1.2.5" - use-sidecar "^1.0.5" - -react-icons@^4.3.1: - version "4.3.1" - resolved "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz" - integrity sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ== - -react-is@^16.13.1, react-is@^16.7.0: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-merge-refs@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz" - integrity sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ== - -react-remove-scroll-bar@^2.1.0: - version "2.2.0" - resolved "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.2.0.tgz" - integrity sha512-UU9ZBP1wdMR8qoUs7owiVcpaPwsQxUDC2lypP6mmixaGlARZa7ZIBx1jcuObLdhMOvCsnZcvetOho0wzPa9PYg== - dependencies: - react-style-singleton "^2.1.0" - tslib "^1.0.0" - -react-remove-scroll@2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.4.1.tgz" - integrity sha512-K7XZySEzOHMTq7dDwcHsZA6Y7/1uX5RsWhRXVYv8rdh+y9Qz2nMwl9RX/Mwnj/j7JstCGmxyfyC0zbVGXYh3mA== - dependencies: - react-remove-scroll-bar "^2.1.0" - react-style-singleton "^2.1.0" - tslib "^1.0.0" - use-callback-ref "^1.2.3" - use-sidecar "^1.0.1" - -react-router-dom@^6.2.1: - version "6.2.1" - resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz" - integrity sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA== - dependencies: - history "^5.2.0" - react-router "6.2.1" - -react-router@6.2.1: - version "6.2.1" - resolved "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz" - integrity sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg== - dependencies: - history "^5.2.0" - -react-style-singleton@^2.1.0: - version "2.1.1" - resolved "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.1.1.tgz" - integrity sha512-jNRp07Jza6CBqdRKNgGhT3u9umWvils1xsuMOjZlghBDH2MU0PL2WZor4PGYjXpnRCa9DQSlHMs/xnABWOwYbA== - dependencies: - get-nonce "^1.0.0" - invariant "^2.2.4" - tslib "^1.0.0" - -react-use-measure@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz" - integrity sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig== - dependencies: - debounce "^1.2.1" - -react@*, "react@^15.3.0 || ^16.0.0 || ^17.0.0", "react@^16.8.0 || ^17.0.0", "react@^16.8.0 || 17.x", react@^17.0.2, "react@>= 16.8", "react@>= 16.8.0", react@>=0.14.0, react@>=16.13, react@>=16.8, "react@>=16.8 || ^17.0.0", react@>=16.8.0, react@>=16.8.6, "react@0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x", "react@15.x || 16.x || 17.x", react@17.0.2: - version "17.0.2" - resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve@^1.12.0: - version "1.20.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - -safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== - -source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -style-value-types@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz" - integrity sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA== - dependencies: - hey-listen "^1.0.8" - tslib "^2.1.0" - -stylis@4.0.13: - version "4.0.13" - resolved "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz" - integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -tiny-invariant@^1.0.6: - version "1.2.0" - resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz" - integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -toggle-selection@^1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz" - integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -tslib@^1.0.0: - version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^1.9.3: - version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.0.3, tslib@^2.1.0: - version "2.3.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - -typescript@^4.5.4: - version "4.5.4" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz" - integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== - -ua-parser-js@^0.7.18: - version "0.7.37" - resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz" - integrity sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA== - -uc.micro@^1.0.1: - version "1.0.6" - resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz" - integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== - -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -urql@^2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/urql/-/urql-2.0.6.tgz" - integrity sha512-ovK9mx7YxD/CKUwVZGbEDBzZjbCcNsr1990nIhDCKe3Ij/0gNcIa+0EIyXKceOPuYDYKavIoaNQV2kOZjQxFcw== - dependencies: - "@urql/core" "^2.3.6" - wonka "^4.0.14" - -use-callback-ref@^1.2.3, use-callback-ref@^1.2.5: - version "1.2.5" - resolved "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz" - integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg== - -use-sidecar@^1.0.1, use-sidecar@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.0.5.tgz" - integrity sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA== - dependencies: - detect-node-es "^1.1.0" - tslib "^1.9.3" - -warning@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz" - integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== - dependencies: - loose-envify "^1.0.0" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -wonka@^4.0.14: - version "4.0.15" - resolved "https://registry.npmjs.org/wonka/-/wonka-4.0.15.tgz" - integrity sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yaml@^1.7.2: - version "1.10.2" - resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== diff --git a/server/go.mod b/go.mod similarity index 74% rename from server/go.mod rename to go.mod index fc6045dd5..83fb96480 100644 --- a/server/go.mod +++ b/go.mod @@ -1,11 +1,9 @@ -module github.com/authorizerdev/authorizer/server +module github.com/authorizerdev/authorizer -go 1.21 - -toolchain go1.21.4 +go 1.24.2 require ( - github.com/99designs/gqlgen v0.17.45 + github.com/99designs/gqlgen v0.17.73 github.com/arangodb/go-driver v1.6.0 github.com/aws/aws-sdk-go v1.47.4 github.com/coreos/go-oidc/v3 v3.6.0 @@ -14,23 +12,21 @@ require ( github.com/gin-gonic/gin v1.9.1 github.com/glebarez/sqlite v1.10.0 github.com/gocql/gocql v1.6.0 - github.com/gokyle/twofactor v1.0.1 - github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/golang-jwt/jwt/v4 v4.5.2 github.com/google/uuid v1.6.0 github.com/guregu/dynamo v1.20.2 - github.com/joho/godotenv v1.5.1 github.com/pquerna/otp v1.4.0 - github.com/redis/go-redis/v9 v9.2.1 + github.com/redis/go-redis/v9 v9.6.3 github.com/robertkrimen/otto v0.2.1 - github.com/sirupsen/logrus v1.9.3 - github.com/stretchr/testify v1.9.0 - github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d + github.com/rs/zerolog v1.33.0 + github.com/spf13/cobra v1.8.1 + github.com/stretchr/testify v1.10.0 github.com/twilio/twilio-go v1.14.1 - github.com/vektah/gqlparser/v2 v2.5.11 + github.com/vektah/gqlparser/v2 v2.5.26 go.mongodb.org/mongo-driver v1.12.1 - golang.org/x/crypto v0.21.0 - golang.org/x/oauth2 v0.13.0 - google.golang.org/appengine v1.6.8 + golang.org/x/crypto v0.46.0 + golang.org/x/oauth2 v0.30.0 + golang.org/x/sync v0.19.0 gopkg.in/mail.v2 v2.3.1 gopkg.in/square/go-jose.v2 v2.6.0 gorm.io/driver/mysql v1.5.2 @@ -40,27 +36,28 @@ require ( ) require ( - github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/agnivade/levenshtein v1.2.1 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 // indirect github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/couchbase/gocbcore/v10 v10.2.8 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/glebarez/go-sqlite v1.21.2 // indirect - github.com/go-jose/go-jose/v3 v3.0.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.4 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect @@ -70,9 +67,11 @@ require ( github.com/gorilla/websocket v1.5.0 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgx/v5 v5.4.3 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.5.4 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -82,10 +81,9 @@ require ( github.com/leodido/go-urn v1.2.4 // indirect github.com/libsql/libsql-client-go v0.0.0-20231026052543-fce76c0f39a7 // indirect github.com/libsql/sqlite-antlr4-parser v0.0.0-20230802215326-5cb5bb604475 // indirect - github.com/maruel/rs v1.1.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/microsoft/go-mssqldb v1.6.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.7.0 // indirect @@ -95,24 +93,24 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sosodev/duration v1.2.0 // indirect + github.com/sosodev/duration v1.3.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect - github.com/urfave/cli/v2 v2.27.1 // indirect + github.com/urfave/cli/v2 v2.27.6 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/mod v0.16.0 // indirect - golang.org/x/net v0.22.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.19.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.32.0 // indirect + golang.org/x/tools v0.39.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect @@ -122,5 +120,4 @@ require ( modernc.org/memory v1.5.0 // indirect modernc.org/sqlite v1.23.1 // indirect nhooyr.io/websocket v1.8.7 // indirect - rsc.io/qr v0.2.0 // indirect ) diff --git a/server/go.sum b/go.sum similarity index 84% rename from server/go.sum rename to go.sum index 4ce25c18b..c3327f3b7 100644 --- a/server/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/99designs/gqlgen v0.17.45 h1:bH0AH67vIJo8JKNKPJP+pOPpQhZeuVRQLf53dKIpDik= -github.com/99designs/gqlgen v0.17.45/go.mod h1:Bas0XQ+Jiu/Xm5E33jC8sES3G+iC2esHBMXcq0fUPs0= +github.com/99designs/gqlgen v0.17.73 h1:A3Ki+rHWqKbAOlg5fxiZBnz6OjW3nwupDHEG15gEsrg= +github.com/99designs/gqlgen v0.17.73/go.mod h1:2RyGWjy2k7W9jxrs8MOQthXGkD3L3oGr0jXW3Pu8lGg= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= @@ -18,14 +18,14 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= -github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI= -github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY= -github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= -github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo= +github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y= +github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= +github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= -github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= +github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= +github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/arangodb/go-driver v1.6.0 h1:NFWj/idqXZxhFVueihMSI2R9NotNIsgvNfM/xmpekb4= @@ -40,8 +40,6 @@ github.com/aws/aws-sdk-go v1.47.4/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3Tju github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= -github.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBEK16QnXY= -github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= @@ -55,13 +53,14 @@ github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/coreos/go-oidc/v3 v3.6.0 h1:AKVxfYw1Gmkn/w96z0DbT/B/xFnzTd3MkZvWLjF4n/o= github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/couchbase/gocb/v2 v2.6.4 h1:o5k5JnxYkgamVL9svx+vbXc7vKF5X72tNt/qORs+L30= github.com/couchbase/gocb/v2 v2.6.4/go.mod h1:W/cHlBGfendPh53WzRaF1KIXTovI9DaI7EPeeqIsnmc= github.com/couchbase/gocbcore/v10 v10.2.8 h1:Enjxyxd6XYIP0SSlKxt+GHL0J+A/GaLxGJZ13XCfOW4= @@ -69,16 +68,17 @@ github.com/couchbase/gocbcore/v10 v10.2.8/go.mod h1:lYQIIk+tzoMcwtwU5GzPbDdqEkwk github.com/couchbaselabs/gocaves/client v0.0.0-20230307083111-cc3960c624b1/go.mod h1:AVekAZwIY2stsJOMWLAS/0uA/+qdp7pjO8EHnl61QkY= github.com/couchbaselabs/gocaves/client v0.0.0-20230404095311-05e3ba4f0259 h1:2TXy68EGEzIMHOx9UvczR5ApVecwCfQZ0LjkmwMI6g4= github.com/couchbaselabs/gocaves/client v0.0.0-20230404095311-05e3ba4f0259/go.mod h1:AVekAZwIY2stsJOMWLAS/0uA/+qdp7pjO8EHnl61QkY= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= -github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo= +github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -96,8 +96,8 @@ github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9g github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc= github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA= -github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= -github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= +github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -112,6 +112,8 @@ github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= @@ -122,12 +124,13 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gocql/gocql v1.6.0 h1:IdFdOTbnpbd0pDhl4REKQDM+Q0SzKXQ1Yh+YZZ8T/qU= github.com/gocql/gocql v1.6.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= -github.com/gokyle/twofactor v1.0.1 h1:uRhvx0S4Hb82RPIDALnf7QxbmPL49LyyaCkJDpWx+Ek= -github.com/gokyle/twofactor v1.0.1/go.mod h1:4gxzH1eaE/F3Pct/sCDNOylP0ClofUO5j4XZN9tKtLE= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= @@ -139,7 +142,6 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -147,11 +149,11 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= @@ -172,12 +174,16 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= -github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= +github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= @@ -192,8 +198,6 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -222,17 +226,18 @@ github.com/libsql/sqlite-antlr4-parser v0.0.0-20230802215326-5cb5bb604475 h1:6Pf github.com/libsql/sqlite-antlr4-parser v0.0.0-20230802215326-5cb5bb604475/go.mod h1:20nXSmcf0nAscrzqsXeC2/tA3KkV2eCiJqYuyAgl+ss= github.com/localtunnel/go-localtunnel v0.0.0-20170326223115-8a804488f275 h1:IZycmTpoUtQK3PD60UYBwjaCUHUP7cML494ao9/O8+Q= github.com/localtunnel/go-localtunnel v0.0.0-20170326223115-8a804488f275/go.mod h1:zt6UU74K6Z6oMOYJbJzYpYucqdcQwSMPBEdSvGiaUMw= -github.com/maruel/rs v1.1.0 h1:dh4OceAF5yD06EASOrb+DS358LI4g0B90YApSdjCP6U= -github.com/maruel/rs v1.1.0/go.mod h1:vzwMjzSJJxLIXmU62qHj6O5QRn5kvCKxFrfaFCxBcUY= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc= github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -254,8 +259,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= -github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg= -github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/redis/go-redis/v9 v9.6.3 h1:8Dr5ygF1QFXRxIH/m3Xg9MMG1rS8YCtAgosrsewT6i0= +github.com/redis/go-redis/v9 v9.6.3/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -263,14 +268,19 @@ github.com/robertkrimen/otto v0.2.1 h1:FVP0PJ0AHIjC+N4pKCG9yCDz6LHNPCwi/GKID5pGG github.com/robertkrimen/otto v0.2.1/go.mod h1:UPwtJ1Xu7JrLcZjNWN8orJaM5n5YEtqL//farB5FlRY= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/sosodev/duration v1.2.0 h1:pqK/FLSjsAADWY74SyWDCjOcd5l7H8GSnnOGEB9A1Us= -github.com/sosodev/duration v1.2.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= +github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4= +github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -279,7 +289,6 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -287,10 +296,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d h1:4x1FeGJRB00cvxnKXnRJDT89fvG/Lzm2ecm0vlr/qDs= -github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d/go.mod h1:uSELzeIcTceNCgzbKdJuJa0ouCqqtkyzL+6bnA3rM+M= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/twilio/twilio-go v1.14.1 h1:uyMwNe2naFKwxLpVflAHbKEPiW9iHNI8VF6NWLJJ1Kk= github.com/twilio/twilio-go v1.14.1/go.mod h1:tdnfQ5TjbewoAu4lf9bMsGvfuJ/QU9gYuv9yx3TSIXU= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= @@ -299,18 +306,18 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= -github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8= -github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= +github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g= +github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/vektah/gqlparser/v2 v2.5.26 h1:REqqFkO8+SOEgZHR/eHScjjVjGS8Nk3RMO/juiTobN4= +github.com/vektah/gqlparser/v2 v2.5.26/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -321,7 +328,6 @@ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUu golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -330,15 +336,16 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58 golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -353,17 +360,17 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -376,15 +383,17 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -392,6 +401,7 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -403,26 +413,25 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -466,5 +475,3 @@ modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY= -rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs= diff --git a/server/gqlgen.yml b/gqlgen.yml similarity index 88% rename from server/gqlgen.yml rename to gqlgen.yml index 104bdab25..2258e4196 100644 --- a/server/gqlgen.yml +++ b/gqlgen.yml @@ -1,26 +1,26 @@ # Where are all the schema files located? globs are supported eg src/**/*.graphqls schema: - - graph/*.graphqls + - internal/graph/*.graphqls # Where should the generated server code go? exec: - filename: graph/generated/generated.go + filename: internal/graph/generated/generated.go package: generated # Uncomment to enable federation # federation: -# filename: graph/generated/federation.go +# filename: internal/graph/generated/federation.go # package: generated # Where should any generated models go? model: - filename: graph/model/models_gen.go + filename: internal/graph/model/models_gen.go package: model # Where should the resolver implementations go? resolver: layout: follow-schema - dir: graph + dir: internal/graph package: graph # Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models @@ -42,7 +42,7 @@ resolver: # gqlgen will search for any type names in the schema in these go packages # if they match it will use them, otherwise it will generate them. autobind: -# - "github.com/authorizerdev/authorizer/server/graph/model" +# - "github.com/authorizerdev/authorizer/internal/internal/graph/model" # This section declares type mapping between the GraphQL and go type systems # diff --git a/internal/authenticators/config/config.go b/internal/authenticators/config/config.go new file mode 100644 index 000000000..7d4834802 --- /dev/null +++ b/internal/authenticators/config/config.go @@ -0,0 +1,13 @@ +package config + +// AuthenticatorConfig defines authenticator config +type AuthenticatorConfig struct { + // ScannerImage is the base64 of QR code image + ScannerImage string + // Secrets is the secret key + Secret string + // RecoveryCode is the list of recovery codes + RecoveryCodes []string + // RecoveryCodeMap is the map of recovery codes + RecoveryCodeMap map[string]bool +} diff --git a/internal/authenticators/providers.go b/internal/authenticators/providers.go new file mode 100644 index 000000000..a22c5e82c --- /dev/null +++ b/internal/authenticators/providers.go @@ -0,0 +1,38 @@ +package authenticators + +import ( + "context" + + ac "github.com/authorizerdev/authorizer/internal/authenticators/config" + "github.com/authorizerdev/authorizer/internal/authenticators/totp" + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/storage" + "github.com/rs/zerolog" +) + +// Dependencies defines the dependencies for authenticators provider +type Dependencies struct { + Log *zerolog.Logger + StorageProvider storage.Provider +} + +// Provider defines authenticators provider +type Provider interface { + // Generate totp: to generate totp, store secret into db and returns base64 of QR code image + Generate(ctx context.Context, id string) (*ac.AuthenticatorConfig, error) + // Validate totp: user passcode with secret stored in our db + Validate(ctx context.Context, passcode string, userID string) (bool, error) + // ValidateRecoveryCode totp: allows user to validate using recovery code incase if they lost their device + ValidateRecoveryCode(ctx context.Context, recoveryCode, userID string) (bool, error) +} + +// New returns a new authenticators provider +func New(cfg *config.Config, deps *Dependencies) (Provider, error) { + if !cfg.EnableTOTPLogin { + return nil, nil + } + return totp.NewProvider(&totp.Dependencies{ + Log: deps.Log, + StorageProvider: deps.StorageProvider, + }) +} diff --git a/internal/authenticators/totp/provider.go b/internal/authenticators/totp/provider.go new file mode 100644 index 000000000..04231c341 --- /dev/null +++ b/internal/authenticators/totp/provider.go @@ -0,0 +1,29 @@ +package totp + +import ( + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/storage" +) + +type Dependencies struct { + Log *zerolog.Logger + StorageProvider storage.Provider +} + +type provider struct { + deps *Dependencies +} + +// TOTPConfig defines totp config +type TOTPConfig struct { + ScannerImage string + Secret string +} + +// NewProvider returns a new totp provider +func NewProvider(deps *Dependencies) (*provider, error) { + return &provider{ + deps: deps, + }, nil +} diff --git a/server/authenticators/providers/totp/totp.go b/internal/authenticators/totp/totp.go similarity index 70% rename from server/authenticators/providers/totp/totp.go rename to internal/authenticators/totp/totp.go index b02fe293e..e96799b66 100644 --- a/server/authenticators/providers/totp/totp.go +++ b/internal/authenticators/totp/totp.go @@ -10,25 +10,24 @@ import ( "github.com/google/uuid" "github.com/pquerna/otp/totp" - log "github.com/sirupsen/logrus" - "github.com/authorizerdev/authorizer/server/authenticators/providers" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/refs" + "github.com/authorizerdev/authorizer/internal/authenticators/config" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // Generate generates a Time-Based One-Time Password (TOTP) for a user and returns the base64-encoded QR code for frontend display. -func (p *provider) Generate(ctx context.Context, id string) (*providers.AuthenticatorConfig, error) { +func (p *provider) Generate(ctx context.Context, id string) (*config.AuthenticatorConfig, error) { + log := p.deps.Log.With().Str("func", "Generate (totp provider)").Logger() var buf bytes.Buffer - //get user details - user, err := db.Provider.GetUserByID(ctx, id) + // Get user details + user, err := p.deps.StorageProvider.GetUserByID(ctx, id) if err != nil { return nil, err } - // generate totp, Authenticators hash is valid for 30 seconds + // Generate totp, Authenticators hash is valid for 30 seconds key, err := totp.Generate(totp.GenerateOpts{ Issuer: "authorizer", AccountName: refs.StringValue(user.Email), @@ -36,7 +35,7 @@ func (p *provider) Generate(ctx context.Context, id string) (*providers.Authenti if err != nil { return nil, err } - //generating image for key and encoding to base64 for displaying in frontend + // Generating image for key and encoding to base64 for displaying in frontend img, err := key.Image(200, 200) if err != nil { return nil, err @@ -59,20 +58,20 @@ func (p *provider) Generate(ctx context.Context, id string) (*providers.Authenti return nil, err } recoveryCodesString := string(jsonData) - totpModel := &models.Authenticator{ + totpModel := &schemas.Authenticator{ Secret: secret, RecoveryCodes: refs.NewStringRef(recoveryCodesString), UserID: user.ID, Method: constants.EnvKeyTOTPAuthenticator, } - authenticator, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, user.ID, constants.EnvKeyTOTPAuthenticator) + authenticator, err := p.deps.StorageProvider.GetAuthenticatorDetailsByUserId(ctx, user.ID, constants.EnvKeyTOTPAuthenticator) if err != nil { - log.Debug("Failed to get authenticator details by user id, creating new record: ", err) + log.Debug().Err(err).Msg("error getting authenticator details") // continue } if authenticator == nil { // if authenticator is nil then create new authenticator - _, err = db.Provider.AddAuthenticator(ctx, totpModel) + _, err = p.deps.StorageProvider.AddAuthenticator(ctx, totpModel) if err != nil { return nil, err } @@ -80,12 +79,12 @@ func (p *provider) Generate(ctx context.Context, id string) (*providers.Authenti authenticator.Secret = secret authenticator.RecoveryCodes = refs.NewStringRef(recoveryCodesString) // if authenticator is not nil then update authenticator - _, err = db.Provider.UpdateAuthenticator(ctx, authenticator) + _, err = p.deps.StorageProvider.UpdateAuthenticator(ctx, authenticator) if err != nil { return nil, err } } - return &providers.AuthenticatorConfig{ + return &config.AuthenticatorConfig{ ScannerImage: encodedText, Secret: secret, RecoveryCodes: recoveryCodes, @@ -96,7 +95,7 @@ func (p *provider) Generate(ctx context.Context, id string) (*providers.Authenti // Validate validates a Time-Based One-Time Password (TOTP) against the stored TOTP secret for a user. func (p *provider) Validate(ctx context.Context, passcode string, userID string) (bool, error) { // get totp details - totpModel, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, userID, constants.EnvKeyTOTPAuthenticator) + totpModel, err := p.deps.StorageProvider.GetAuthenticatorDetailsByUserId(ctx, userID, constants.EnvKeyTOTPAuthenticator) if err != nil { return false, err } @@ -106,7 +105,7 @@ func (p *provider) Validate(ctx context.Context, passcode string, userID string) if totpModel.VerifiedAt == nil && status { timeNow := time.Now().Unix() totpModel.VerifiedAt = &timeNow - _, err = db.Provider.UpdateAuthenticator(ctx, totpModel) + _, err = p.deps.StorageProvider.UpdateAuthenticator(ctx, totpModel) if err != nil { return false, err } @@ -117,7 +116,7 @@ func (p *provider) Validate(ctx context.Context, passcode string, userID string) // ValidateRecoveryCode validates a Time-Based One-Time Password (TOTP) recovery code against the stored TOTP recovery code for a user. func (p *provider) ValidateRecoveryCode(ctx context.Context, recoveryCode, userID string) (bool, error) { // get totp details - totpModel, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, userID, constants.EnvKeyTOTPAuthenticator) + totpModel, err := p.deps.StorageProvider.GetAuthenticatorDetailsByUserId(ctx, userID, constants.EnvKeyTOTPAuthenticator) if err != nil { return false, err } @@ -143,7 +142,7 @@ func (p *provider) ValidateRecoveryCode(ctx context.Context, recoveryCode, userI recoveryCodesString := string(jsonData) totpModel.RecoveryCodes = refs.NewStringRef(recoveryCodesString) // update recovery code map in db - _, err = db.Provider.UpdateAuthenticator(ctx, totpModel) + _, err = p.deps.StorageProvider.UpdateAuthenticator(ctx, totpModel) if err != nil { return false, err } diff --git a/internal/authenticators/totp_store.go b/internal/authenticators/totp_store.go new file mode 100644 index 000000000..306ac68df --- /dev/null +++ b/internal/authenticators/totp_store.go @@ -0,0 +1,20 @@ +package authenticators + +// TODO delete file +// Provider is the global authenticators provider. +// var Provider providers.Provider + +// InitTOTPStore initializes the TOTP authenticator store if it's not disabled in the environment variables. +// It sets the global Provider variable to a new TOTP provider. +// func InitTOTPStore() error { +// var err error +// isTOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin) + +// if !isTOTPEnvServiceDisabled { +// Provider, err = totp.NewProvider() +// if err != nil { +// return err +// } +// } +// return nil +// } diff --git a/server/cli/cli.go b/internal/cli/cli.go similarity index 100% rename from server/cli/cli.go rename to internal/cli/cli.go diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 000000000..fabdb48e8 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,243 @@ +package config + +// Config defines the configuration for the authorizer instance +type Config struct { + // Env is the environment of the authorizer instance + Env string + // OrganizationLogo is the logo of the organization + OrganizationLogo string + // OrganizationName is the name of the organization + OrganizationName string + // AdminSecret is the secret for the admin + AdminSecret string + // AllowedOrigins is the list of allowed origins + AllowedOrigins []string + + // EnableLoginPage is the flag to enable login page + EnableLoginPage bool + // EnablePlayground is the flag to enable playground + EnablePlayground bool + + // Database Configurations + // DatabaseType is the type of database to use + DatabaseType string + // DatabaseURL is the URL of the database + DatabaseURL string + // DatabaseName is the name of the database + DatabaseName string + // DatabaseUsername is the username for the database + DatabaseUsername string + // DatabasePassword is the password for the database + DatabasePassword string + // DatabaseHost is the host for the database + DatabaseHost string + // DatabasePort is the port for the database + DatabasePort int + // DatabaseCert is the certificate for the database + DatabaseCert string + // DatabaseCACert is the CA certificate for the database + DatabaseCACert string + // DatabaseCertKey is the certificate key for the database + DatabaseCertKey string + + // CouchBase flags + // CouchBaseBucket is the bucket for the database + // Used only for CouchBase database + CouchBaseBucket string + // CouchBaseRamQuota is the RAM quota for the database + // Used only for CouchBase database + CouchBaseRamQuota string + // CouchBaseScope is the scope for the database + // Used only for CouchBase database + CouchBaseScope string + + // AWS flags + // AWSRegion is the region for the database + // Used only for AWS database + AWSRegion string + // AWSAccessKeyID is the access key ID for the database + // Used only for AWS database + AWSAccessKeyID string + // AWSSecretAccessKey is the secret access key for the database + // Used only for AWS database + AWSSecretAccessKey string + + // Email Configurations + // SMTPHost is the host for the SMTP server + SMTPHost string + // SMTPPort is the port for the SMTP server + SMTPPort int + // SMTPUsername is the username for the SMTP server + SMTPUsername string + // SMTPPassword is the password for the SMTP server + SMTPPassword string + // SMTPSenderEmail is the sender email for the SMTP server + SMTPSenderEmail string + // SMTPSenderName is the sender name for the SMTP server + SMTPSenderName string + // SMTPLocalName is the local name for the SMTP server + SMTPLocalName string + // SkipTLSVerification is the flag to skip TLS verification + SkipTLSVerification bool + + // Memory Store Configurations + // RedisURL is the URL of the redis server + RedisURL string + + // Auth Configurations + // DefaultRoles is the default roles for the user + // It is a comma separated string + // TODO: check derived keys + DefaultRoles []string + // Roles is the list of all the roles of the user + // It is a comma separated string + Roles []string + // ProtectedRoles is the list of all the protected roles + // For this roles, sign-up is disabled + // It is a comma separated string + ProtectedRoles []string + // EnableStrongPassword is the flag to enable strong password + EnableStrongPassword bool + // EnableTOTPLogin boolean to enable TOTP login + EnableTOTPLogin bool + // EnableBasicAuthentication boolean to enable basic authentication + EnableBasicAuthentication bool + // EnableMagicLinkLogin boolean to enable magic link login + EnableMagicLinkLogin bool + // EnableEmailVerification boolean to enable email verification + EnableEmailVerification bool + // EnableMobileBasicAuthentication boolean to enable mobile basic authentication + EnableMobileBasicAuthentication bool + // EnablePhoneVerification boolean to enable phone verification + EnablePhoneVerification bool + // EnableMFA boolean to enable MFA + EnableMFA bool + // EnableEmailOTP boolean to enable email OTP + EnableEmailOTP bool + // EnableSMSOTP boolean to enable SMS OTP + EnableSMSOTP bool + // EnableSignup boolean to enable signup + EnableSignup bool + // IsEmailServiceEnabled is derived from SMTP configurations + IsEmailServiceEnabled bool + // IsSMSServiceEnabled is derived from Twilio configurations + IsSMSServiceEnabled bool + // EnforceMFA is the flag to enforce MFA + EnforceMFA bool + + // URLs + // ResetPasswordURL is the URL for reset password + ResetPasswordURL string + + // JWT Configurations + // JWTType is the type of JWT to use + JWTType string + // JWTSecret is the secret for the JWT + JWTSecret string + // JWTPublicKey is the public key for the JWT + JWTPublicKey string + // JWTPrivateKey is the private key for the JWT + JWTPrivateKey string + // JWTRoleClaim is the role claim for the JWT + JWTRoleClaim string + // CustomAccessTokenScript is the custom access token script + CustomAccessTokenScript string + + // OAuth Configurations + // ClientID is the client ID for the authorizer + ClientID string + // ClientSecret is the secret for the authorizer + ClientSecret string + // Default Authorize response mode + DefaultAuthorizeResponseMode string + // Default Authorize response type + DefaultAuthorizeResponseType string + + // Twilio Configurations + // TwilioAPISecret is the API secret for Twilio + TwilioAPISecret string + // TwilioAPIKey is the API key for Twilio + TwilioAPIKey string + // TwilioSender is the sender for Twilio + TwilioSender string + // TwilioAccountSID is the account SID for Twilio + TwilioAccountSID string + + // OAuth providers that authorizer supports + // GoogleClientID is the client ID for Google OAuth + GoogleClientID string + // GoogleClientSecret is the client secret for Google OAuth + GoogleClientSecret string + // Scopes is the list of scopes for Google OAuth + GoogleScopes []string + + // GithubClientID is the client ID for Github OAuth + GithubClientID string + // GithubClientSecret is the client secret for Github OAuth + GithubClientSecret string + // GithubScopes is the list of scopes for Github OAuth + GithubScopes []string + + // FacebookClientID is the client ID for Facebook OAuth + FacebookClientID string + // FacebookClientSecret is the client secret for Facebook OAuth + FacebookClientSecret string + // FacebookScopes is the list of scopes for Facebook OAuth + FacebookScopes []string + + // LinkedinClientID is the client ID for Linkedin OAuth + LinkedinClientID string + // LinkedinClientSecret is the client secret for Linkedin OAuth + LinkedinClientSecret string + // LinkedinScopes is the list of scopes for Linkedin OAuth + LinkedinScopes []string + + // TwitterClientID is the client ID for Twitter OAuth + TwitterClientID string + // TwitterClientSecret is the client secret for Twitter OAuth + TwitterClientSecret string + // TwitterScopes is the list of scopes for Twitter OAuth + TwitterScopes []string + + // MicrosoftClientID is the client ID for Microsoft OAuth + MicrosoftClientID string + // MicrosoftClientSecret is the client secret for Microsoft OAuth + MicrosoftClientSecret string + // MicrosoftTenantID is the tenant ID for Microsoft OAuth + MicrosoftTenantID string + // MicrosoftScopes is the list of scopes for Microsoft OAuth + MicrosoftScopes []string + + // AppleClientID is the client ID for Apple OAuth + AppleClientID string + // AppleClientSecret is the client secret for Apple OAuth + AppleClientSecret string + // AppleScopes is the list of scopes for Apple OAuth + AppleScopes []string + + // DiscordClientID is the client ID for Discord OAuth + DiscordClientID string + // DiscordClientSecret is the client secret for Discord OAuth + DiscordClientSecret string + // DiscordScopes is the list of scopes for Discord OAuth + DiscordScopes []string + + // TwitchClientID is the client ID for Twitch OAuth + TwitchClientID string + // TwitchClientSecret is the client secret for Twitch OAuth + TwitchClientSecret string + // TwitchScopes is the list of scopes for Twitch OAuth + TwitchScopes []string + + // RobloxClientID is the client ID for Roblox OAuth + RobloxClientID string + // RobloxClientSecret is the client secret for Roblox OAuth + RobloxClientSecret string + // RobloxScopes is the list of scopes for Roblox OAuth + RobloxScopes []string + + // IsAppCookieSecure is the flag to set secure(http only) cookie + AppCookieSecure bool + // IsAdminCookieSecure is the flag to set secure(http only) cookie + AdminCookieSecure bool +} diff --git a/server/constants/auth_methods.go b/internal/constants/auth_methods.go similarity index 99% rename from server/constants/auth_methods.go rename to internal/constants/auth_methods.go index ca2002fa6..659667b27 100644 --- a/server/constants/auth_methods.go +++ b/internal/constants/auth_methods.go @@ -9,6 +9,7 @@ const ( AuthRecipeMethodMagicLinkLogin = "magic_link_login" // AuthRecipeMethodMobileOTP is the mobile_otp auth method AuthRecipeMethodMobileOTP = "mobile_otp" + // AuthRecipeMethodGoogle is the google auth method AuthRecipeMethodGoogle = "google" // AuthRecipeMethodGithub is the github auth method diff --git a/server/constants/authenticator_method.go b/internal/constants/authenticator_method.go similarity index 100% rename from server/constants/authenticator_method.go rename to internal/constants/authenticator_method.go diff --git a/server/constants/cookie.go b/internal/constants/cookie.go similarity index 100% rename from server/constants/cookie.go rename to internal/constants/cookie.go diff --git a/server/constants/db_types.go b/internal/constants/db_types.go similarity index 82% rename from server/constants/db_types.go rename to internal/constants/db_types.go index 63ad637fb..d6d0777f2 100644 --- a/server/constants/db_types.go +++ b/internal/constants/db_types.go @@ -11,24 +11,29 @@ const ( DbTypeMysql = "mysql" // DbTypeSqlserver is the sqlserver database type DbTypeSqlserver = "sqlserver" - // DbTypeArangodb is the arangodb database type - DbTypeArangodb = "arangodb" - // DbTypeMongodb is the mongodb database type - DbTypeMongodb = "mongodb" // DbTypeYugabyte is the yugabyte database type DbTypeYugabyte = "yugabyte" // DbTypeMariaDB is the mariadb database type DbTypeMariaDB = "mariadb" - // DbTypeCassandra is the cassandra database type + // DbTypePlanetScaleDB is the planetscale database type + DbTypePlanetScaleDB = "planetscale" + // DbTypeCockroachDB is the cockroach database type + DbTypeCockroachDB = "cockroachdb" + + // DbTypeArangoDB is the arangodb database type + DbTypeArangoDB = "arangodb" + + // DbTypeMongoDB is the mongodb database type + DbTypeMongoDB = "mongodb" + + // DbTypeCassandraDB is the cassandra database type DbTypeCassandraDB = "cassandradb" // DbTypeScyllaDB is the scylla database type DbTypeScyllaDB = "scylladb" - // DbTypeCockroachDB is the cockroach database type - DbTypeCockroachDB = "cockroachdb" - // DbTypePlanetScaleDB is the planetscale database type - DbTypePlanetScaleDB = "planetscale" + // DbTypeDynamoDB is the Dynamo database type DbTypeDynamoDB = "dynamodb" + // DbTypeCouchbaseDB is the Couchbase database type DbTypeCouchbaseDB = "couchbase" ) diff --git a/internal/constants/env.go b/internal/constants/env.go new file mode 100644 index 000000000..be9761cd0 --- /dev/null +++ b/internal/constants/env.go @@ -0,0 +1,215 @@ +package constants + +var VERSION = "0.0.1" + +const ( + // TestEnv is used for testing + TestEnv = "test" + // // EnvKeyEnv key for env variable ENV + // EnvKeyEnv = "ENV" + // // EnvKeyEnvPath key for cli arg variable ENV_PATH + // EnvKeyEnvPath = "ENV_PATH" + // // EnvKeyAuthorizerURL key for env variable AUTHORIZER_URL + // EnvKeyAuthorizerURL = "AUTHORIZER_URL" + // // EnvKeyPort key for env variable PORT + // EnvKeyPort = "PORT" + // // EnvKeyAccessTokenExpiryTime key for env variable ACCESS_TOKEN_EXPIRY_TIME + // EnvKeyAccessTokenExpiryTime = "ACCESS_TOKEN_EXPIRY_TIME" + // // EnvKeyAdminSecret key for env variable ADMIN_SECRET + // EnvKeyAdminSecret = "ADMIN_SECRET" + // // EnvKeyDatabaseType key for env variable DATABASE_TYPE + // EnvKeyDatabaseType = "DATABASE_TYPE" + // // EnvKeyDatabaseURL key for env variable DATABASE_URL + // EnvKeyDatabaseURL = "DATABASE_URL" + // // EnvAwsRegion key for env variable AWS REGION + // EnvAwsRegion = "AWS_REGION" + // // EnvAwsAccessKeyID key for env variable AWS_ACCESS_KEY_ID + // EnvAwsAccessKeyID = "AWS_ACCESS_KEY_ID" + // // EnvAwsAccessKey key for env variable AWS_SECRET_ACCESS_KEY + // EnvAwsSecretAccessKey = "AWS_SECRET_ACCESS_KEY" + // // EnvKeyDatabaseName key for env variable DATABASE_NAME + // EnvKeyDatabaseName = "DATABASE_NAME" + // // EnvKeyDatabaseUsername key for env variable DATABASE_USERNAME + // EnvKeyDatabaseUsername = "DATABASE_USERNAME" + // // EnvKeyDatabasePassword key for env variable DATABASE_PASSWORD + // EnvKeyDatabasePassword = "DATABASE_PASSWORD" + // // EnvKeyDatabasePort key for env variable DATABASE_PORT + // EnvKeyDatabasePort = "DATABASE_PORT" + // // EnvKeyDatabaseHost key for env variable DATABASE_HOST + // EnvKeyDatabaseHost = "DATABASE_HOST" + // // EnvKeyDatabaseCert key for env variable DATABASE_CERT + // EnvKeyDatabaseCert = "DATABASE_CERT" + // // EnvKeyDatabaseCertKey key for env variable DATABASE_KEY + // EnvKeyDatabaseCertKey = "DATABASE_CERT_KEY" + // // EnvKeyDatabaseCACert key for env variable 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 = "SMTP_HOST" + // // EnvKeySmtpPort key for env variable SMTP_PORT + // EnvKeySmtpPort = "SMTP_PORT" + // // EnvKeySmtpUsername key for env variable SMTP_USERNAME + // EnvKeySmtpUsername = "SMTP_USERNAME" + // // EnvKeySmtpPassword key for env variable SMTP_PASSWORD + // EnvKeySmtpPassword = "SMTP_PASSWORD" + // // EnvKeySmtpLocalName key for env variable SMTP_LOCAL_NAME + // EnvKeySmtpLocalName = "SMTP_LOCAL_NAME" + // // EnvKeySenderEmail key for env variable SENDER_EMAIL + // EnvKeySenderEmail = "SENDER_EMAIL" + // // EnvKeySenderName key for env variable SENDER_NAME + // EnvKeySenderName = "SENDER_NAME" + // EnvKeyIsEmailServiceEnabled key for env variable IS_EMAIL_SERVICE_ENABLED + // EnvKeyIsEmailServiceEnabled = "IS_EMAIL_SERVICE_ENABLED" + // EnvKeyIsSMSServiceEnabled key for env variable IS_SMS_SERVICE_ENABLED + // EnvKeyIsSMSServiceEnabled = "IS_SMS_SERVICE_ENABLED" + // EnvKeyAppCookieSecure key for env variable APP_COOKIE_SECURE + // EnvKeyAppCookieSecure = "APP_COOKIE_SECURE" + // EnvKeyAdminCookieSecure key for env variable ADMIN_COOKIE_SECURE + // EnvKeyAdminCookieSecure = "ADMIN_COOKIE_SECURE" + // EnvKeyJwtType key for env variable JWT_TYPE + // EnvKeyJwtType = "JWT_TYPE" + // // EnvKeyJwtSecret key for env variable JWT_SECRET + // EnvKeyJwtSecret = "JWT_SECRET" + // // EnvKeyJwtPrivateKey key for env variable JWT_PRIVATE_KEY + // EnvKeyJwtPrivateKey = "JWT_PRIVATE_KEY" + // // EnvKeyJwtPublicKey key for env variable JWT_PUBLIC_KEY + // EnvKeyJwtPublicKey = "JWT_PUBLIC_KEY" + // EnvKeyAppURL key for env variable APP_URL + // EnvKeyAppURL = "APP_URL" + // EnvKeyRedisURL key for env variable REDIS_URL + // EnvKeyRedisURL = "REDIS_URL" + // EnvKeyResetPasswordURL key for env variable RESET_PASSWORD_URL + // EnvKeyResetPasswordURL = "RESET_PASSWORD_URL" + // EnvKeyJwtRoleClaim key for env variable JWT_ROLE_CLAIM + // EnvKeyJwtRoleClaim = "JWT_ROLE_CLAIM" + // EnvKeyGoogleClientID key for env variable GOOGLE_CLIENT_ID + // EnvKeyGoogleClientID = "GOOGLE_CLIENT_ID" + // // EnvKeyGoogleClientSecret key for env variable GOOGLE_CLIENT_SECRET + // EnvKeyGoogleClientSecret = "GOOGLE_CLIENT_SECRET" + // // EnvKeyGithubClientID key for env variable GITHUB_CLIENT_ID + // EnvKeyGithubClientID = "GITHUB_CLIENT_ID" + // // EnvKeyGithubClientSecret key for env variable GITHUB_CLIENT_SECRET + // EnvKeyGithubClientSecret = "GITHUB_CLIENT_SECRET" + // // EnvKeyFacebookClientID key for env variable FACEBOOK_CLIENT_ID + // EnvKeyFacebookClientID = "FACEBOOK_CLIENT_ID" + // // EnvKeyFacebookClientSecret key for env variable FACEBOOK_CLIENT_SECRET + // EnvKeyFacebookClientSecret = "FACEBOOK_CLIENT_SECRET" + // // EnvKeyLinkedinClientID key for env variable LINKEDIN_CLIENT_ID + // EnvKeyLinkedInClientID = "LINKEDIN_CLIENT_ID" + // // EnvKeyLinkedinClientSecret key for env variable LINKEDIN_CLIENT_SECRET + // EnvKeyLinkedInClientSecret = "LINKEDIN_CLIENT_SECRET" + // // EnvKeyAppleClientID key for env variable APPLE_CLIENT_ID + // EnvKeyAppleClientID = "APPLE_CLIENT_ID" + // // EnvKeyAppleClientSecret key for env variable APPLE_CLIENT_SECRET + // EnvKeyAppleClientSecret = "APPLE_CLIENT_SECRET" + // // EnvKeyDiscordClientID key for env variable DISCORD_CLIENT_ID + // EnvKeyDiscordClientID = "DISCORD_CLIENT_ID" + // // EnvKeyDiscordClientSecret key for env variable DISCORD_CLIENT_SECRET + // EnvKeyDiscordClientSecret = "DISCORD_CLIENT_SECRET" + // // EnvKeyTwitterClientID key for env variable TWITTER_CLIENT_ID + // EnvKeyTwitterClientID = "TWITTER_CLIENT_ID" + // // EnvKeyTwitterClientSecret key for env variable 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" + // // EnvKeyTwitchClientID key for env variable TWITCH_CLIENT_ID + // EnvKeyTwitchClientID = "TWITCH_CLIENT_ID" + // // EnvKeyTwitchClientSecret key for env variable TWITCH_CLIENT_SECRET + // EnvKeyTwitchClientSecret = "TWITCH_CLIENT_SECRET" + // // EnvKeyRobloxClientID key for env variable ROBLOX_CLIENT_ID + // EnvKeyRobloxClientID = "ROBLOX_CLIENT_ID" + // // EnvKeyRobloxClientSecret key for env variable ROBLOX_CLIENT_SECRET + // EnvKeyRobloxClientSecret = "ROBLOX_CLIENT_SECRET" + // // EnvKeyOrganizationName key for env variable ORGANIZATION_NAME + // EnvKeyOrganizationName = "ORGANIZATION_NAME" + // // EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO + // EnvKeyOrganizationLogo = "ORGANIZATION_LOGO" + // // EnvKeyCustomAccessTokenScript key for env variable CUSTOM_ACCESS_TOKEN_SCRIPT + // EnvKeyCustomAccessTokenScript = "CUSTOM_ACCESS_TOKEN_SCRIPT" + + // Not Exposed Keys + // EnvKeyClientID key for env variable CLIENT_ID + // EnvKeyClientID = "CLIENT_ID" + // // EnvKeyClientSecret key for env variable CLIENT_SECRET + // EnvKeyClientSecret = "CLIENT_SECRET" + // // EnvKeyEncryptionKey key for env variable ENCRYPTION_KEY + // EnvKeyEncryptionKey = "ENCRYPTION_KEY" + // // EnvKeyJWK key for env variable JWK + // EnvKeyJWK = "JWK" + + // Boolean variables + // EnvKeyIsProd key for env variable IS_PROD + // EnvKeyIsProd = "IS_PROD" + // // EnvKeyDisableEmailVerification key for env variable DISABLE_EMAIL_VERIFICATION + // EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION" + // // EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH + // EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION" + // // EnvKeyDisableBasicAuthentication key for env variable DISABLE_MOBILE_BASIC_AUTH + // EnvKeyDisableMobileBasicAuthentication = "DISABLE_MOBILE_BASIC_AUTHENTICATION" + // // EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN + // EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN" + // // EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE + // EnvKeyDisableLoginPage = "DISABLE_LOGIN_PAGE" + // // EnvKeyDisableSignUp key for env variable DISABLE_SIGN_UP + // EnvKeyDisableSignUp = "DISABLE_SIGN_UP" + // // EnvKeyDisableRedisForEnv key for env variable DISABLE_REDIS_FOR_ENV + // EnvKeyDisableRedisForEnv = "DISABLE_REDIS_FOR_ENV" + // EnvKeyDisableStrongPassword key for env variable DISABLE_STRONG_PASSWORD + // EnvKeyDisableStrongPassword = "DISABLE_STRONG_PASSWORD" + // EnvKeyEnforceMultiFactorAuthentication is key for env variable ENFORCE_MULTI_FACTOR_AUTHENTICATION + // If enforced and changed later on, existing user will have MFA but new user will not have MFA + // EnvKeyEnforceMultiFactorAuthentication = "ENFORCE_MULTI_FACTOR_AUTHENTICATION" + // EnvKeyDisableMultiFactorAuthentication is key for env variable DISABLE_MULTI_FACTOR_AUTHENTICATION + // this variable is used to completely disable multi factor authentication. It will have no effect on profile preference + // EnvKeyDisableMultiFactorAuthentication = "DISABLE_MULTI_FACTOR_AUTHENTICATION" + // EnvKeyDisableTOTPLogin is key for env variable DISABLE_TOTP_LOGIN + // this variable is used to completely disable totp verification + // EnvKeyDisableTOTPLogin = "DISABLE_TOTP_LOGIN" + // EnvKeyDisableMailOTPLogin is key for env variable DISABLE_MAIL_OTP_LOGIN + // this variable is used to completely disable totp verification + // EnvKeyDisableMailOTPLogin = "DISABLE_MAIL_OTP_LOGIN" + // EnvKeyDisablePhoneVerification is key for env variable DISABLE_PHONE_VERIFICATION + // this variable is used to disable phone verification + // EnvKeyDisablePhoneVerification = "DISABLE_PHONE_VERIFICATION" + // EnvKeyDisablePlayGround is key for env variable DISABLE_PLAYGROUND + // this variable will disable or enable playground use in dashboard + // EnvKeyDisablePlayGround = "DISABLE_PLAYGROUND" + + // Slice variables + // EnvKeyRoles key for env variable ROLES + // EnvKeyRoles = "ROLES" + // EnvKeyProtectedRoles key for env variable PROTECTED_ROLES + // EnvKeyProtectedRoles = "PROTECTED_ROLES" + // EnvKeyDefaultRoles key for env variable DEFAULT_ROLES + // EnvKeyDefaultRoles = "DEFAULT_ROLES" + // EnvKeyAllowedOrigins key for env variable ALLOWED_ORIGINS + // EnvKeyAllowedOrigins = "ALLOWED_ORIGINS" + + // For oauth/openid/authorize + // EnvKeyDefaultAuthorizeResponseType key for env variable DEFAULT_AUTHORIZE_RESPONSE_TYPE + // This env is used for setting default response type in authorize handler + // EnvKeyDefaultAuthorizeResponseType = "DEFAULT_AUTHORIZE_RESPONSE_TYPE" + // EnvKeyDefaultAuthorizeResponseMode key for env variable DEFAULT_AUTHORIZE_RESPONSE_MODE + // This env is used for setting default response mode in authorize handler + // EnvKeyDefaultAuthorizeResponseMode = "DEFAULT_AUTHORIZE_RESPONSE_MODE" + + // Twilio env variables + // EnvKeyTwilioAPIKey key for env variable TWILIO_API_KEY + // EnvKeyTwilioAPIKey = "TWILIO_API_KEY" + // // EnvKeyTwilioAPISecret key for env variable TWILIO_API_SECRET + // EnvKeyTwilioAPISecret = "TWILIO_API_SECRET" + // // EnvKeyTwilioAccountSID key for env variable TWILIO_ACCOUNT_SID + // EnvKeyTwilioAccountSID = "TWILIO_ACCOUNT_SID" + // // EnvKeyTwilioSender key for env variable TWILIO_SENDER + // EnvKeyTwilioSender = "TWILIO_SENDER" +) diff --git a/server/constants/oauth2.go b/internal/constants/oauth2.go similarity index 100% rename from server/constants/oauth2.go rename to internal/constants/oauth2.go diff --git a/server/constants/oauth_info_urls.go b/internal/constants/oauth_info_urls.go similarity index 100% rename from server/constants/oauth_info_urls.go rename to internal/constants/oauth_info_urls.go diff --git a/server/constants/pagination.go b/internal/constants/pagination.go similarity index 100% rename from server/constants/pagination.go rename to internal/constants/pagination.go diff --git a/server/constants/token_types.go b/internal/constants/token_types.go similarity index 100% rename from server/constants/token_types.go rename to internal/constants/token_types.go diff --git a/server/constants/verification_types.go b/internal/constants/verification_types.go similarity index 100% rename from server/constants/verification_types.go rename to internal/constants/verification_types.go diff --git a/server/constants/webhook_event.go b/internal/constants/webhook_event.go similarity index 100% rename from server/constants/webhook_event.go rename to internal/constants/webhook_event.go diff --git a/server/cookie/admin_cookie.go b/internal/cookie/admin_cookie.go similarity index 57% rename from server/cookie/admin_cookie.go rename to internal/cookie/admin_cookie.go index f03a945ac..d0e2b4b2b 100644 --- a/server/cookie/admin_cookie.go +++ b/internal/cookie/admin_cookie.go @@ -3,22 +3,14 @@ package cookie import ( "net/url" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" "github.com/gin-gonic/gin" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/parsers" ) // SetAdminCookie sets the admin cookie in the response -func SetAdminCookie(gc *gin.Context, token string) { - adminCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAdminCookieSecure) - if err != nil { - log.Debug("Error while getting admin cookie secure from env variable: %v", err) - adminCookieSecure = true - } - +func SetAdminCookie(gc *gin.Context, token string, adminCookieSecure bool) { secure := adminCookieSecure httpOnly := adminCookieSecure hostname := parsers.GetHost(gc) @@ -43,13 +35,7 @@ func GetAdminCookie(gc *gin.Context) (string, error) { } // DeleteAdminCookie sets the response cookie to empty -func DeleteAdminCookie(gc *gin.Context) { - adminCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAdminCookieSecure) - if err != nil { - log.Debug("Error while getting admin cookie secure from env variable: %v", err) - adminCookieSecure = true - } - +func DeleteAdminCookie(gc *gin.Context, adminCookieSecure bool) { secure := adminCookieSecure httpOnly := adminCookieSecure hostname := parsers.GetHost(gc) diff --git a/server/cookie/cookie.go b/internal/cookie/cookie.go similarity index 74% rename from server/cookie/cookie.go rename to internal/cookie/cookie.go index 7dd9ccf89..6f707b443 100644 --- a/server/cookie/cookie.go +++ b/internal/cookie/cookie.go @@ -4,22 +4,14 @@ import ( "net/http" "net/url" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" "github.com/gin-gonic/gin" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/parsers" ) // SetSession sets the session cookie in the response -func SetSession(gc *gin.Context, sessionID string) { - appCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAppCookieSecure) - if err != nil { - log.Debug("Error while getting app cookie secure from env variable: %v", err) - appCookieSecure = true - } - +func SetSession(gc *gin.Context, sessionID string, appCookieSecure bool) { secure := appCookieSecure httpOnly := appCookieSecure hostname := parsers.GetHost(gc) @@ -48,13 +40,7 @@ func SetSession(gc *gin.Context, sessionID string) { } // DeleteSession sets session cookies to expire -func DeleteSession(gc *gin.Context) { - appCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAppCookieSecure) - if err != nil { - log.Debug("Error while getting app cookie secure from env variable: %v", err) - appCookieSecure = true - } - +func DeleteSession(gc *gin.Context, appCookieSecure bool) { secure := appCookieSecure httpOnly := appCookieSecure hostname := parsers.GetHost(gc) diff --git a/server/cookie/mfa_session.go b/internal/cookie/mfa_session.go similarity index 74% rename from server/cookie/mfa_session.go rename to internal/cookie/mfa_session.go index 3fdcaacec..81256a5bf 100644 --- a/server/cookie/mfa_session.go +++ b/internal/cookie/mfa_session.go @@ -4,22 +4,16 @@ import ( "net/http" "net/url" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" "github.com/gin-gonic/gin" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/parsers" ) -// SetMfaSession sets the mfa session cookie in the response -func SetMfaSession(gc *gin.Context, sessionID string) { - appCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAppCookieSecure) - if err != nil { - log.Debug("Error while getting app cookie secure from env variable: %v", err) - appCookieSecure = true - } +// TODO set app cookie as per config +// SetMfaSession sets the mfa session cookie in the response +func SetMfaSession(gc *gin.Context, sessionID string, appCookieSecure bool) { secure := appCookieSecure httpOnly := appCookieSecure hostname := parsers.GetHost(gc) @@ -48,13 +42,7 @@ func SetMfaSession(gc *gin.Context, sessionID string) { } // DeleteMfaSession deletes the mfa session cookies to expire -func DeleteMfaSession(gc *gin.Context) { - appCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAppCookieSecure) - if err != nil { - log.Debug("Error while getting app cookie secure from env variable: %v", err) - appCookieSecure = true - } - +func DeleteMfaSession(gc *gin.Context, appCookieSecure bool) { secure := appCookieSecure httpOnly := appCookieSecure hostname := parsers.GetHost(gc) diff --git a/internal/crypto/aes.go b/internal/crypto/aes.go new file mode 100644 index 000000000..5c8fec237 --- /dev/null +++ b/internal/crypto/aes.go @@ -0,0 +1,143 @@ +package crypto + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "errors" + "io" +) + +// var bytes = []byte{35, 46, 57, 24, 85, 35, 24, 74, 87, 35, 88, 98, 66, 32, 14, 0o5} + +// const ( +// // Static key for encryption +// encryptionKey = "authorizerdev" +// ) + +// EncryptAES method is to encrypt or hide any classified text +func EncryptAES(key, text string) (string, error) { + keyBytes := []byte(ensureHashKey(key)) + block, err := aes.NewCipher(keyBytes) + if err != nil { + return "", err + } + + // The IV needs to be unique, but not secure. Therefore, it's common to + // include it at the beginning of the ciphertext. + ciphertext := make([]byte, aes.BlockSize+len(text)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return "", err + } + + stream := cipher.NewCFBEncrypter(block, iv) + stream.XORKeyStream(ciphertext[aes.BlockSize:], []byte(text)) + + // Encode the ciphertext to URL-safe base64 without padding + return base64.RawURLEncoding.EncodeToString(ciphertext), nil +} + +// DecryptAES method is to extract back the encrypted text +func DecryptAES(key, encryptedText string) (string, error) { + keyBytes := []byte(ensureHashKey(key)) + ciphertext, err := base64.RawURLEncoding.DecodeString(encryptedText) + if err != nil { + return "", err + } + + block, err := aes.NewCipher(keyBytes) + if err != nil { + return "", err + } + + if len(ciphertext) < aes.BlockSize { + return "", errors.New("ciphertext too short") + } + + iv := ciphertext[:aes.BlockSize] + ciphertext = ciphertext[aes.BlockSize:] + + stream := cipher.NewCFBDecrypter(block, iv) + stream.XORKeyStream(ciphertext, ciphertext) + + return string(ciphertext), nil +} + +// ensureHashKey ensure the key is 32 bytes long +// if short it will append 0's to the key +// if long it will truncate the key +func ensureHashKey(key string) string { + if len(key) < 32 { + return key + string(bytes.Repeat([]byte{0}, 32-len(key))) + } + return key[:32] +} + +// EncryptAESEnv encrypts data using AES algorithm +// kept for the backward compatibility of env data encryption +// TODO: Check if this is still needed +// func EncryptAESEnv(text []byte) ([]byte, error) { +// var res []byte +// key := []byte(encryptionKey) +// c, err := aes.NewCipher(key) +// if err != nil { +// return res, err +// } + +// // gcm or Galois/Counter Mode, is a mode of operation +// // for symmetric key cryptographic block ciphers +// // - https://en.wikipedia.org/wiki/Galois/Counter_Mode +// gcm, err := cipher.NewGCM(c) +// if err != nil { +// return res, err +// } + +// // creates a new byte array the size of the nonce +// // which must be passed to Seal +// nonce := make([]byte, gcm.NonceSize()) +// // populates our nonce with a cryptographically secure +// // random sequence +// if _, err = io.ReadFull(rand.Reader, nonce); err != nil { +// return res, err +// } + +// // here we encrypt our text using the Seal function +// // Seal encrypts and authenticates plaintext, authenticates the +// // additional data and appends the result to dst, returning the updated +// // slice. The nonce must be NonceSize() bytes long and unique for all +// // time, for a given key. +// return gcm.Seal(nonce, nonce, text, nil), nil +// } + +// // DecryptAES decrypts data using AES algorithm +// // Kept for the backward compatibility of env data decryption +// // TODO: Check if this is still needed +// func DecryptAESEnv(ciphertext []byte) ([]byte, error) { +// var res []byte +// key := []byte(encryptionKey) +// c, err := aes.NewCipher(key) +// if err != nil { +// return res, err +// } + +// gcm, err := cipher.NewGCM(c) +// if err != nil { +// return res, err +// } + +// nonceSize := gcm.NonceSize() +// if len(ciphertext) < nonceSize { +// return res, err +// } + +// nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] +// plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) +// if err != nil { +// return res, err +// } + +// return plaintext, nil +// } diff --git a/server/crypto/b64.go b/internal/crypto/b64.go similarity index 100% rename from server/crypto/b64.go rename to internal/crypto/b64.go diff --git a/internal/crypto/common.go b/internal/crypto/common.go new file mode 100644 index 000000000..3f5a3fedc --- /dev/null +++ b/internal/crypto/common.go @@ -0,0 +1,71 @@ +package crypto + +import ( + "crypto/x509" + + "golang.org/x/crypto/bcrypt" + "gopkg.in/square/go-jose.v2" +) + +// GetPubJWK returns JWK for given keys +func GetPubJWK(algo, keyID string, publicKey interface{}) (string, error) { + jwk := &jose.JSONWebKeySet{ + Keys: []jose.JSONWebKey{ + { + Algorithm: algo, + Key: publicKey, + Use: "sig", + KeyID: keyID, + Certificates: []*x509.Certificate{}, + CertificateThumbprintSHA1: []uint8{}, + CertificateThumbprintSHA256: []uint8{}, + }, + }, + } + jwkPublicKey, err := jwk.Keys[0].MarshalJSON() + if err != nil { + return "", err + } + return string(jwkPublicKey), nil +} + +// // EncryptEnvData is used to encrypt the env data +// TODO: remove this function if not needed +// func EncryptEnvData(data map[string]interface{}) (string, error) { +// jsonBytes, err := json.Marshal(data) +// if err != nil { +// return "", err +// } + +// storeData, err := memorystore.Provider.GetEnvStore() +// if err != nil { +// return "", err +// } + +// err = json.Unmarshal(jsonBytes, &storeData) +// if err != nil { +// return "", err +// } + +// configData, err := json.Marshal(storeData) +// if err != nil { +// return "", err +// } + +// encryptedConfig, err := EncryptAESEnv(configData) +// if err != nil { +// return "", err +// } + +// return EncryptB64(string(encryptedConfig)), nil +// } + +// EncryptPassword is used for encrypting password +func EncryptPassword(password string) (string, error) { + pw, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return "", err + } + + return string(pw), nil +} diff --git a/server/crypto/ecdsa.go b/internal/crypto/ecdsa.go similarity index 100% rename from server/crypto/ecdsa.go rename to internal/crypto/ecdsa.go diff --git a/server/crypto/hmac.go b/internal/crypto/hmac.go similarity index 100% rename from server/crypto/hmac.go rename to internal/crypto/hmac.go diff --git a/server/crypto/rsa.go b/internal/crypto/rsa.go similarity index 100% rename from server/crypto/rsa.go rename to internal/crypto/rsa.go diff --git a/internal/email/email.go b/internal/email/email.go new file mode 100644 index 000000000..30e6526a2 --- /dev/null +++ b/internal/email/email.go @@ -0,0 +1,146 @@ +package email + +import ( + "bytes" + "context" + "crypto/tls" + "strings" + "text/template" + + "github.com/rs/zerolog" + gomail "gopkg.in/mail.v2" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/email/templates" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage" +) + +// Provider interface for email provider +type Provider interface { + SendEmail(to []string, event string, data map[string]interface{}) error +} + +// Dependencies struct for email provider +type Dependencies struct { + Log *zerolog.Logger + StorageProvider storage.Provider +} + +// provider struct for email provider +type provider struct { + config *config.Config + deps *Dependencies + + mailer *gomail.Dialer +} + +// New returns a new email provider +func New( + config *config.Config, + deps *Dependencies, +) (Provider, error) { + mailer := gomail.NewDialer(config.SMTPHost, config.SMTPPort, config.SMTPUsername, config.SMTPPassword) + if strings.TrimSpace(config.SMTPLocalName) != "" { + mailer.LocalName = config.SMTPLocalName + } + if config.SkipTLSVerification { + mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true} + } + return &provider{ + config: config, + deps: deps, + mailer: mailer, + }, nil +} + +// SendEmail function to send mail +func (p *provider) SendEmail(to []string, event string, data map[string]interface{}) error { + log := p.deps.Log.With().Str("func", "send_email").Str("event", event).Logger() + // Don't trigger email sending in case of test + if p.config.Env == constants.TestEnv { + return nil + } + + tmp, err := p.getEmailTemplate(event, data) + if err != nil { + log.Debug().Err(err).Msg("Failed to get email template") + return err + } + + m := gomail.NewMessage() + m.SetAddressHeader("From", p.config.SMTPSenderEmail, p.config.SMTPSenderName) + m.SetHeader("To", to...) + m.SetHeader("Subject", tmp.Subject) + m.SetBody("text/html", tmp.Template) + if err := p.mailer.DialAndSend(m); err != nil { + log.Debug().Err(err).Msg("Failed to send email") + return err + } + return nil +} + +func getDefaultTemplate(event string) *model.EmailTemplate { + switch event { + case constants.VerificationTypeBasicAuthSignup, constants.VerificationTypeMagicLinkLogin, constants.VerificationTypeUpdateEmail: + return &model.EmailTemplate{ + Subject: templates.EmailVerificationSubject, + Template: templates.EmailVerificationTemplate, + } + case constants.VerificationTypeForgotPassword: + return &model.EmailTemplate{ + Subject: templates.ForgotPasswordSubject, + Template: templates.ForgotPasswordTemplate, + } + case constants.VerificationTypeInviteMember: + return &model.EmailTemplate{ + Subject: templates.InviteUserEmailSubject, + Template: templates.InviteUserEmailTemplate, + } + case constants.VerificationTypeOTP: + return &model.EmailTemplate{ + Subject: templates.OtpEmailSubject, + Template: templates.OtpEmailTemplate, + } + default: + return nil + } +} + +func (p *provider) getEmailTemplate(event string, data map[string]interface{}) (*model.EmailTemplate, error) { + ctx := context.Background() + var tmp *model.EmailTemplate + et, err := p.deps.StorageProvider.GetEmailTemplateByEventName(ctx, event) + if err != nil || et == nil { + tmp = getDefaultTemplate(event) + } else { + tmp = et.AsAPIEmailTemplate() + } + + templ, err := template.New(event + "_template.tmpl").Parse(tmp.Template) + if err != nil { + return nil, err + } + buf := &bytes.Buffer{} + err = templ.Execute(buf, data) + if err != nil { + return nil, err + } + templateString := buf.String() + + subject, err := template.New(event + "_subject.tmpl").Parse(tmp.Subject) + if err != nil { + return nil, err + } + buf = &bytes.Buffer{} + err = subject.Execute(buf, data) + if err != nil { + return nil, err + } + subjectString := buf.String() + return &model.EmailTemplate{ + Template: templateString, + Subject: subjectString, + }, nil +} diff --git a/server/email/email_verification.go b/internal/email/templates/email_verification.go similarity index 95% rename from server/email/email_verification.go rename to internal/email/templates/email_verification.go index 7a3de2557..9d537c789 100644 --- a/server/email/email_verification.go +++ b/internal/email/templates/email_verification.go @@ -1,8 +1,12 @@ -package email +package templates const ( - emailVerificationSubject = "Please verify your email" - emailVerificationTemplate = ` + // EmailVerificationSubject is the default subject of the email + // sent for email verification + EmailVerificationSubject = "Please verify your email" + // EmailVerificationTemplate is the default template of the email + // sent for email verification + EmailVerificationTemplate = ` diff --git a/server/email/forgot_password_email.go b/internal/email/templates/forgot_password.go similarity index 96% rename from server/email/forgot_password_email.go rename to internal/email/templates/forgot_password.go index 678f83c80..2fc80ffb2 100644 --- a/server/email/forgot_password_email.go +++ b/internal/email/templates/forgot_password.go @@ -1,8 +1,10 @@ -package email +package templates const ( - forgotPasswordSubject = "Reset Password" - forgotPasswordTemplate = ` + // ForgotPasswordSubject is the default subject for forgot password email + ForgotPasswordSubject = "Reset Password" + // ForgotPasswordTemplate is the default template for forgot password email + ForgotPasswordTemplate = ` diff --git a/server/email/invite_email.go b/internal/email/templates/invite_user.go similarity index 95% rename from server/email/invite_email.go rename to internal/email/templates/invite_user.go index bec33a60c..351a8a3d4 100644 --- a/server/email/invite_email.go +++ b/internal/email/templates/invite_user.go @@ -1,8 +1,10 @@ -package email +package templates const ( - inviteEmailSubject = "Please accept the invitation" - inviteEmailTemplate = ` + // InviteUserEmailSubject is the default subject of the email sent to invite a user + InviteUserEmailSubject = "Please accept the invitation" + // InviteUserEmailTemplate is the default template of the email sent to invite a user + InviteUserEmailTemplate = ` diff --git a/server/email/otp.go b/internal/email/templates/otp.go similarity index 96% rename from server/email/otp.go rename to internal/email/templates/otp.go index d3bf7c0d5..0c6874c8d 100644 --- a/server/email/otp.go +++ b/internal/email/templates/otp.go @@ -1,8 +1,10 @@ -package email +package templates const ( - otpEmailSubject = "OTP for your multi factor authentication" - otpEmailTemplate = ` + // OtPEmailSubject is the default subject of the OTP email + OtpEmailSubject = "OTP for your multi factor authentication" + // OtpEmailTemplate is the default template of the OTP email + OtpEmailTemplate = ` diff --git a/internal/env/env.go b/internal/env/env.go new file mode 100644 index 000000000..b5c8b316f --- /dev/null +++ b/internal/env/env.go @@ -0,0 +1,887 @@ +package env + +// InitEnv to initialize EnvData and through error if required env are not present +// func InitAllEnv() error { +// envData, err := GetEnvData() +// if err != nil || envData == nil { +// log.Info("No env data found in db, using local clone of env data") +// // get clone of current store +// envData, err = memorystore.Provider.GetEnvStore() +// if err != nil { +// log.Debug("Error while getting env data from memorystore: ", err) +// return err +// } +// } + +// // unique client id for each instance +// cid, ok := envData[constants.EnvKeyClientID] +// clientID := "" +// if !ok || cid == "" { +// clientID = uuid.New().String() +// envData[constants.EnvKeyClientID] = clientID +// } else { +// clientID = cid.(string) +// } + +// // unique client secret for each instance +// if val, ok := envData[constants.EnvKeyClientSecret]; !ok || val != "" { +// envData[constants.EnvKeyClientSecret] = uuid.New().String() +// } + +// // os string envs +// osEnv := os.Getenv(constants.EnvKeyEnv) +// osAppURL := os.Getenv(constants.EnvKeyAppURL) +// osAuthorizerURL := os.Getenv(constants.EnvKeyAuthorizerURL) +// osPort := os.Getenv(constants.EnvKeyPort) +// osAccessTokenExpiryTime := os.Getenv(constants.EnvKeyAccessTokenExpiryTime) +// osAdminSecret := os.Getenv(constants.EnvKeyAdminSecret) +// osSmtpHost := os.Getenv(constants.EnvKeySmtpHost) +// osSmtpPort := os.Getenv(constants.EnvKeySmtpPort) +// osSmtpUsername := os.Getenv(constants.EnvKeySmtpUsername) +// osSmtpPassword := os.Getenv(constants.EnvKeySmtpPassword) +// osSmtpLocalName := os.Getenv(constants.EnvKeySmtpLocalName) +// osSenderEmail := os.Getenv(constants.EnvKeySenderEmail) +// osSenderName := os.Getenv(constants.EnvKeySenderName) +// osJwtType := os.Getenv(constants.EnvKeyJwtType) +// osJwtSecret := os.Getenv(constants.EnvKeyJwtSecret) +// osJwtPrivateKey := os.Getenv(constants.EnvKeyJwtPrivateKey) +// osJwtPublicKey := os.Getenv(constants.EnvKeyJwtPublicKey) +// osJwtRoleClaim := os.Getenv(constants.EnvKeyJwtRoleClaim) +// osCustomAccessTokenScript := os.Getenv(constants.EnvKeyCustomAccessTokenScript) +// osGoogleClientID := os.Getenv(constants.EnvKeyGoogleClientID) +// osGoogleClientSecret := os.Getenv(constants.EnvKeyGoogleClientSecret) +// osGithubClientID := os.Getenv(constants.EnvKeyGithubClientID) +// osGithubClientSecret := os.Getenv(constants.EnvKeyGithubClientSecret) +// osFacebookClientID := os.Getenv(constants.EnvKeyFacebookClientID) +// osFacebookClientSecret := os.Getenv(constants.EnvKeyFacebookClientSecret) +// osLinkedInClientID := os.Getenv(constants.EnvKeyLinkedInClientID) +// osLinkedInClientSecret := os.Getenv(constants.EnvKeyLinkedInClientSecret) +// osAppleClientID := os.Getenv(constants.EnvKeyAppleClientID) +// osAppleClientSecret := os.Getenv(constants.EnvKeyAppleClientSecret) +// osTwitterClientID := os.Getenv(constants.EnvKeyTwitterClientID) +// osTwitterClientSecret := os.Getenv(constants.EnvKeyTwitterClientSecret) +// osMicrosoftClientID := os.Getenv(constants.EnvKeyMicrosoftClientID) +// osMicrosoftClientSecret := os.Getenv(constants.EnvKeyMicrosoftClientSecret) +// osMicrosoftActiveDirectoryTenantID := os.Getenv(constants.EnvKeyMicrosoftActiveDirectoryTenantID) +// osTwitchClientID := os.Getenv(constants.EnvKeyTwitchClientID) +// osTwitchClientSecret := os.Getenv(constants.EnvKeyTwitchClientSecret) +// osRobloxClientID := os.Getenv(constants.EnvKeyTwitchClientID) +// osRobloxClientSecret := os.Getenv(constants.EnvKeyTwitchClientSecret) +// osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL) +// osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName) +// osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo) +// osAwsRegion := os.Getenv(constants.EnvAwsRegion) +// osAwsAccessKey := os.Getenv(constants.EnvAwsAccessKeyID) +// 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 +// osAppCookieSecure := os.Getenv(constants.EnvKeyAppCookieSecure) +// osAdminCookieSecure := os.Getenv(constants.EnvKeyAdminCookieSecure) +// osDisableBasicAuthentication := os.Getenv(constants.EnvKeyDisableBasicAuthentication) +// osDisableMobileBasicAuthentication := os.Getenv(constants.AuthRecipeMethodMobileBasicAuth) +// osDisableEmailVerification := os.Getenv(constants.EnvKeyDisableEmailVerification) +// osDisableMagicLinkLogin := os.Getenv(constants.EnvKeyDisableMagicLinkLogin) +// osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage) +// osDisableSignUp := os.Getenv(constants.EnvKeyDisableSignUp) +// osDisableRedisForEnv := os.Getenv(constants.EnvKeyDisableRedisForEnv) +// osDisableStrongPassword := os.Getenv(constants.EnvKeyDisableStrongPassword) +// osEnforceMultiFactorAuthentication := os.Getenv(constants.EnvKeyEnforceMultiFactorAuthentication) +// osDisableMultiFactorAuthentication := os.Getenv(constants.EnvKeyDisableMultiFactorAuthentication) +// osDisableTOTPLogin := os.Getenv(constants.EnvKeyDisableTOTPLogin) +// osDisableMailOTPLogin := os.Getenv(constants.EnvKeyDisableMailOTPLogin) +// // phone verification var +// osDisablePhoneVerification := os.Getenv(constants.EnvKeyDisablePhoneVerification) +// osDisablePlayground := os.Getenv(constants.EnvKeyDisablePlayGround) + +// // twilio vars +// osTwilioApiKey := os.Getenv(constants.EnvKeyTwilioAPIKey) +// osTwilioApiSecret := os.Getenv(constants.EnvKeyTwilioAPISecret) +// osTwilioAccountSid := os.Getenv(constants.EnvKeyTwilioAccountSID) +// osTwilioSender := os.Getenv(constants.EnvKeyTwilioSender) + +// // os slice vars +// osAllowedOrigins := os.Getenv(constants.EnvKeyAllowedOrigins) +// osRoles := os.Getenv(constants.EnvKeyRoles) +// osDefaultRoles := os.Getenv(constants.EnvKeyDefaultRoles) +// osProtectedRoles := os.Getenv(constants.EnvKeyProtectedRoles) + +// ienv, ok := envData[constants.EnvKeyEnv] +// if !ok || ienv == "" { +// envData[constants.EnvKeyEnv] = osEnv +// if envData[constants.EnvKeyEnv] == "" { +// envData[constants.EnvKeyEnv] = "production" +// } + +// if envData[constants.EnvKeyEnv] == "production" { +// envData[constants.EnvKeyIsProd] = true +// } else { +// envData[constants.EnvKeyIsProd] = false +// } +// } +// if osEnv != "" && osEnv != envData[constants.EnvKeyEnv] { +// envData[constants.EnvKeyEnv] = osEnv +// if envData[constants.EnvKeyEnv] == "production" { +// envData[constants.EnvKeyIsProd] = true +// } else { +// envData[constants.EnvKeyIsProd] = false +// } +// } + +// if val, ok := envData[constants.EnvAwsRegion]; !ok || val == "" { +// envData[constants.EnvAwsRegion] = osAwsRegion +// } + +// if osAwsRegion != "" && envData[constants.EnvAwsRegion] != osAwsRegion { +// envData[constants.EnvAwsRegion] = osAwsRegion +// } + +// if val, ok := envData[constants.EnvAwsAccessKeyID]; !ok || val == "" { +// envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey +// } +// if osAwsAccessKey != "" && envData[constants.EnvAwsAccessKeyID] != osAwsAccessKey { +// envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey +// } + +// if val, ok := envData[constants.EnvAwsSecretAccessKey]; !ok || val == "" { +// envData[constants.EnvAwsSecretAccessKey] = osAwsSecretKey +// } +// if 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 == "" { +// envData[constants.EnvKeyAppURL] = osAppURL +// } +// if osAppURL != "" && envData[constants.EnvKeyAppURL] != osAppURL { +// envData[constants.EnvKeyAppURL] = osAppURL +// } + +// if val, ok := envData[constants.EnvKeyAuthorizerURL]; !ok || val == "" { +// envData[constants.EnvKeyAuthorizerURL] = osAuthorizerURL +// } +// if osAuthorizerURL != "" && envData[constants.EnvKeyAuthorizerURL] != osAuthorizerURL { +// envData[constants.EnvKeyAuthorizerURL] = osAuthorizerURL +// } + +// if val, ok := envData[constants.EnvKeyPort]; !ok || val == "" { +// envData[constants.EnvKeyPort] = osPort +// if envData[constants.EnvKeyPort] == "" { +// envData[constants.EnvKeyPort] = "8080" +// } +// } +// if osPort != "" && envData[constants.EnvKeyPort] != osPort { +// envData[constants.EnvKeyPort] = osPort +// } + +// if val, ok := envData[constants.EnvKeyAccessTokenExpiryTime]; !ok || val == "" { +// envData[constants.EnvKeyAccessTokenExpiryTime] = osAccessTokenExpiryTime +// if envData[constants.EnvKeyAccessTokenExpiryTime] == "" { +// envData[constants.EnvKeyAccessTokenExpiryTime] = "30m" +// } +// } +// if osAccessTokenExpiryTime != "" && envData[constants.EnvKeyAccessTokenExpiryTime] != osAccessTokenExpiryTime { +// envData[constants.EnvKeyAccessTokenExpiryTime] = osAccessTokenExpiryTime +// } + +// if val, ok := envData[constants.EnvKeyAdminSecret]; !ok || val == "" { +// envData[constants.EnvKeyAdminSecret] = osAdminSecret +// } +// if osAdminSecret != "" && envData[constants.EnvKeyAdminSecret] != osAdminSecret { +// envData[constants.EnvKeyAdminSecret] = osAdminSecret +// } + +// if val, ok := envData[constants.EnvKeySmtpHost]; !ok || val == "" { +// envData[constants.EnvKeySmtpHost] = osSmtpHost +// } +// if osSmtpHost != "" && envData[constants.EnvKeySmtpHost] != osSmtpHost { +// envData[constants.EnvKeySmtpHost] = osSmtpHost +// } + +// if val, ok := envData[constants.EnvKeySmtpPort]; !ok || val == "" { +// envData[constants.EnvKeySmtpPort] = osSmtpPort +// } +// if osSmtpPort != "" && envData[constants.EnvKeySmtpPort] != osSmtpPort { +// envData[constants.EnvKeySmtpPort] = osSmtpPort +// } + +// if val, ok := envData[constants.EnvKeySmtpUsername]; !ok || val == "" { +// envData[constants.EnvKeySmtpUsername] = osSmtpUsername +// } +// if osSmtpUsername != "" && envData[constants.EnvKeySmtpUsername] != osSmtpUsername { +// envData[constants.EnvKeySmtpUsername] = osSmtpUsername +// } + +// if val, ok := envData[constants.EnvKeySmtpLocalName]; !ok || val == "" { +// envData[constants.EnvKeySmtpLocalName] = osSmtpLocalName +// } +// if osSmtpLocalName != "" && envData[constants.EnvKeySmtpLocalName] != osSmtpLocalName { +// envData[constants.EnvKeySmtpLocalName] = osSmtpLocalName +// } + +// if val, ok := envData[constants.EnvKeySmtpPassword]; !ok || val == "" { +// envData[constants.EnvKeySmtpPassword] = osSmtpPassword +// } +// if osSmtpPassword != "" && envData[constants.EnvKeySmtpPassword] != osSmtpPassword { +// envData[constants.EnvKeySmtpPassword] = osSmtpPassword +// } + +// if val, ok := envData[constants.EnvKeySenderEmail]; !ok || val == "" { +// envData[constants.EnvKeySenderEmail] = osSenderEmail +// } +// if osSenderEmail != "" && envData[constants.EnvKeySenderEmail] != osSenderEmail { +// envData[constants.EnvKeySenderEmail] = osSenderEmail +// } + +// if val, ok := envData[constants.EnvKeySenderName]; !ok || val == "" { +// envData[constants.EnvKeySenderName] = osSenderName +// } +// if osSenderName != "" && envData[constants.EnvKeySenderName] != osSenderName { +// envData[constants.EnvKeySenderName] = osSenderName +// } + +// algoVal, ok := envData[constants.EnvKeyJwtType] +// algo := "" +// if !ok || algoVal == "" { +// envData[constants.EnvKeyJwtType] = osJwtType +// if envData[constants.EnvKeyJwtType] == "" { +// envData[constants.EnvKeyJwtType] = "RS256" +// algo = envData[constants.EnvKeyJwtType].(string) +// } +// } else { +// algo = algoVal.(string) +// if !crypto.IsHMACA(algo) && !crypto.IsRSA(algo) && !crypto.IsECDSA(algo) { +// log.Debug("Invalid JWT Algorithm") +// return errors.New("invalid JWT_TYPE") +// } +// } +// if osJwtType != "" && osJwtType != algo { +// if !crypto.IsHMACA(osJwtType) && !crypto.IsRSA(osJwtType) && !crypto.IsECDSA(osJwtType) { +// log.Debug("Invalid JWT Algorithm") +// return errors.New("invalid JWT_TYPE") +// } +// algo = osJwtType +// envData[constants.EnvKeyJwtType] = osJwtType +// } + +// if crypto.IsHMACA(algo) { +// if val, ok := envData[constants.EnvKeyJwtSecret]; !ok || val == "" { +// envData[constants.EnvKeyJwtSecret] = osJwtSecret +// if envData[constants.EnvKeyJwtSecret] == "" { +// envData[constants.EnvKeyJwtSecret], _, err = crypto.NewHMACKey(algo, clientID) +// if err != nil { +// return err +// } +// } +// } +// if osJwtSecret != "" && envData[constants.EnvKeyJwtSecret] != osJwtSecret { +// envData[constants.EnvKeyJwtSecret] = osJwtSecret +// } +// } + +// if crypto.IsRSA(algo) || crypto.IsECDSA(algo) { +// privateKey, publicKey := "", "" + +// if val, ok := envData[constants.EnvKeyJwtPrivateKey]; !ok || val == "" { +// privateKey = osJwtPrivateKey +// } +// if osJwtPrivateKey != "" && privateKey != osJwtPrivateKey { +// privateKey = osJwtPrivateKey +// } + +// if val, ok := envData[constants.EnvKeyJwtPublicKey]; !ok || val == "" { +// publicKey = osJwtPublicKey +// } +// if osJwtPublicKey != "" && publicKey != osJwtPublicKey { +// publicKey = osJwtPublicKey +// } + +// // if algo is RSA / ECDSA, then we need to have both private and public key +// // if either of them is not present generate new keys +// if privateKey == "" || publicKey == "" { +// if crypto.IsRSA(algo) { +// _, privateKey, publicKey, _, err = crypto.NewRSAKey(algo, clientID) +// if err != nil { +// return err +// } +// } else if crypto.IsECDSA(algo) { +// _, privateKey, publicKey, _, err = crypto.NewECDSAKey(algo, clientID) +// if err != nil { +// return err +// } +// } +// } else { +// // parse keys to make sure they are valid +// if crypto.IsRSA(algo) { +// _, err = crypto.ParseRsaPrivateKeyFromPemStr(privateKey) +// if err != nil { +// return err +// } + +// _, err := crypto.ParseRsaPublicKeyFromPemStr(publicKey) +// if err != nil { +// return err +// } + +// } else if crypto.IsECDSA(algo) { +// _, err = crypto.ParseEcdsaPrivateKeyFromPemStr(privateKey) +// if err != nil { +// return err +// } + +// _, err := crypto.ParseEcdsaPublicKeyFromPemStr(publicKey) +// if err != nil { +// return err +// } +// } +// } + +// envData[constants.EnvKeyJwtPrivateKey] = privateKey +// envData[constants.EnvKeyJwtPublicKey] = publicKey + +// } + +// if val, ok := envData[constants.EnvKeyJwtRoleClaim]; !ok || val == "" { +// envData[constants.EnvKeyJwtRoleClaim] = osJwtRoleClaim + +// if envData[constants.EnvKeyJwtRoleClaim] == "" { +// envData[constants.EnvKeyJwtRoleClaim] = "roles" +// } +// } +// if osJwtRoleClaim != "" && envData[constants.EnvKeyJwtRoleClaim] != osJwtRoleClaim { +// envData[constants.EnvKeyJwtRoleClaim] = osJwtRoleClaim +// } + +// if val, ok := envData[constants.EnvKeyCustomAccessTokenScript]; !ok || val == "" { +// envData[constants.EnvKeyCustomAccessTokenScript] = osCustomAccessTokenScript +// } +// if osCustomAccessTokenScript != "" && envData[constants.EnvKeyCustomAccessTokenScript] != osCustomAccessTokenScript { +// envData[constants.EnvKeyCustomAccessTokenScript] = osCustomAccessTokenScript +// } + +// if val, ok := envData[constants.EnvKeyGoogleClientID]; !ok || val == "" { +// envData[constants.EnvKeyGoogleClientID] = osGoogleClientID +// } +// if osGoogleClientID != "" && envData[constants.EnvKeyGoogleClientID] != osGoogleClientID { +// envData[constants.EnvKeyGoogleClientID] = osGoogleClientID +// } + +// if val, ok := envData[constants.EnvKeyGoogleClientSecret]; !ok || val == "" { +// envData[constants.EnvKeyGoogleClientSecret] = osGoogleClientSecret +// } +// if osGoogleClientSecret != "" && envData[constants.EnvKeyGoogleClientSecret] != osGoogleClientSecret { +// envData[constants.EnvKeyGoogleClientSecret] = osGoogleClientSecret +// } + +// if val, ok := envData[constants.EnvKeyGithubClientID]; !ok || val == "" { +// envData[constants.EnvKeyGithubClientID] = osGithubClientID +// } +// if osGithubClientID != "" && envData[constants.EnvKeyGithubClientID] != osGithubClientID { +// envData[constants.EnvKeyGithubClientID] = osGithubClientID +// } + +// if val, ok := envData[constants.EnvKeyGithubClientSecret]; !ok || val == "" { +// envData[constants.EnvKeyGithubClientSecret] = osGithubClientSecret +// } +// if osGithubClientSecret != "" && envData[constants.EnvKeyGithubClientSecret] != osGithubClientSecret { +// envData[constants.EnvKeyGithubClientSecret] = osGithubClientSecret +// } + +// if val, ok := envData[constants.EnvKeyFacebookClientID]; !ok || val == "" { +// envData[constants.EnvKeyFacebookClientID] = osFacebookClientID +// } +// if osFacebookClientID != "" && envData[constants.EnvKeyFacebookClientID] != osFacebookClientID { +// envData[constants.EnvKeyFacebookClientID] = osFacebookClientID +// } + +// if val, ok := envData[constants.EnvKeyFacebookClientSecret]; !ok || val == "" { +// envData[constants.EnvKeyFacebookClientSecret] = osFacebookClientSecret +// } +// if osFacebookClientSecret != "" && envData[constants.EnvKeyFacebookClientSecret] != osFacebookClientSecret { +// envData[constants.EnvKeyFacebookClientSecret] = osFacebookClientSecret +// } + +// if val, ok := envData[constants.EnvKeyLinkedInClientID]; !ok || val == "" { +// envData[constants.EnvKeyLinkedInClientID] = osLinkedInClientID +// } +// if osLinkedInClientID != "" && envData[constants.EnvKeyLinkedInClientID] != osLinkedInClientID { +// envData[constants.EnvKeyLinkedInClientID] = osLinkedInClientID +// } + +// if val, ok := envData[constants.EnvKeyLinkedInClientSecret]; !ok || val == "" { +// envData[constants.EnvKeyLinkedInClientSecret] = osLinkedInClientSecret +// } +// if osLinkedInClientSecret != "" && envData[constants.EnvKeyLinkedInClientSecret] != osLinkedInClientSecret { +// envData[constants.EnvKeyLinkedInClientSecret] = osLinkedInClientSecret +// } + +// if val, ok := envData[constants.EnvKeyAppleClientID]; !ok || val == "" { +// envData[constants.EnvKeyAppleClientID] = osAppleClientID +// } +// if osAppleClientID != "" && envData[constants.EnvKeyAppleClientID] != osAppleClientID { +// envData[constants.EnvKeyAppleClientID] = osAppleClientID +// } + +// if val, ok := envData[constants.EnvKeyAppleClientSecret]; !ok || val == "" { +// envData[constants.EnvKeyAppleClientSecret] = osAppleClientSecret +// } +// if osAppleClientSecret != "" && envData[constants.EnvKeyAppleClientSecret] != osAppleClientSecret { +// envData[constants.EnvKeyAppleClientSecret] = osAppleClientSecret +// } + +// if val, ok := envData[constants.EnvKeyTwitterClientID]; !ok || val == "" { +// envData[constants.EnvKeyTwitterClientID] = osTwitterClientID +// } +// if osTwitterClientID != "" && envData[constants.EnvKeyTwitterClientID] != osTwitterClientID { +// envData[constants.EnvKeyTwitterClientID] = osTwitterClientID +// } + +// if val, ok := envData[constants.EnvKeyTwitterClientSecret]; !ok || val == "" { +// envData[constants.EnvKeyTwitterClientSecret] = osTwitterClientSecret +// } +// if osTwitterClientSecret != "" && 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.EnvKeyTwitchClientID]; !ok || val == "" { +// envData[constants.EnvKeyTwitchClientID] = osTwitchClientID +// } +// if osTwitchClientID != "" && envData[constants.EnvKeyTwitchClientID] != osTwitchClientID { +// envData[constants.EnvKeyTwitchClientID] = osTwitchClientID +// } + +// if val, ok := envData[constants.EnvKeyTwitchClientSecret]; !ok || val == "" { +// envData[constants.EnvKeyTwitchClientSecret] = osTwitchClientSecret +// } +// if osTwitchClientSecret != "" && envData[constants.EnvKeyTwitchClientSecret] != osTwitchClientSecret { +// envData[constants.EnvKeyTwitchClientSecret] = osTwitchClientSecret +// } + +// if val, ok := envData[constants.EnvKeyRobloxClientID]; !ok || val == "" { +// envData[constants.EnvKeyRobloxClientID] = osRobloxClientID +// } +// if osRobloxClientID != "" && envData[constants.EnvKeyRobloxClientID] != osRobloxClientID { +// envData[constants.EnvKeyRobloxClientID] = osRobloxClientID +// } + +// if val, ok := envData[constants.EnvKeyRobloxClientSecret]; !ok || val == "" { +// envData[constants.EnvKeyRobloxClientSecret] = osRobloxClientSecret +// } +// if osRobloxClientSecret != "" && envData[constants.EnvKeyRobloxClientSecret] != osRobloxClientSecret { +// envData[constants.EnvKeyRobloxClientSecret] = osRobloxClientSecret +// } + +// if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" { +// envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/") +// } +// if osResetPasswordURL != "" && envData[constants.EnvKeyResetPasswordURL] != osResetPasswordURL { +// envData[constants.EnvKeyResetPasswordURL] = osResetPasswordURL +// } + +// if val, ok := envData[constants.EnvKeyOrganizationName]; !ok || val == "" { +// envData[constants.EnvKeyOrganizationName] = osOrganizationName +// } +// if osOrganizationName != "" && envData[constants.EnvKeyOrganizationName] != osOrganizationName { +// envData[constants.EnvKeyOrganizationName] = osOrganizationName +// } + +// if val, ok := envData[constants.EnvKeyOrganizationLogo]; !ok || val == "" { +// envData[constants.EnvKeyOrganizationLogo] = osOrganizationLogo +// } +// if osOrganizationLogo != "" && envData[constants.EnvKeyOrganizationLogo] != osOrganizationLogo { +// envData[constants.EnvKeyOrganizationLogo] = osOrganizationLogo +// } + +// if _, ok := envData[constants.EnvKeyAppCookieSecure]; !ok { +// if osAppCookieSecure == "" { +// envData[constants.EnvKeyAppCookieSecure] = true +// } else { +// envData[constants.EnvKeyAppCookieSecure] = osAppCookieSecure == "true" +// } +// } +// if osAppCookieSecure != "" { +// boolValue, err := strconv.ParseBool(osAppCookieSecure) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyAppCookieSecure].(bool) { +// envData[constants.EnvKeyAppCookieSecure] = boolValue +// } +// } + +// if _, ok := envData[constants.EnvKeyAdminCookieSecure]; !ok { +// if osAdminCookieSecure == "" { +// envData[constants.EnvKeyAdminCookieSecure] = true +// } else { +// envData[constants.EnvKeyAdminCookieSecure] = osAdminCookieSecure == "true" +// } +// } +// if osAdminCookieSecure != "" { +// boolValue, err := strconv.ParseBool(osAdminCookieSecure) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyAdminCookieSecure].(bool) { +// envData[constants.EnvKeyAdminCookieSecure] = boolValue +// } +// } + +// if _, ok := envData[constants.EnvKeyDisableBasicAuthentication]; !ok { +// envData[constants.EnvKeyDisableBasicAuthentication] = osDisableBasicAuthentication == "true" +// } +// if osDisableBasicAuthentication != "" { +// boolValue, err := strconv.ParseBool(osDisableBasicAuthentication) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisableBasicAuthentication].(bool) { +// envData[constants.EnvKeyDisableBasicAuthentication] = boolValue +// } +// } + +// if _, 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 { +// envData[constants.EnvKeyDisableEmailVerification] = osDisableEmailVerification == "true" +// } +// if osDisableEmailVerification != "" { +// boolValue, err := strconv.ParseBool(osDisableEmailVerification) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisableEmailVerification].(bool) { +// envData[constants.EnvKeyDisableEmailVerification] = boolValue +// } +// } + +// if _, ok := envData[constants.EnvKeyDisableMagicLinkLogin]; !ok { +// envData[constants.EnvKeyDisableMagicLinkLogin] = osDisableMagicLinkLogin == "true" +// } +// if osDisableMagicLinkLogin != "" { +// boolValue, err := strconv.ParseBool(osDisableMagicLinkLogin) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisableMagicLinkLogin] { +// envData[constants.EnvKeyDisableMagicLinkLogin] = boolValue +// } +// } + +// if _, ok := envData[constants.EnvKeyDisableLoginPage]; !ok { +// envData[constants.EnvKeyDisableLoginPage] = osDisableLoginPage == "true" +// } +// if osDisableLoginPage != "" { +// boolValue, err := strconv.ParseBool(osDisableLoginPage) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisableLoginPage].(bool) { +// envData[constants.EnvKeyDisableLoginPage] = boolValue +// } +// } + +// if _, ok := envData[constants.EnvKeyDisableSignUp]; !ok { +// envData[constants.EnvKeyDisableSignUp] = osDisableSignUp == "true" +// } +// if osDisableSignUp != "" { +// boolValue, err := strconv.ParseBool(osDisableSignUp) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisableSignUp].(bool) { +// envData[constants.EnvKeyDisableSignUp] = boolValue +// } +// } + +// if _, ok := envData[constants.EnvKeyDisableRedisForEnv]; !ok { +// envData[constants.EnvKeyDisableRedisForEnv] = osDisableRedisForEnv == "true" +// } +// if osDisableRedisForEnv != "" { +// boolValue, err := strconv.ParseBool(osDisableRedisForEnv) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisableRedisForEnv].(bool) { +// envData[constants.EnvKeyDisableRedisForEnv] = boolValue +// } +// } + +// if _, ok := envData[constants.EnvKeyDisableStrongPassword]; !ok { +// envData[constants.EnvKeyDisableStrongPassword] = osDisableStrongPassword == "true" +// } +// if osDisableStrongPassword != "" { +// boolValue, err := strconv.ParseBool(osDisableStrongPassword) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisableStrongPassword].(bool) { +// envData[constants.EnvKeyDisableStrongPassword] = boolValue +// } +// } + +// if _, ok := envData[constants.EnvKeyEnforceMultiFactorAuthentication]; !ok { +// envData[constants.EnvKeyEnforceMultiFactorAuthentication] = osEnforceMultiFactorAuthentication == "true" +// } +// if osEnforceMultiFactorAuthentication != "" { +// boolValue, err := strconv.ParseBool(osEnforceMultiFactorAuthentication) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) { +// envData[constants.EnvKeyEnforceMultiFactorAuthentication] = boolValue +// } +// } + +// if _, ok := envData[constants.EnvKeyDisableMultiFactorAuthentication]; !ok { +// envData[constants.EnvKeyDisableMultiFactorAuthentication] = osDisableMultiFactorAuthentication == "true" +// } +// if osDisableMultiFactorAuthentication != "" { +// boolValue, err := strconv.ParseBool(osDisableMultiFactorAuthentication) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) { +// envData[constants.EnvKeyDisableMultiFactorAuthentication] = boolValue +// } +// } + +// // no need to add nil check as its already done above +// if envData[constants.EnvKeySmtpHost] == "" || envData[constants.EnvKeySmtpUsername] == "" || envData[constants.EnvKeySmtpPassword] == "" || envData[constants.EnvKeySenderEmail] == "" && envData[constants.EnvKeySmtpPort] == "" { +// envData[constants.EnvKeyDisableEmailVerification] = true +// envData[constants.EnvKeyDisableMagicLinkLogin] = true +// envData[constants.EnvKeyIsEmailServiceEnabled] = false +// envData[constants.EnvKeyDisableMailOTPLogin] = true +// } + +// if envData[constants.EnvKeySmtpHost] != "" && envData[constants.EnvKeySmtpUsername] != "" && envData[constants.EnvKeySmtpPassword] != "" && envData[constants.EnvKeySenderEmail] != "" && envData[constants.EnvKeySmtpPort] != "" { +// envData[constants.EnvKeyIsEmailServiceEnabled] = true +// } + +// if envData[constants.EnvKeyDisableEmailVerification].(bool) { +// envData[constants.EnvKeyDisableMagicLinkLogin] = true +// } + +// if val, ok := envData[constants.EnvKeyAllowedOrigins]; !ok || val == "" { +// envData[constants.EnvKeyAllowedOrigins] = osAllowedOrigins +// if envData[constants.EnvKeyAllowedOrigins] == "" { +// envData[constants.EnvKeyAllowedOrigins] = "*" +// } +// } +// if osAllowedOrigins != "" && envData[constants.EnvKeyAllowedOrigins] != osAllowedOrigins { +// envData[constants.EnvKeyAllowedOrigins] = osAllowedOrigins +// } + +// if val, ok := envData[constants.EnvKeyRoles]; !ok || val == "" { +// envData[constants.EnvKeyRoles] = osRoles +// if envData[constants.EnvKeyRoles] == "" { +// envData[constants.EnvKeyRoles] = "user" +// } +// } +// if osRoles != "" && envData[constants.EnvKeyRoles] != osRoles { +// envData[constants.EnvKeyRoles] = osRoles +// } +// roles := strings.Split(envData[constants.EnvKeyRoles].(string), ",") + +// if val, ok := envData[constants.EnvKeyDefaultRoles]; !ok || val == "" { +// envData[constants.EnvKeyDefaultRoles] = osDefaultRoles +// if envData[constants.EnvKeyDefaultRoles] == "" { +// envData[constants.EnvKeyDefaultRoles] = "user" +// } +// } +// if osDefaultRoles != "" && envData[constants.EnvKeyDefaultRoles] != osDefaultRoles { +// envData[constants.EnvKeyDefaultRoles] = osDefaultRoles +// } +// defaultRoles := strings.Split(envData[constants.EnvKeyDefaultRoles].(string), ",") +// if len(defaultRoles) == 0 { +// defaultRoles = []string{roles[0]} +// } + +// for _, role := range defaultRoles { +// if !utils.StringSliceContains(roles, role) { +// return fmt.Errorf("Default role %s is not defined in roles", role) +// } +// } + +// if val, ok := envData[constants.EnvKeyProtectedRoles]; !ok || val == "" { +// envData[constants.EnvKeyProtectedRoles] = osProtectedRoles +// } +// if osProtectedRoles != "" && 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 +// } + +// if val, ok := envData[constants.EnvKeyTwilioAPISecret]; !ok || val == "" { +// envData[constants.EnvKeyTwilioAPISecret] = osTwilioApiSecret +// } +// if osTwilioApiSecret != "" && envData[constants.EnvKeyTwilioAPISecret] != osTwilioApiSecret { +// envData[constants.EnvKeyTwilioAPISecret] = osTwilioApiSecret +// } + +// if val, ok := envData[constants.EnvKeyTwilioAPIKey]; !ok || val == "" { +// envData[constants.EnvKeyTwilioAPIKey] = osTwilioApiKey +// } +// if osTwilioApiKey != "" && envData[constants.EnvKeyTwilioAPIKey] != osTwilioApiKey { +// envData[constants.EnvKeyTwilioAPIKey] = osTwilioApiKey +// } + +// if val, ok := envData[constants.EnvKeyTwilioAccountSID]; !ok || val == "" { +// envData[constants.EnvKeyTwilioAccountSID] = osTwilioAccountSid +// } +// if osTwilioAccountSid != "" && envData[constants.EnvKeyTwilioAccountSID] != osTwilioAccountSid { +// envData[constants.EnvKeyTwilioAccountSID] = osTwilioAccountSid +// } + +// if val, ok := envData[constants.EnvKeyTwilioSender]; !ok || val == "" { +// envData[constants.EnvKeyTwilioSender] = osTwilioSender +// } +// if osTwilioSender != "" && envData[constants.EnvKeyTwilioSender] != osTwilioSender { +// envData[constants.EnvKeyTwilioSender] = osTwilioSender +// } + +// if _, ok := envData[constants.EnvKeyDisablePhoneVerification]; !ok { +// envData[constants.EnvKeyDisablePhoneVerification] = osDisablePhoneVerification == "false" +// } +// if osDisablePhoneVerification != "" { +// boolValue, err := strconv.ParseBool(osDisablePhoneVerification) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisablePhoneVerification] { +// envData[constants.EnvKeyDisablePhoneVerification] = boolValue +// } +// } + +// if envData[constants.EnvKeyTwilioAPIKey] == "" || envData[constants.EnvKeyTwilioAPISecret] == "" || envData[constants.EnvKeyTwilioAccountSID] == "" || envData[constants.EnvKeyTwilioSender] == "" { +// envData[constants.EnvKeyDisablePhoneVerification] = true +// envData[constants.EnvKeyIsSMSServiceEnabled] = false +// } +// if envData[constants.EnvKeyTwilioAPIKey] != "" && envData[constants.EnvKeyTwilioAPISecret] != "" && envData[constants.EnvKeyTwilioAccountSID] != "" && envData[constants.EnvKeyTwilioSender] != "" { +// envData[constants.EnvKeyDisablePhoneVerification] = false +// envData[constants.EnvKeyIsSMSServiceEnabled] = true +// } + +// if _, ok := envData[constants.EnvKeyDisablePlayGround]; !ok { +// envData[constants.EnvKeyDisablePlayGround] = osDisablePlayground == "true" +// } +// if osDisablePlayground != "" { +// boolValue, err := strconv.ParseBool(osDisablePlayground) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisablePlayGround].(bool) { +// envData[constants.EnvKeyDisablePlayGround] = boolValue +// } +// } +// // TODO: remove after beta launch +// envData[constants.EnvKeyDisableTOTPLogin] = true +// if _, ok := envData[constants.EnvKeyDisableTOTPLogin]; !ok { +// envData[constants.EnvKeyDisableTOTPLogin] = osDisableTOTPLogin == "true" +// } +// if osDisableTOTPLogin != "" { +// boolValue, err := strconv.ParseBool(osDisableTOTPLogin) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisableTOTPLogin].(bool) { +// envData[constants.EnvKeyDisableTOTPLogin] = boolValue +// } +// } + +// if _, ok := envData[constants.EnvKeyDisableMailOTPLogin]; !ok { +// envData[constants.EnvKeyDisableMailOTPLogin] = osDisableMailOTPLogin == "true" +// } +// if osDisableMailOTPLogin != "" { +// boolValue, err := strconv.ParseBool(osDisableMailOTPLogin) +// if err != nil { +// return err +// } +// if boolValue != envData[constants.EnvKeyDisableMailOTPLogin].(bool) { +// envData[constants.EnvKeyDisableMailOTPLogin] = boolValue +// } +// } + +// err = memorystore.Provider.UpdateEnvStore(envData) +// if err != nil { +// log.Debug("Error while updating env store: ", err) +// return err +// } +// return nil +// } diff --git a/internal/env/persist_env.go b/internal/env/persist_env.go new file mode 100644 index 000000000..ed827ca0a --- /dev/null +++ b/internal/env/persist_env.go @@ -0,0 +1,249 @@ +package env + +// func fixBackwardCompatibility(data map[string]interface{}) (bool, map[string]interface{}) { +// result := data +// // check if env data is stored in older format +// hasOlderFormat := false +// if _, ok := result["bool_env"]; ok { +// for key, value := range result["bool_env"].(map[string]interface{}) { +// result[key] = value +// } +// hasOlderFormat = true +// delete(result, "bool_env") +// } + +// if _, ok := result["string_env"]; ok { +// for key, value := range result["string_env"].(map[string]interface{}) { +// result[key] = value +// } +// hasOlderFormat = true +// delete(result, "string_env") +// } + +// if _, ok := result["slice_env"]; ok { +// for key, value := range result["slice_env"].(map[string]interface{}) { +// typeOfValue := reflect.TypeOf(value) +// if strings.Contains(typeOfValue.String(), "[]string") { +// result[key] = strings.Join(value.([]string), ",") +// } +// if strings.Contains(typeOfValue.String(), "[]interface") { +// result[key] = strings.Join(utils.ConvertInterfaceToStringSlice(value), ",") +// } +// } +// hasOlderFormat = true +// delete(result, "slice_env") +// } + +// return hasOlderFormat, result +// } + +// // GetEnvData returns the env data from database +// func GetEnvData() (map[string]interface{}, error) { +// var result map[string]interface{} +// ctx := context.Background() +// env, err := db.Provider.GetEnv(ctx) +// // config not found in db +// if err != nil || env == nil { +// log.Debug("Error while getting env data from db: ", err) +// return result, err +// } + +// encryptionKey := env.Hash +// decryptedEncryptionKey, err := crypto.DecryptB64(encryptionKey) +// if err != nil { +// log.Debug("Error while decrypting encryption key: ", err) +// return result, err +// } + +// memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey) +// b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData) +// if err != nil { +// log.Debug("Error while decrypting env data from B64: ", err) +// return result, err +// } + +// decryptedConfigs, err := crypto.DecryptAESEnv([]byte(b64DecryptedConfig)) +// if err != nil { +// log.Debug("Error while decrypting env data from AES: ", err) +// return result, err +// } + +// err = json.Unmarshal(decryptedConfigs, &result) +// if err != nil { +// log.Debug("Error while unmarshalling env data: ", err) +// return result, err +// } + +// hasOlderFormat, result := fixBackwardCompatibility(result) + +// if hasOlderFormat { +// err = memorystore.Provider.UpdateEnvStore(result) +// if err != nil { +// log.Debug("Error while updating env store: ", err) +// return result, err +// } + +// } + +// return result, err +// } + +// // PersistEnv persists the environment variables to the database +// func PersistEnv() error { +// ctx := context.Background() +// env, err := db.Provider.GetEnv(ctx) +// // config not found in db +// if err != nil || env == nil { +// // AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid +// hash := uuid.New().String()[:36-4] +// err := memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, hash) +// if err != nil { +// log.Debug("Error while updating encryption env variable: ", err) +// return err +// } +// encodedHash := crypto.EncryptB64(hash) +// res, err := memorystore.Provider.GetEnvStore() +// if err != nil { +// log.Debug("Error while getting env store: ", err) +// return err +// } +// encryptedConfig, err := crypto.EncryptEnvData(res) +// if err != nil { +// log.Debug("Error while encrypting env data: ", err) +// return err +// } +// env = &models.Env{ +// Hash: encodedHash, +// EnvData: encryptedConfig, +// } +// _, err = db.Provider.AddEnv(ctx, env) +// if err != nil { +// log.Debug("Error while persisting env data to db: ", err) +// return err +// } +// } else { +// // decrypt the config data from db +// // decryption can be done using the hash stored in db +// encryptionKey := env.Hash +// decryptedEncryptionKey, err := crypto.DecryptB64(encryptionKey) +// if err != nil { +// log.Debug("Error while decrypting encryption key: ", err) +// return err +// } + +// memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey) + +// b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData) +// if err != nil { +// log.Debug("Error while decrypting env data from B64: ", err) +// return err +// } + +// decryptedConfigs, err := crypto.DecryptAESEnv([]byte(b64DecryptedConfig)) +// if err != nil { +// log.Debug("Error while decrypting env data from AES: ", err) +// return err +// } + +// // temp store variable +// storeData := map[string]interface{}{} + +// err = json.Unmarshal(decryptedConfigs, &storeData) +// if err != nil { +// log.Debug("Error while un-marshalling env data: ", err) +// return err +// } + +// hasOlderFormat, result := fixBackwardCompatibility(storeData) +// if hasOlderFormat { +// err = memorystore.Provider.UpdateEnvStore(result) +// if err != nil { +// log.Debug("Error while updating env store: ", err) +// return err +// } + +// } + +// // if env is changed via env file or OS env +// // give that higher preference and update db, but we don't recommend it + +// hasChanged := false +// for key, value := range storeData { +// // don't override unexposed envs +// // check only for derivative keys +// // No need to check for ENCRYPTION_KEY which special key we use for encrypting config data +// // as we have removed it from json +// if key != constants.EnvKeyEncryptionKey { +// envValue := strings.TrimSpace(os.Getenv(key)) +// if envValue != "" { +// switch key { +// case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyIsSMSServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure, constants.EnvKeyDisablePhoneVerification, constants.EnvKeyDisablePlayGround, constants.EnvKeyDisableTOTPLogin, constants.EnvKeyDisableMailOTPLogin: +// if envValueBool, err := strconv.ParseBool(envValue); err == nil { +// if value.(bool) != envValueBool { +// storeData[key] = envValueBool +// hasChanged = true +// } +// } +// default: +// if value != nil && value.(string) != envValue { +// storeData[key] = envValue +// hasChanged = true +// } +// } +// } +// } +// } + +// // handle derivative cases like disabling email verification & magic login +// // in case SMTP is off but env is set to true +// if storeData[constants.EnvKeySmtpHost] == "" || storeData[constants.EnvKeySmtpUsername] == "" || storeData[constants.EnvKeySmtpPassword] == "" || storeData[constants.EnvKeySenderEmail] == "" && storeData[constants.EnvKeySmtpPort] == "" { +// storeData[constants.EnvKeyIsEmailServiceEnabled] = false + +// if val, ok := storeData[constants.EnvKeyDisableEmailVerification]; ok && val != nil && !val.(bool) { +// storeData[constants.EnvKeyDisableEmailVerification] = true +// hasChanged = true +// } + +// if val, ok := storeData[constants.EnvKeyDisableMagicLinkLogin]; ok && val != nil && !val.(bool) { +// storeData[constants.EnvKeyDisableMagicLinkLogin] = true +// hasChanged = true +// } + +// if val, ok := storeData[constants.EnvKeyDisableMailOTPLogin]; ok && val != nil && !val.(bool) { +// storeData[constants.EnvKeyDisableMailOTPLogin] = true +// hasChanged = true +// } +// } + +// err = memorystore.Provider.UpdateEnvStore(storeData) +// if err != nil { +// log.Debug("Error while updating env store: ", err) +// return err +// } + +// jwk, err := crypto.GenerateJWKBasedOnEnv() +// if err != nil { +// log.Debug("Error while generating JWK: ", err) +// return err +// } +// // updating jwk +// memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJWK, jwk) + +// if hasChanged { +// encryptedConfig, err := crypto.EncryptEnvData(storeData) +// if err != nil { +// log.Debug("Error while encrypting env data: ", err) +// return err +// } + +// env.EnvData = encryptedConfig +// _, err = db.Provider.UpdateEnv(ctx, env) +// if err != nil { +// log.Debug("Failed to Update Config: ", err) +// return err +// } +// } +// } + +// return nil +// } diff --git a/internal/events/events.go b/internal/events/events.go new file mode 100644 index 000000000..5ab1d93b5 --- /dev/null +++ b/internal/events/events.go @@ -0,0 +1,142 @@ +package events + +import ( + "bytes" + "context" + "encoding/json" + "io" + "net/http" + "time" + + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/storage" + "github.com/authorizerdev/authorizer/internal/storage/schemas" +) + +// Dependencies for events +type Dependencies struct { + Log *zerolog.Logger + StorageProvider storage.Provider +} + +// Provider interface for registering events +type Provider interface { + // RegisterEvent to register event and add webhook logs + RegisterEvent(ctx context.Context, eventName string, authRecipe string, user *schemas.User) error +} + +type provider struct { + config *config.Config + deps *Dependencies +} + +// New returns a new events provider +func New(config *config.Config, deps *Dependencies) (Provider, error) { + return &provider{ + config: config, + deps: deps, + }, nil +} + +// RegisterEvent util to register event +func (p *provider) RegisterEvent(ctx context.Context, eventName string, authRecipe string, user *schemas.User) error { + log := p.deps.Log.With().Str("func", "RegisterEvent").Str("event", eventName).Logger() + webhooks, err := p.deps.StorageProvider.GetWebhookByEventName(ctx, eventName) + if err != nil { + log.Debug().Err(err).Msg("error getting webhook") + return err + } + for _, webhook := range webhooks { + if !webhook.Enabled { + continue + } + userBytes, err := json.Marshal(user.AsAPIUser()) + if err != nil { + log.Debug().Err(err).Msg("error marshalling user obj") + continue + } + userMap := map[string]interface{}{} + err = json.Unmarshal(userBytes, &userMap) + if err != nil { + log.Debug().Err(err).Msg("error un-marshalling user obj") + continue + } + + reqBody := map[string]interface{}{ + "webhook_id": webhook.ID, + "event_name": eventName, + "event_description": webhook.EventDescription, + "user": userMap, + } + + if eventName == constants.UserLoginWebhookEvent || eventName == constants.UserSignUpWebhookEvent { + reqBody["auth_recipe"] = authRecipe + } + + requestBody, err := json.Marshal(reqBody) + if err != nil { + log.Debug().Err(err).Msg("error marshalling requestBody obj") + continue + } + + // don't trigger webhook call in case of test + if p.config.Env == constants.TestEnv { + _, err := p.deps.StorageProvider.AddWebhookLog(ctx, &schemas.WebhookLog{ + HttpStatus: 200, + Request: string(requestBody), + Response: string(`{"message": "test"}`), + WebhookID: webhook.ID, + }) + if err != nil { + log.Debug().Err(err).Msg("error saving webhook log") + } + continue + } + + requestBytesBuffer := bytes.NewBuffer(requestBody) + req, err := http.NewRequest("POST", webhook.EndPoint, requestBytesBuffer) + if err != nil { + log.Debug().Err(err).Msg("error creating request") + continue + } + req.Header.Set("Content-Type", "application/json") + headersMap := make(map[string]interface{}) + err = json.Unmarshal([]byte(webhook.Headers), &headersMap) + if err != nil { + log.Debug().Err(err).Msg("error un-marshalling headers") + } + for key, val := range headersMap { + req.Header.Set(key, val.(string)) + } + + client := &http.Client{Timeout: time.Second * 30} + resp, err := client.Do(req) + if err != nil { + log.Debug().Err(err).Msg("error making request") + continue + } + defer resp.Body.Close() + + responseBytes, err := io.ReadAll(resp.Body) + if err != nil { + log.Debug().Err(err).Msg("error reading response") + continue + } + + statusCode := int64(resp.StatusCode) + _, err = p.deps.StorageProvider.AddWebhookLog(ctx, &schemas.WebhookLog{ + HttpStatus: statusCode, + Request: string(requestBody), + Response: string(responseBytes), + WebhookID: webhook.ID, + }) + if err != nil { + log.Debug().Err(err).Msg("error saving webhook log") + continue + } + } + return nil +} diff --git a/server/graph/generated/generated.go b/internal/graph/generated/generated.go similarity index 86% rename from server/graph/generated/generated.go rename to internal/graph/generated/generated.go index fe4c09eed..2f8ea7905 100644 --- a/server/graph/generated/generated.go +++ b/internal/graph/generated/generated.go @@ -13,7 +13,7 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/introspection" - "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/internal/graph/model" gqlparser "github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2/ast" ) @@ -197,35 +197,35 @@ type ComplexityRoot struct { Mutation struct { AddEmailTemplate func(childComplexity int, params model.AddEmailTemplateRequest) int AddWebhook func(childComplexity int, params model.AddWebhookRequest) int - AdminLogin func(childComplexity int, params model.AdminLoginInput) int + AdminLogin func(childComplexity int, params model.AdminLoginRequest) int AdminLogout func(childComplexity int) int - AdminSignup func(childComplexity int, params model.AdminSignupInput) int + AdminSignup func(childComplexity int, params model.AdminSignupRequest) int DeactivateAccount func(childComplexity int) int DeleteEmailTemplate func(childComplexity int, params model.DeleteEmailTemplateRequest) int - DeleteUser func(childComplexity int, params model.DeleteUserInput) int + DeleteUser func(childComplexity int, params model.DeleteUserRequest) int DeleteWebhook func(childComplexity int, params model.WebhookRequest) int - EnableAccess func(childComplexity int, param model.UpdateAccessInput) int - ForgotPassword func(childComplexity int, params model.ForgotPasswordInput) int - GenerateJwtKeys func(childComplexity int, params model.GenerateJWTKeysInput) int - InviteMembers func(childComplexity int, params model.InviteMemberInput) int - Login func(childComplexity int, params model.LoginInput) int + EnableAccess func(childComplexity int, param model.UpdateAccessRequest) int + ForgotPassword func(childComplexity int, params model.ForgotPasswordRequest) int + GenerateJwtKeys func(childComplexity int, params model.GenerateJWTKeysRequest) int + InviteMembers func(childComplexity int, params model.InviteMemberRequest) int + Login func(childComplexity int, params model.LoginRequest) int Logout func(childComplexity int) int - MagicLinkLogin func(childComplexity int, params model.MagicLinkLoginInput) int - MobileLogin func(childComplexity int, params model.MobileLoginInput) int - MobileSignup func(childComplexity int, params *model.MobileSignUpInput) int + MagicLinkLogin func(childComplexity int, params model.MagicLinkLoginRequest) int + MobileLogin func(childComplexity int, params model.MobileLoginRequest) int + MobileSignup func(childComplexity int, params *model.MobileSignUpRequest) int ResendOtp func(childComplexity int, params model.ResendOTPRequest) int - ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int - ResetPassword func(childComplexity int, params model.ResetPasswordInput) int - Revoke func(childComplexity int, params model.OAuthRevokeInput) int - RevokeAccess func(childComplexity int, param model.UpdateAccessInput) int - Signup func(childComplexity int, params model.SignUpInput) int + ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailRequest) int + ResetPassword func(childComplexity int, params model.ResetPasswordRequest) int + Revoke func(childComplexity int, params model.OAuthRevokeRequest) int + RevokeAccess func(childComplexity int, param model.UpdateAccessRequest) int + Signup func(childComplexity int, params model.SignUpRequest) int TestEndpoint func(childComplexity int, params model.TestEndpointRequest) int UpdateEmailTemplate func(childComplexity int, params model.UpdateEmailTemplateRequest) int - UpdateEnv func(childComplexity int, params model.UpdateEnvInput) int - UpdateProfile func(childComplexity int, params model.UpdateProfileInput) int - UpdateUser func(childComplexity int, params model.UpdateUserInput) int + UpdateEnv func(childComplexity int, params model.UpdateEnvRequest) int + UpdateProfile func(childComplexity int, params model.UpdateProfileRequest) int + UpdateUser func(childComplexity int, params model.UpdateUserRequest) int UpdateWebhook func(childComplexity int, params model.UpdateWebhookRequest) int - VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int + VerifyEmail func(childComplexity int, params model.VerifyEmailRequest) int VerifyOtp func(childComplexity int, params model.VerifyOTPRequest) int } @@ -238,34 +238,25 @@ type ComplexityRoot struct { Query struct { AdminSession func(childComplexity int) int - EmailTemplates func(childComplexity int, params *model.PaginatedInput) int + EmailTemplates func(childComplexity int, params *model.PaginatedRequest) int Env func(childComplexity int) int Meta func(childComplexity int) int Profile func(childComplexity int) int - Session func(childComplexity int, params *model.SessionQueryInput) int + Session func(childComplexity int, params *model.SessionQueryRequest) int User func(childComplexity int, params model.GetUserRequest) int - Users func(childComplexity int, params *model.PaginatedInput) int - ValidateJwtToken func(childComplexity int, params model.ValidateJWTTokenInput) int - ValidateSession func(childComplexity int, params *model.ValidateSessionInput) int - VerificationRequests func(childComplexity int, params *model.PaginatedInput) int + Users func(childComplexity int, params *model.PaginatedRequest) int + ValidateJwtToken func(childComplexity int, params model.ValidateJWTTokenRequest) int + ValidateSession func(childComplexity int, params *model.ValidateSessionRequest) int + VerificationRequests func(childComplexity int, params *model.PaginatedRequest) int Webhook func(childComplexity int, params model.WebhookRequest) int WebhookLogs func(childComplexity int, params *model.ListWebhookLogRequest) int - Webhooks func(childComplexity int, params *model.PaginatedInput) int + Webhooks func(childComplexity int, params *model.PaginatedRequest) int } Response struct { Message func(childComplexity int) int } - SMSVerificationRequests struct { - Code func(childComplexity int) int - CodeExpiresAt func(childComplexity int) int - CreatedAt func(childComplexity int) int - ID func(childComplexity int) int - PhoneNumber func(childComplexity int) int - UpdatedAt func(childComplexity int) int - } - TestEndpointResponse struct { HTTPStatus func(childComplexity int) int Response func(childComplexity int) int @@ -359,31 +350,31 @@ type ComplexityRoot struct { } type MutationResolver interface { - Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) - MobileSignup(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error) - Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) - MobileLogin(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error) - MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) + Signup(ctx context.Context, params model.SignUpRequest) (*model.AuthResponse, error) + MobileSignup(ctx context.Context, params *model.MobileSignUpRequest) (*model.AuthResponse, error) + Login(ctx context.Context, params model.LoginRequest) (*model.AuthResponse, error) + MobileLogin(ctx context.Context, params model.MobileLoginRequest) (*model.AuthResponse, error) + MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginRequest) (*model.Response, error) Logout(ctx context.Context) (*model.Response, error) - UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error) - VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error) - ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) - ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.ForgotPasswordResponse, error) - ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) - Revoke(ctx context.Context, params model.OAuthRevokeInput) (*model.Response, error) + UpdateProfile(ctx context.Context, params model.UpdateProfileRequest) (*model.Response, error) + VerifyEmail(ctx context.Context, params model.VerifyEmailRequest) (*model.AuthResponse, error) + ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailRequest) (*model.Response, error) + ForgotPassword(ctx context.Context, params model.ForgotPasswordRequest) (*model.ForgotPasswordResponse, error) + ResetPassword(ctx context.Context, params model.ResetPasswordRequest) (*model.Response, error) + Revoke(ctx context.Context, params model.OAuthRevokeRequest) (*model.Response, error) VerifyOtp(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error) ResendOtp(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error) DeactivateAccount(ctx context.Context) (*model.Response, error) - DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) - UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error) - AdminSignup(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) - AdminLogin(ctx context.Context, params model.AdminLoginInput) (*model.Response, error) + DeleteUser(ctx context.Context, params model.DeleteUserRequest) (*model.Response, error) + UpdateUser(ctx context.Context, params model.UpdateUserRequest) (*model.User, error) + AdminSignup(ctx context.Context, params model.AdminSignupRequest) (*model.Response, error) + AdminLogin(ctx context.Context, params model.AdminLoginRequest) (*model.Response, error) AdminLogout(ctx context.Context) (*model.Response, error) - UpdateEnv(ctx context.Context, params model.UpdateEnvInput) (*model.Response, error) - InviteMembers(ctx context.Context, params model.InviteMemberInput) (*model.InviteMembersResponse, error) - RevokeAccess(ctx context.Context, param model.UpdateAccessInput) (*model.Response, error) - EnableAccess(ctx context.Context, param model.UpdateAccessInput) (*model.Response, error) - GenerateJwtKeys(ctx context.Context, params model.GenerateJWTKeysInput) (*model.GenerateJWTKeysResponse, error) + UpdateEnv(ctx context.Context, params model.UpdateEnvRequest) (*model.Response, error) + InviteMembers(ctx context.Context, params model.InviteMemberRequest) (*model.InviteMembersResponse, error) + RevokeAccess(ctx context.Context, param model.UpdateAccessRequest) (*model.Response, error) + EnableAccess(ctx context.Context, param model.UpdateAccessRequest) (*model.Response, error) + GenerateJwtKeys(ctx context.Context, params model.GenerateJWTKeysRequest) (*model.GenerateJWTKeysResponse, error) AddWebhook(ctx context.Context, params model.AddWebhookRequest) (*model.Response, error) UpdateWebhook(ctx context.Context, params model.UpdateWebhookRequest) (*model.Response, error) DeleteWebhook(ctx context.Context, params model.WebhookRequest) (*model.Response, error) @@ -394,19 +385,19 @@ type MutationResolver interface { } type QueryResolver interface { Meta(ctx context.Context) (*model.Meta, error) - Session(ctx context.Context, params *model.SessionQueryInput) (*model.AuthResponse, error) + Session(ctx context.Context, params *model.SessionQueryRequest) (*model.AuthResponse, error) Profile(ctx context.Context) (*model.User, error) - ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) - ValidateSession(ctx context.Context, params *model.ValidateSessionInput) (*model.ValidateSessionResponse, error) - Users(ctx context.Context, params *model.PaginatedInput) (*model.Users, error) + ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenRequest) (*model.ValidateJWTTokenResponse, error) + ValidateSession(ctx context.Context, params *model.ValidateSessionRequest) (*model.ValidateSessionResponse, error) + Users(ctx context.Context, params *model.PaginatedRequest) (*model.Users, error) User(ctx context.Context, params model.GetUserRequest) (*model.User, error) - VerificationRequests(ctx context.Context, params *model.PaginatedInput) (*model.VerificationRequests, error) + VerificationRequests(ctx context.Context, params *model.PaginatedRequest) (*model.VerificationRequests, error) AdminSession(ctx context.Context) (*model.Response, error) Env(ctx context.Context) (*model.Env, error) Webhook(ctx context.Context, params model.WebhookRequest) (*model.Webhook, error) - Webhooks(ctx context.Context, params *model.PaginatedInput) (*model.Webhooks, error) + Webhooks(ctx context.Context, params *model.PaginatedRequest) (*model.Webhooks, error) WebhookLogs(ctx context.Context, params *model.ListWebhookLogRequest) (*model.WebhookLogs, error) - EmailTemplates(ctx context.Context, params *model.PaginatedInput) (*model.EmailTemplates, error) + EmailTemplates(ctx context.Context, params *model.PaginatedRequest) (*model.EmailTemplates, error) } type executableSchema struct { @@ -423,7 +414,7 @@ func (e *executableSchema) Schema() *ast.Schema { return parsedSchema } -func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) { +func (e *executableSchema) Complexity(ctx context.Context, typeName, field string, childComplexity int, rawArgs map[string]any) (int, bool) { ec := executionContext{nil, e, 0, 0, nil} _ = ec switch typeName + "." + field { @@ -1280,7 +1271,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation__add_email_template_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__add_email_template_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1292,7 +1283,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation__add_webhook_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__add_webhook_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1304,12 +1295,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation__admin_login_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__admin_login_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.AdminLogin(childComplexity, args["params"].(model.AdminLoginInput)), true + return e.complexity.Mutation.AdminLogin(childComplexity, args["params"].(model.AdminLoginRequest)), true case "Mutation._admin_logout": if e.complexity.Mutation.AdminLogout == nil { @@ -1323,12 +1314,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation__admin_signup_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__admin_signup_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.AdminSignup(childComplexity, args["params"].(model.AdminSignupInput)), true + return e.complexity.Mutation.AdminSignup(childComplexity, args["params"].(model.AdminSignupRequest)), true case "Mutation.deactivate_account": if e.complexity.Mutation.DeactivateAccount == nil { @@ -1342,7 +1333,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation__delete_email_template_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__delete_email_template_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1354,19 +1345,19 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation__delete_user_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__delete_user_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.DeleteUser(childComplexity, args["params"].(model.DeleteUserInput)), true + return e.complexity.Mutation.DeleteUser(childComplexity, args["params"].(model.DeleteUserRequest)), true case "Mutation._delete_webhook": if e.complexity.Mutation.DeleteWebhook == nil { break } - args, err := ec.field_Mutation__delete_webhook_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__delete_webhook_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1378,60 +1369,60 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation__enable_access_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__enable_access_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.EnableAccess(childComplexity, args["param"].(model.UpdateAccessInput)), true + return e.complexity.Mutation.EnableAccess(childComplexity, args["param"].(model.UpdateAccessRequest)), true case "Mutation.forgot_password": if e.complexity.Mutation.ForgotPassword == nil { break } - args, err := ec.field_Mutation_forgot_password_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_forgot_password_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.ForgotPassword(childComplexity, args["params"].(model.ForgotPasswordInput)), true + return e.complexity.Mutation.ForgotPassword(childComplexity, args["params"].(model.ForgotPasswordRequest)), true case "Mutation._generate_jwt_keys": if e.complexity.Mutation.GenerateJwtKeys == nil { break } - args, err := ec.field_Mutation__generate_jwt_keys_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__generate_jwt_keys_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.GenerateJwtKeys(childComplexity, args["params"].(model.GenerateJWTKeysInput)), true + return e.complexity.Mutation.GenerateJwtKeys(childComplexity, args["params"].(model.GenerateJWTKeysRequest)), true case "Mutation._invite_members": if e.complexity.Mutation.InviteMembers == nil { break } - args, err := ec.field_Mutation__invite_members_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__invite_members_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.InviteMembers(childComplexity, args["params"].(model.InviteMemberInput)), true + return e.complexity.Mutation.InviteMembers(childComplexity, args["params"].(model.InviteMemberRequest)), true case "Mutation.login": if e.complexity.Mutation.Login == nil { break } - args, err := ec.field_Mutation_login_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_login_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.Login(childComplexity, args["params"].(model.LoginInput)), true + return e.complexity.Mutation.Login(childComplexity, args["params"].(model.LoginRequest)), true case "Mutation.logout": if e.complexity.Mutation.Logout == nil { @@ -1445,43 +1436,43 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation_magic_link_login_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_magic_link_login_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.MagicLinkLogin(childComplexity, args["params"].(model.MagicLinkLoginInput)), true + return e.complexity.Mutation.MagicLinkLogin(childComplexity, args["params"].(model.MagicLinkLoginRequest)), true case "Mutation.mobile_login": if e.complexity.Mutation.MobileLogin == nil { break } - args, err := ec.field_Mutation_mobile_login_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_mobile_login_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.MobileLogin(childComplexity, args["params"].(model.MobileLoginInput)), true + return e.complexity.Mutation.MobileLogin(childComplexity, args["params"].(model.MobileLoginRequest)), true case "Mutation.mobile_signup": if e.complexity.Mutation.MobileSignup == nil { break } - args, err := ec.field_Mutation_mobile_signup_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_mobile_signup_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.MobileSignup(childComplexity, args["params"].(*model.MobileSignUpInput)), true + return e.complexity.Mutation.MobileSignup(childComplexity, args["params"].(*model.MobileSignUpRequest)), true case "Mutation.resend_otp": if e.complexity.Mutation.ResendOtp == nil { break } - args, err := ec.field_Mutation_resend_otp_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_resend_otp_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1493,67 +1484,67 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation_resend_verify_email_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_resend_verify_email_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.ResendVerifyEmail(childComplexity, args["params"].(model.ResendVerifyEmailInput)), true + return e.complexity.Mutation.ResendVerifyEmail(childComplexity, args["params"].(model.ResendVerifyEmailRequest)), true case "Mutation.reset_password": if e.complexity.Mutation.ResetPassword == nil { break } - args, err := ec.field_Mutation_reset_password_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_reset_password_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.ResetPassword(childComplexity, args["params"].(model.ResetPasswordInput)), true + return e.complexity.Mutation.ResetPassword(childComplexity, args["params"].(model.ResetPasswordRequest)), true case "Mutation.revoke": if e.complexity.Mutation.Revoke == nil { break } - args, err := ec.field_Mutation_revoke_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_revoke_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.Revoke(childComplexity, args["params"].(model.OAuthRevokeInput)), true + return e.complexity.Mutation.Revoke(childComplexity, args["params"].(model.OAuthRevokeRequest)), true case "Mutation._revoke_access": if e.complexity.Mutation.RevokeAccess == nil { break } - args, err := ec.field_Mutation__revoke_access_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__revoke_access_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.RevokeAccess(childComplexity, args["param"].(model.UpdateAccessInput)), true + return e.complexity.Mutation.RevokeAccess(childComplexity, args["param"].(model.UpdateAccessRequest)), true case "Mutation.signup": if e.complexity.Mutation.Signup == nil { break } - args, err := ec.field_Mutation_signup_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_signup_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.Signup(childComplexity, args["params"].(model.SignUpInput)), true + return e.complexity.Mutation.Signup(childComplexity, args["params"].(model.SignUpRequest)), true case "Mutation._test_endpoint": if e.complexity.Mutation.TestEndpoint == nil { break } - args, err := ec.field_Mutation__test_endpoint_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__test_endpoint_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1565,7 +1556,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation__update_email_template_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__update_email_template_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1577,43 +1568,43 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation__update_env_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__update_env_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.UpdateEnv(childComplexity, args["params"].(model.UpdateEnvInput)), true + return e.complexity.Mutation.UpdateEnv(childComplexity, args["params"].(model.UpdateEnvRequest)), true case "Mutation.update_profile": if e.complexity.Mutation.UpdateProfile == nil { break } - args, err := ec.field_Mutation_update_profile_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_update_profile_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.UpdateProfile(childComplexity, args["params"].(model.UpdateProfileInput)), true + return e.complexity.Mutation.UpdateProfile(childComplexity, args["params"].(model.UpdateProfileRequest)), true case "Mutation._update_user": if e.complexity.Mutation.UpdateUser == nil { break } - args, err := ec.field_Mutation__update_user_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__update_user_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.UpdateUser(childComplexity, args["params"].(model.UpdateUserInput)), true + return e.complexity.Mutation.UpdateUser(childComplexity, args["params"].(model.UpdateUserRequest)), true case "Mutation._update_webhook": if e.complexity.Mutation.UpdateWebhook == nil { break } - args, err := ec.field_Mutation__update_webhook_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation__update_webhook_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1625,19 +1616,19 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Mutation_verify_email_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_verify_email_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.VerifyEmail(childComplexity, args["params"].(model.VerifyEmailInput)), true + return e.complexity.Mutation.VerifyEmail(childComplexity, args["params"].(model.VerifyEmailRequest)), true case "Mutation.verify_otp": if e.complexity.Mutation.VerifyOtp == nil { break } - args, err := ec.field_Mutation_verify_otp_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_verify_otp_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1684,12 +1675,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Query__email_templates_args(context.TODO(), rawArgs) + args, err := ec.field_Query__email_templates_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Query.EmailTemplates(childComplexity, args["params"].(*model.PaginatedInput)), true + return e.complexity.Query.EmailTemplates(childComplexity, args["params"].(*model.PaginatedRequest)), true case "Query._env": if e.complexity.Query.Env == nil { @@ -1717,19 +1708,19 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Query_session_args(context.TODO(), rawArgs) + args, err := ec.field_Query_session_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Query.Session(childComplexity, args["params"].(*model.SessionQueryInput)), true + return e.complexity.Query.Session(childComplexity, args["params"].(*model.SessionQueryRequest)), true case "Query._user": if e.complexity.Query.User == nil { break } - args, err := ec.field_Query__user_args(context.TODO(), rawArgs) + args, err := ec.field_Query__user_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1741,55 +1732,55 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Query__users_args(context.TODO(), rawArgs) + args, err := ec.field_Query__users_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Query.Users(childComplexity, args["params"].(*model.PaginatedInput)), true + return e.complexity.Query.Users(childComplexity, args["params"].(*model.PaginatedRequest)), true case "Query.validate_jwt_token": if e.complexity.Query.ValidateJwtToken == nil { break } - args, err := ec.field_Query_validate_jwt_token_args(context.TODO(), rawArgs) + args, err := ec.field_Query_validate_jwt_token_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Query.ValidateJwtToken(childComplexity, args["params"].(model.ValidateJWTTokenInput)), true + return e.complexity.Query.ValidateJwtToken(childComplexity, args["params"].(model.ValidateJWTTokenRequest)), true case "Query.validate_session": if e.complexity.Query.ValidateSession == nil { break } - args, err := ec.field_Query_validate_session_args(context.TODO(), rawArgs) + args, err := ec.field_Query_validate_session_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Query.ValidateSession(childComplexity, args["params"].(*model.ValidateSessionInput)), true + return e.complexity.Query.ValidateSession(childComplexity, args["params"].(*model.ValidateSessionRequest)), true case "Query._verification_requests": if e.complexity.Query.VerificationRequests == nil { break } - args, err := ec.field_Query__verification_requests_args(context.TODO(), rawArgs) + args, err := ec.field_Query__verification_requests_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Query.VerificationRequests(childComplexity, args["params"].(*model.PaginatedInput)), true + return e.complexity.Query.VerificationRequests(childComplexity, args["params"].(*model.PaginatedRequest)), true case "Query._webhook": if e.complexity.Query.Webhook == nil { break } - args, err := ec.field_Query__webhook_args(context.TODO(), rawArgs) + args, err := ec.field_Query__webhook_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1801,7 +1792,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Query__webhook_logs_args(context.TODO(), rawArgs) + args, err := ec.field_Query__webhook_logs_args(ctx, rawArgs) if err != nil { return 0, false } @@ -1813,12 +1804,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Query__webhooks_args(context.TODO(), rawArgs) + args, err := ec.field_Query__webhooks_args(ctx, rawArgs) if err != nil { return 0, false } - return e.complexity.Query.Webhooks(childComplexity, args["params"].(*model.PaginatedInput)), true + return e.complexity.Query.Webhooks(childComplexity, args["params"].(*model.PaginatedRequest)), true case "Response.message": if e.complexity.Response.Message == nil { @@ -1827,48 +1818,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Response.Message(childComplexity), true - case "SMSVerificationRequests.code": - if e.complexity.SMSVerificationRequests.Code == nil { - break - } - - return e.complexity.SMSVerificationRequests.Code(childComplexity), true - - case "SMSVerificationRequests.code_expires_at": - if e.complexity.SMSVerificationRequests.CodeExpiresAt == nil { - break - } - - return e.complexity.SMSVerificationRequests.CodeExpiresAt(childComplexity), true - - case "SMSVerificationRequests.created_at": - if e.complexity.SMSVerificationRequests.CreatedAt == nil { - break - } - - return e.complexity.SMSVerificationRequests.CreatedAt(childComplexity), true - - case "SMSVerificationRequests.id": - if e.complexity.SMSVerificationRequests.ID == nil { - break - } - - return e.complexity.SMSVerificationRequests.ID(childComplexity), true - - case "SMSVerificationRequests.phone_number": - if e.complexity.SMSVerificationRequests.PhoneNumber == nil { - break - } - - return e.complexity.SMSVerificationRequests.PhoneNumber(childComplexity), true - - case "SMSVerificationRequests.updated_at": - if e.complexity.SMSVerificationRequests.UpdatedAt == nil { - break - } - - return e.complexity.SMSVerificationRequests.UpdatedAt(childComplexity), true - case "TestEndpointResponse.http_status": if e.complexity.TestEndpointResponse.HTTPStatus == nil { break @@ -2280,48 +2229,48 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in } func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { - rc := graphql.GetOperationContext(ctx) - ec := executionContext{rc, e, 0, 0, make(chan graphql.DeferredResult)} + opCtx := graphql.GetOperationContext(ctx) + ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)} inputUnmarshalMap := graphql.BuildUnmarshalerMap( ec.unmarshalInputAddEmailTemplateRequest, ec.unmarshalInputAddWebhookRequest, - ec.unmarshalInputAdminLoginInput, - ec.unmarshalInputAdminSignupInput, + ec.unmarshalInputAdminLoginRequest, + ec.unmarshalInputAdminSignupRequest, ec.unmarshalInputDeleteEmailTemplateRequest, - ec.unmarshalInputDeleteUserInput, - ec.unmarshalInputForgotPasswordInput, - ec.unmarshalInputGenerateJWTKeysInput, + ec.unmarshalInputDeleteUserRequest, + ec.unmarshalInputForgotPasswordRequest, + ec.unmarshalInputGenerateJWTKeysRequest, ec.unmarshalInputGetUserRequest, - ec.unmarshalInputInviteMemberInput, + ec.unmarshalInputInviteMemberRequest, ec.unmarshalInputListWebhookLogRequest, - ec.unmarshalInputLoginInput, - ec.unmarshalInputMagicLinkLoginInput, - ec.unmarshalInputMobileLoginInput, - ec.unmarshalInputMobileSignUpInput, - ec.unmarshalInputOAuthRevokeInput, - ec.unmarshalInputPaginatedInput, - ec.unmarshalInputPaginationInput, + ec.unmarshalInputLoginRequest, + ec.unmarshalInputMagicLinkLoginRequest, + ec.unmarshalInputMobileLoginRequest, + ec.unmarshalInputMobileSignUpRequest, + ec.unmarshalInputOAuthRevokeRequest, + ec.unmarshalInputPaginatedRequest, + ec.unmarshalInputPaginationRequest, ec.unmarshalInputResendOTPRequest, - ec.unmarshalInputResendVerifyEmailInput, - ec.unmarshalInputResetPasswordInput, - ec.unmarshalInputSessionQueryInput, - ec.unmarshalInputSignUpInput, + ec.unmarshalInputResendVerifyEmailRequest, + ec.unmarshalInputResetPasswordRequest, + ec.unmarshalInputSessionQueryRequest, + ec.unmarshalInputSignUpRequest, ec.unmarshalInputTestEndpointRequest, - ec.unmarshalInputUpdateAccessInput, + ec.unmarshalInputUpdateAccessRequest, ec.unmarshalInputUpdateEmailTemplateRequest, - ec.unmarshalInputUpdateEnvInput, - ec.unmarshalInputUpdateProfileInput, - ec.unmarshalInputUpdateUserInput, + ec.unmarshalInputUpdateEnvRequest, + ec.unmarshalInputUpdateProfileRequest, + ec.unmarshalInputUpdateUserRequest, ec.unmarshalInputUpdateWebhookRequest, - ec.unmarshalInputValidateJWTTokenInput, - ec.unmarshalInputValidateSessionInput, - ec.unmarshalInputVerifyEmailInput, + ec.unmarshalInputValidateJWTTokenRequest, + ec.unmarshalInputValidateSessionRequest, + ec.unmarshalInputVerifyEmailRequest, ec.unmarshalInputVerifyOTPRequest, ec.unmarshalInputWebhookRequest, ) first := true - switch rc.Operation.Operation { + switch opCtx.Operation.Operation { case ast.Query: return func(ctx context.Context) *graphql.Response { var response graphql.Response @@ -2329,7 +2278,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { if first { first = false ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) - data = ec._Query(ctx, rc.Operation.SelectionSet) + data = ec._Query(ctx, opCtx.Operation.SelectionSet) } else { if atomic.LoadInt32(&ec.pendingDeferred) > 0 { result := <-ec.deferredResults @@ -2359,7 +2308,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { } first = false ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) - data := ec._Mutation(ctx, rc.Operation.SelectionSet) + data := ec._Mutation(ctx, opCtx.Operation.SelectionSet) var buf bytes.Buffer data.MarshalGQL(&buf) @@ -2467,7 +2416,7 @@ type User { gender: String birthdate: String phone_number: String - phone_number_verified: Boolean + phone_number_verified: Boolean! picture: String roles: [String!]! created_at: Int64 @@ -2499,15 +2448,6 @@ type VerificationRequests { verification_requests: [VerificationRequest!]! } -type SMSVerificationRequests { - id: ID! - code: String! - code_expires_at: Int64! - phone_number: String! - created_at: Int64! - updated_at: Int64 -} - type Error { message: String! reason: String! @@ -2687,7 +2627,7 @@ type EmailTemplates { email_templates: [EmailTemplate!]! } -input UpdateEnvInput { +input UpdateEnvRequest { ACCESS_TOKEN_EXPIRY_TIME: String ADMIN_SECRET: String CUSTOM_ACCESS_TOKEN_SCRIPT: String @@ -2752,16 +2692,16 @@ input UpdateEnvInput { DISABLE_TOTP_LOGIN: Boolean } -input AdminLoginInput { +input AdminLoginRequest { admin_secret: String! } -input AdminSignupInput { +input AdminSignupRequest { admin_secret: String! } # Deprecated from v1.2.0 -input MobileSignUpInput { +input MobileSignUpRequest { email: String given_name: String family_name: String @@ -2784,7 +2724,7 @@ input MobileSignUpInput { app_data: Map } -input SignUpInput { +input SignUpRequest { email: String given_name: String family_name: String @@ -2807,7 +2747,7 @@ input SignUpInput { app_data: Map } -input LoginInput { +input LoginRequest { email: String phone_number: String password: String! @@ -2820,7 +2760,7 @@ input LoginInput { } # Deprecated from v1.2.0 -input MobileLoginInput { +input MobileLoginRequest { phone_number: String! password: String! roles: [String!] @@ -2831,7 +2771,7 @@ input MobileLoginInput { state: String } -input VerifyEmailInput { +input VerifyEmailRequest { token: String! # state is used for authorization code grant flow # it is used to get code for an on-going auth process during login @@ -2839,7 +2779,7 @@ input VerifyEmailInput { state: String } -input ResendVerifyEmailInput { +input ResendVerifyEmailRequest { email: String! identifier: String! # state is used for authorization code grant flow @@ -2848,7 +2788,7 @@ input ResendVerifyEmailInput { state: String } -input UpdateProfileInput { +input UpdateProfileRequest { old_password: String new_password: String confirm_new_password: String @@ -2865,7 +2805,7 @@ input UpdateProfileInput { app_data: Map } -input UpdateUserInput { +input UpdateUserRequest { id: ID! email: String email_verified: Boolean @@ -2883,14 +2823,14 @@ input UpdateUserInput { app_data: Map } -input ForgotPasswordInput { +input ForgotPasswordRequest { email: String phone_number: String state: String redirect_uri: String } -input ResetPasswordInput { +input ResetPasswordRequest { token: String otp: String phone_number: String @@ -2898,11 +2838,11 @@ input ResetPasswordInput { confirm_password: String! } -input DeleteUserInput { +input DeleteUserRequest { email: String! } -input MagicLinkLoginInput { +input MagicLinkLoginRequest { email: String! roles: [String!] scope: [String!] @@ -2910,50 +2850,50 @@ input MagicLinkLoginInput { redirect_uri: String } -input SessionQueryInput { +input SessionQueryRequest { roles: [String!] scope: [String!] } -input PaginationInput { +input PaginationRequest { limit: Int64 page: Int64 } -input PaginatedInput { - pagination: PaginationInput +input PaginatedRequest { + pagination: PaginationRequest } -input OAuthRevokeInput { +input OAuthRevokeRequest { refresh_token: String! } -input InviteMemberInput { +input InviteMemberRequest { emails: [String!]! redirect_uri: String } -input UpdateAccessInput { +input UpdateAccessRequest { user_id: String! } -input ValidateJWTTokenInput { +input ValidateJWTTokenRequest { token_type: String! token: String! roles: [String!] } -input ValidateSessionInput { +input ValidateSessionRequest { cookie: String! roles: [String!] } -input GenerateJWTKeysInput { +input GenerateJWTKeysRequest { type: String! } input ListWebhookLogRequest { - pagination: PaginationInput + pagination: PaginationRequest webhook_id: String } @@ -3035,34 +2975,37 @@ input GetUserRequest { } type Mutation { - signup(params: SignUpInput!): AuthResponse! + signup(params: SignUpRequest!): AuthResponse! # Deprecated from v1.2.0 - mobile_signup(params: MobileSignUpInput): AuthResponse! - login(params: LoginInput!): AuthResponse! + mobile_signup(params: MobileSignUpRequest): AuthResponse! + login(params: LoginRequest!): AuthResponse! # Deprecated from v1.2.0 - mobile_login(params: MobileLoginInput!): AuthResponse! - magic_link_login(params: MagicLinkLoginInput!): Response! + mobile_login(params: MobileLoginRequest!): AuthResponse! + magic_link_login(params: MagicLinkLoginRequest!): Response! logout: Response! - update_profile(params: UpdateProfileInput!): Response! - verify_email(params: VerifyEmailInput!): AuthResponse! - resend_verify_email(params: ResendVerifyEmailInput!): Response! - forgot_password(params: ForgotPasswordInput!): ForgotPasswordResponse! - reset_password(params: ResetPasswordInput!): Response! - revoke(params: OAuthRevokeInput!): Response! + update_profile(params: UpdateProfileRequest!): Response! + verify_email(params: VerifyEmailRequest!): AuthResponse! + resend_verify_email(params: ResendVerifyEmailRequest!): Response! + forgot_password(params: ForgotPasswordRequest!): ForgotPasswordResponse! + reset_password(params: ResetPasswordRequest!): Response! + revoke(params: OAuthRevokeRequest!): Response! verify_otp(params: VerifyOTPRequest!): AuthResponse! resend_otp(params: ResendOTPRequest!): Response! deactivate_account: Response! # admin only apis - _delete_user(params: DeleteUserInput!): Response! - _update_user(params: UpdateUserInput!): User! - _admin_signup(params: AdminSignupInput!): Response! - _admin_login(params: AdminLoginInput!): Response! + _delete_user(params: DeleteUserRequest!): Response! + _update_user(params: UpdateUserRequest!): User! + # deprecated from v2.0.0 + _admin_signup(params: AdminSignupRequest!): Response! + _admin_login(params: AdminLoginRequest!): Response! _admin_logout: Response! - _update_env(params: UpdateEnvInput!): Response! - _invite_members(params: InviteMemberInput!): InviteMembersResponse! - _revoke_access(param: UpdateAccessInput!): Response! - _enable_access(param: UpdateAccessInput!): Response! - _generate_jwt_keys(params: GenerateJWTKeysInput!): GenerateJWTKeysResponse! + # Deprecated from v2.0.0 + _update_env(params: UpdateEnvRequest!): Response! + _invite_members(params: InviteMemberRequest!): InviteMembersResponse! + _revoke_access(param: UpdateAccessRequest!): Response! + _enable_access(param: UpdateAccessRequest!): Response! + # Deprecated from v2.0.0 + _generate_jwt_keys(params: GenerateJWTKeysRequest!): GenerateJWTKeysResponse! _add_webhook(params: AddWebhookRequest!): Response! _update_webhook(params: UpdateWebhookRequest!): Response! _delete_webhook(params: WebhookRequest!): Response! @@ -3074,20 +3017,21 @@ type Mutation { type Query { meta: Meta! - session(params: SessionQueryInput): AuthResponse! + session(params: SessionQueryRequest): AuthResponse! profile: User! - validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse! - validate_session(params: ValidateSessionInput): ValidateSessionResponse! + validate_jwt_token(params: ValidateJWTTokenRequest!): ValidateJWTTokenResponse! + validate_session(params: ValidateSessionRequest): ValidateSessionResponse! # admin only apis - _users(params: PaginatedInput): Users! + _users(params: PaginatedRequest): Users! _user(params: GetUserRequest!): User! - _verification_requests(params: PaginatedInput): VerificationRequests! + _verification_requests(params: PaginatedRequest): VerificationRequests! _admin_session: Response! + # Deprecated from v2.0.0 _env: Env! _webhook(params: WebhookRequest!): Webhook! - _webhooks(params: PaginatedInput): Webhooks! + _webhooks(params: PaginatedRequest): Webhooks! _webhook_logs(params: ListWebhookLogRequest): WebhookLogs! - _email_templates(params: PaginatedInput): EmailTemplates! + _email_templates(params: PaginatedRequest): EmailTemplates! } `, BuiltIn: false}, } @@ -3097,774 +3041,1250 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...) // region ***************************** args.gotpl ***************************** -func (ec *executionContext) field_Mutation__add_email_template_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__add_email_template_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.AddEmailTemplateRequest - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNAddEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAddEmailTemplateRequest(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__add_email_template_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__add_email_template_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.AddEmailTemplateRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.AddEmailTemplateRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation__add_webhook_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.AddWebhookRequest + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNAddWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAddWebhookRequest(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNAddEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAddEmailTemplateRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.AddEmailTemplateRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation__admin_login_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__add_webhook_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.AdminLoginInput - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNAdminLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminLoginInput(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__add_webhook_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__add_webhook_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.AddWebhookRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.AddWebhookRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation__admin_signup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.AdminSignupInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNAdminSignupInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminSignupInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNAddWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAddWebhookRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.AddWebhookRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation__delete_email_template_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__admin_login_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.DeleteEmailTemplateRequest - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNDeleteEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐDeleteEmailTemplateRequest(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__admin_login_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__admin_login_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.AdminLoginRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.AdminLoginRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation__delete_user_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.DeleteUserInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNDeleteUserInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐDeleteUserInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNAdminLoginRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAdminLoginRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.AdminLoginRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation__delete_webhook_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__admin_signup_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.WebhookRequest - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookRequest(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__admin_signup_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__admin_signup_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.AdminSignupRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.AdminSignupRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation__enable_access_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.UpdateAccessInput - if tmp, ok := rawArgs["param"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("param")) - arg0, err = ec.unmarshalNUpdateAccessInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateAccessInput(ctx, tmp) - if err != nil { - return nil, err - } + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalNAdminSignupRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAdminSignupRequest(ctx, tmp) } - args["param"] = arg0 - return args, nil + + var zeroVal model.AdminSignupRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation__generate_jwt_keys_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__delete_email_template_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.GenerateJWTKeysInput - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNGenerateJWTKeysInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐGenerateJWTKeysInput(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__delete_email_template_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__delete_email_template_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.DeleteEmailTemplateRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.DeleteEmailTemplateRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation__invite_members_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.InviteMemberInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNInviteMemberInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐInviteMemberInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNDeleteEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐDeleteEmailTemplateRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.DeleteEmailTemplateRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation__revoke_access_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__delete_user_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.UpdateAccessInput - if tmp, ok := rawArgs["param"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("param")) - arg0, err = ec.unmarshalNUpdateAccessInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateAccessInput(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__delete_user_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } - args["param"] = arg0 + args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__delete_user_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.DeleteUserRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.DeleteUserRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation__test_endpoint_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.TestEndpointRequest + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNTestEndpointRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐTestEndpointRequest(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNDeleteUserRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐDeleteUserRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.DeleteUserRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation__update_email_template_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__delete_webhook_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.UpdateEmailTemplateRequest - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNUpdateEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateEmailTemplateRequest(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__delete_webhook_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__delete_webhook_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.WebhookRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.WebhookRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation__update_env_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.UpdateEnvInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNUpdateEnvInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateEnvInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.WebhookRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation__update_user_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__enable_access_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.UpdateUserInput - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNUpdateUserInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateUserInput(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__enable_access_argsParam(ctx, rawArgs) + if err != nil { + return nil, err } - args["params"] = arg0 + args["param"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__enable_access_argsParam( + ctx context.Context, + rawArgs map[string]any, +) (model.UpdateAccessRequest, error) { + if _, ok := rawArgs["param"]; !ok { + var zeroVal model.UpdateAccessRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation__update_webhook_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.UpdateWebhookRequest - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNUpdateWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateWebhookRequest(ctx, tmp) - if err != nil { - return nil, err - } + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("param")) + if tmp, ok := rawArgs["param"]; ok { + return ec.unmarshalNUpdateAccessRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateAccessRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.UpdateAccessRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation_forgot_password_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__generate_jwt_keys_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.ForgotPasswordInput - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNForgotPasswordInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐForgotPasswordInput(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__generate_jwt_keys_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__generate_jwt_keys_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.GenerateJWTKeysRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.GenerateJWTKeysRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation_login_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.LoginInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐLoginInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNGenerateJWTKeysRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐGenerateJWTKeysRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.GenerateJWTKeysRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation_magic_link_login_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__invite_members_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.MagicLinkLoginInput - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNMagicLinkLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMagicLinkLoginInput(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__invite_members_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__invite_members_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.InviteMemberRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.InviteMemberRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation_mobile_login_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.MobileLoginInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNMobileLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileLoginInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNInviteMemberRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐInviteMemberRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.InviteMemberRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation_mobile_signup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__revoke_access_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 *model.MobileSignUpInput - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalOMobileSignUpInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileSignUpInput(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__revoke_access_argsParam(ctx, rawArgs) + if err != nil { + return nil, err } - args["params"] = arg0 + args["param"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__revoke_access_argsParam( + ctx context.Context, + rawArgs map[string]any, +) (model.UpdateAccessRequest, error) { + if _, ok := rawArgs["param"]; !ok { + var zeroVal model.UpdateAccessRequest + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("param")) + if tmp, ok := rawArgs["param"]; ok { + return ec.unmarshalNUpdateAccessRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateAccessRequest(ctx, tmp) + } + + var zeroVal model.UpdateAccessRequest + return zeroVal, nil +} -func (ec *executionContext) field_Mutation_resend_otp_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__test_endpoint_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.ResendOTPRequest - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNResendOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResendOTPRequest(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__test_endpoint_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__test_endpoint_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.TestEndpointRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.TestEndpointRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation_resend_verify_email_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.ResendVerifyEmailInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNResendVerifyEmailInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResendVerifyEmailInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNTestEndpointRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐTestEndpointRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.TestEndpointRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation_reset_password_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__update_email_template_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.ResetPasswordInput - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNResetPasswordInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResetPasswordInput(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__update_email_template_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__update_email_template_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.UpdateEmailTemplateRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.UpdateEmailTemplateRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation_revoke_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.OAuthRevokeInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNOAuthRevokeInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐOAuthRevokeInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNUpdateEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateEmailTemplateRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.UpdateEmailTemplateRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation_signup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__update_env_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.SignUpInput - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNSignUpInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐSignUpInput(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__update_env_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__update_env_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.UpdateEnvRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.UpdateEnvRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation_update_profile_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.UpdateProfileInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNUpdateProfileInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateProfileInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNUpdateEnvRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateEnvRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.UpdateEnvRequest + return zeroVal, nil } -func (ec *executionContext) field_Mutation_verify_email_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__update_user_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.VerifyEmailInput - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNVerifyEmailInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerifyEmailInput(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__update_user_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__update_user_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.UpdateUserRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.UpdateUserRequest + return zeroVal, nil + } -func (ec *executionContext) field_Mutation_verify_otp_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.VerifyOTPRequest + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNVerifyOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerifyOTPRequest(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNUpdateUserRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateUserRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.UpdateUserRequest + return zeroVal, nil } -func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation__update_webhook_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["name"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation__update_webhook_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } - args["name"] = arg0 + args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation__update_webhook_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.UpdateWebhookRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.UpdateWebhookRequest + return zeroVal, nil + } -func (ec *executionContext) field_Query__email_templates_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 *model.PaginatedInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalOPaginatedInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginatedInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNUpdateWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateWebhookRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.UpdateWebhookRequest + return zeroVal, nil } -func (ec *executionContext) field_Query__user_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_forgot_password_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 model.GetUserRequest - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNGetUserRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐGetUserRequest(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation_forgot_password_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_forgot_password_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.ForgotPasswordRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.ForgotPasswordRequest + return zeroVal, nil + } -func (ec *executionContext) field_Query__users_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 *model.PaginatedInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalOPaginatedInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginatedInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNForgotPasswordRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐForgotPasswordRequest(ctx, tmp) } - args["params"] = arg0 - return args, nil + + var zeroVal model.ForgotPasswordRequest + return zeroVal, nil } -func (ec *executionContext) field_Query__verification_requests_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_login_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 *model.PaginatedInput - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalOPaginatedInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginatedInput(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation_login_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_login_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.LoginRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.LoginRequest + return zeroVal, nil + } -func (ec *executionContext) field_Query__webhook_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.WebhookRequest + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookRequest(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNLoginRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐLoginRequest(ctx, tmp) + } + + var zeroVal model.LoginRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_magic_link_login_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_magic_link_login_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_magic_link_login_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.MagicLinkLoginRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.MagicLinkLoginRequest + return zeroVal, nil + } -func (ec *executionContext) field_Query__webhook_logs_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 *model.ListWebhookLogRequest + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalOListWebhookLogRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐListWebhookLogRequest(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNMagicLinkLoginRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐMagicLinkLoginRequest(ctx, tmp) + } + + var zeroVal model.MagicLinkLoginRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_mobile_login_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_mobile_login_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_mobile_login_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.MobileLoginRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.MobileLoginRequest + return zeroVal, nil + } -func (ec *executionContext) field_Query__webhooks_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 *model.PaginatedInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalOPaginatedInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginatedInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNMobileLoginRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐMobileLoginRequest(ctx, tmp) + } + + var zeroVal model.MobileLoginRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_mobile_signup_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_mobile_signup_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_mobile_signup_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (*model.MobileSignUpRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal *model.MobileSignUpRequest + return zeroVal, nil + } -func (ec *executionContext) field_Query_session_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 *model.SessionQueryInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalOSessionQueryInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐSessionQueryInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalOMobileSignUpRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐMobileSignUpRequest(ctx, tmp) + } + + var zeroVal *model.MobileSignUpRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_resend_otp_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_resend_otp_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_resend_otp_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.ResendOTPRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.ResendOTPRequest + return zeroVal, nil + } -func (ec *executionContext) field_Query_validate_jwt_token_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.ValidateJWTTokenInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNValidateJWTTokenInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateJWTTokenInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNResendOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResendOTPRequest(ctx, tmp) + } + + var zeroVal model.ResendOTPRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_resend_verify_email_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_resend_verify_email_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_resend_verify_email_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.ResendVerifyEmailRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.ResendVerifyEmailRequest + return zeroVal, nil + } -func (ec *executionContext) field_Query_validate_session_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 *model.ValidateSessionInput + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalOValidateSessionInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateSessionInput(ctx, tmp) - if err != nil { - return nil, err - } + return ec.unmarshalNResendVerifyEmailRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResendVerifyEmailRequest(ctx, tmp) + } + + var zeroVal model.ResendVerifyEmailRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_reset_password_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_reset_password_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_reset_password_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.ResetPasswordRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.ResetPasswordRequest + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalNResetPasswordRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResetPasswordRequest(ctx, tmp) + } + + var zeroVal model.ResetPasswordRequest + return zeroVal, nil +} -func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_revoke_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation_revoke_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } - args["includeDeprecated"] = arg0 + args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_revoke_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.OAuthRevokeRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.OAuthRevokeRequest + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalNOAuthRevokeRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐOAuthRevokeRequest(ctx, tmp) + } + + var zeroVal model.OAuthRevokeRequest + return zeroVal, nil +} -func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_signup_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } + args := map[string]any{} + arg0, err := ec.field_Mutation_signup_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } - args["includeDeprecated"] = arg0 + args["params"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_signup_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.SignUpRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.SignUpRequest + return zeroVal, nil + } -// endregion ***************************** args.gotpl ***************************** + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalNSignUpRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐSignUpRequest(ctx, tmp) + } -// region ************************** directives.gotpl ************************** + var zeroVal model.SignUpRequest + return zeroVal, nil +} -// endregion ************************** directives.gotpl ************************** +func (ec *executionContext) field_Mutation_update_profile_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_update_profile_argsParams(ctx, rawArgs) + if err != nil { + return nil, err + } + args["params"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_update_profile_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.UpdateProfileRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.UpdateProfileRequest + return zeroVal, nil + } -// region **************************** field.gotpl ***************************** + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalNUpdateProfileRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateProfileRequest(ctx, tmp) + } -func (ec *executionContext) _AuthResponse_message(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_AuthResponse_message(ctx, field) + var zeroVal model.UpdateProfileRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_verify_email_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_verify_email_argsParams(ctx, rawArgs) if err != nil { - return graphql.Null + return nil, err } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Message, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null + args["params"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_verify_email_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.VerifyEmailRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.VerifyEmailRequest + return zeroVal, nil } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalNVerifyEmailRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐVerifyEmailRequest(ctx, tmp) } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) + + var zeroVal model.VerifyEmailRequest + return zeroVal, nil } -func (ec *executionContext) fieldContext_AuthResponse_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "AuthResponse", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, +func (ec *executionContext) field_Mutation_verify_otp_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_verify_otp_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } - return fc, nil + args["params"] = arg0 + return args, nil } +func (ec *executionContext) field_Mutation_verify_otp_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.VerifyOTPRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.VerifyOTPRequest + return zeroVal, nil + } -func (ec *executionContext) _AuthResponse_should_show_email_otp_screen(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field) - if err != nil { - return graphql.Null + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalNVerifyOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐVerifyOTPRequest(ctx, tmp) } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.ShouldShowEmailOtpScreen, nil - }) + + var zeroVal model.VerifyOTPRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query___type_argsName(ctx, rawArgs) if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null + return nil, err } - res := resTmp.(*bool) - fc.Result = res - return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) + args["name"] = arg0 + return args, nil } +func (ec *executionContext) field_Query___type_argsName( + ctx context.Context, + rawArgs map[string]any, +) (string, error) { + if _, ok := rawArgs["name"]; !ok { + var zeroVal string + return zeroVal, nil + } -func (ec *executionContext) fieldContext_AuthResponse_should_show_email_otp_screen(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "AuthResponse", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + if tmp, ok := rawArgs["name"]; ok { + return ec.unmarshalNString2string(ctx, tmp) } - return fc, nil + + var zeroVal string + return zeroVal, nil } -func (ec *executionContext) _AuthResponse_should_show_mobile_otp_screen(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field) +func (ec *executionContext) field_Query__email_templates_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query__email_templates_argsParams(ctx, rawArgs) if err != nil { - return graphql.Null + return nil, err } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.ShouldShowMobileOtpScreen, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null + args["params"] = arg0 + return args, nil +} +func (ec *executionContext) field_Query__email_templates_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (*model.PaginatedRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal *model.PaginatedRequest + return zeroVal, nil } - if resTmp == nil { - return graphql.Null + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalOPaginatedRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPaginatedRequest(ctx, tmp) } - res := resTmp.(*bool) - fc.Result = res - return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) + + var zeroVal *model.PaginatedRequest + return zeroVal, nil } -func (ec *executionContext) fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "AuthResponse", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, +func (ec *executionContext) field_Query__user_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query__user_argsParams(ctx, rawArgs) + if err != nil { + return nil, err } - return fc, nil + args["params"] = arg0 + return args, nil } +func (ec *executionContext) field_Query__user_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.GetUserRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.GetUserRequest + return zeroVal, nil + } -func (ec *executionContext) _AuthResponse_should_show_totp_screen(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_AuthResponse_should_show_totp_screen(ctx, field) - if err != nil { - return graphql.Null + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalNGetUserRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐGetUserRequest(ctx, tmp) + } + + var zeroVal model.GetUserRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Query__users_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query__users_argsParams(ctx, rawArgs) + if err != nil { + return nil, err + } + args["params"] = arg0 + return args, nil +} +func (ec *executionContext) field_Query__users_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (*model.PaginatedRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal *model.PaginatedRequest + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalOPaginatedRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPaginatedRequest(ctx, tmp) + } + + var zeroVal *model.PaginatedRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Query__verification_requests_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query__verification_requests_argsParams(ctx, rawArgs) + if err != nil { + return nil, err + } + args["params"] = arg0 + return args, nil +} +func (ec *executionContext) field_Query__verification_requests_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (*model.PaginatedRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal *model.PaginatedRequest + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalOPaginatedRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPaginatedRequest(ctx, tmp) + } + + var zeroVal *model.PaginatedRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Query__webhook_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query__webhook_argsParams(ctx, rawArgs) + if err != nil { + return nil, err + } + args["params"] = arg0 + return args, nil +} +func (ec *executionContext) field_Query__webhook_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.WebhookRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.WebhookRequest + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalNWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookRequest(ctx, tmp) + } + + var zeroVal model.WebhookRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Query__webhook_logs_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query__webhook_logs_argsParams(ctx, rawArgs) + if err != nil { + return nil, err + } + args["params"] = arg0 + return args, nil +} +func (ec *executionContext) field_Query__webhook_logs_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (*model.ListWebhookLogRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal *model.ListWebhookLogRequest + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalOListWebhookLogRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐListWebhookLogRequest(ctx, tmp) + } + + var zeroVal *model.ListWebhookLogRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Query__webhooks_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query__webhooks_argsParams(ctx, rawArgs) + if err != nil { + return nil, err + } + args["params"] = arg0 + return args, nil +} +func (ec *executionContext) field_Query__webhooks_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (*model.PaginatedRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal *model.PaginatedRequest + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalOPaginatedRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPaginatedRequest(ctx, tmp) + } + + var zeroVal *model.PaginatedRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Query_session_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query_session_argsParams(ctx, rawArgs) + if err != nil { + return nil, err + } + args["params"] = arg0 + return args, nil +} +func (ec *executionContext) field_Query_session_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (*model.SessionQueryRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal *model.SessionQueryRequest + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalOSessionQueryRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐSessionQueryRequest(ctx, tmp) + } + + var zeroVal *model.SessionQueryRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Query_validate_jwt_token_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query_validate_jwt_token_argsParams(ctx, rawArgs) + if err != nil { + return nil, err + } + args["params"] = arg0 + return args, nil +} +func (ec *executionContext) field_Query_validate_jwt_token_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (model.ValidateJWTTokenRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal model.ValidateJWTTokenRequest + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalNValidateJWTTokenRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐValidateJWTTokenRequest(ctx, tmp) + } + + var zeroVal model.ValidateJWTTokenRequest + return zeroVal, nil +} + +func (ec *executionContext) field_Query_validate_session_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query_validate_session_argsParams(ctx, rawArgs) + if err != nil { + return nil, err + } + args["params"] = arg0 + return args, nil +} +func (ec *executionContext) field_Query_validate_session_argsParams( + ctx context.Context, + rawArgs map[string]any, +) (*model.ValidateSessionRequest, error) { + if _, ok := rawArgs["params"]; !ok { + var zeroVal *model.ValidateSessionRequest + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + if tmp, ok := rawArgs["params"]; ok { + return ec.unmarshalOValidateSessionRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐValidateSessionRequest(ctx, tmp) + } + + var zeroVal *model.ValidateSessionRequest + return zeroVal, nil +} + +func (ec *executionContext) field___Directive_args_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field___Directive_args_argsIncludeDeprecated(ctx, rawArgs) + if err != nil { + return nil, err + } + args["includeDeprecated"] = arg0 + return args, nil +} +func (ec *executionContext) field___Directive_args_argsIncludeDeprecated( + ctx context.Context, + rawArgs map[string]any, +) (*bool, error) { + if _, ok := rawArgs["includeDeprecated"]; !ok { + var zeroVal *bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + if tmp, ok := rawArgs["includeDeprecated"]; ok { + return ec.unmarshalOBoolean2ᚖbool(ctx, tmp) + } + + var zeroVal *bool + return zeroVal, nil +} + +func (ec *executionContext) field___Field_args_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field___Field_args_argsIncludeDeprecated(ctx, rawArgs) + if err != nil { + return nil, err + } + args["includeDeprecated"] = arg0 + return args, nil +} +func (ec *executionContext) field___Field_args_argsIncludeDeprecated( + ctx context.Context, + rawArgs map[string]any, +) (*bool, error) { + if _, ok := rawArgs["includeDeprecated"]; !ok { + var zeroVal *bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + if tmp, ok := rawArgs["includeDeprecated"]; ok { + return ec.unmarshalOBoolean2ᚖbool(ctx, tmp) + } + + var zeroVal *bool + return zeroVal, nil +} + +func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field___Type_enumValues_argsIncludeDeprecated(ctx, rawArgs) + if err != nil { + return nil, err + } + args["includeDeprecated"] = arg0 + return args, nil +} +func (ec *executionContext) field___Type_enumValues_argsIncludeDeprecated( + ctx context.Context, + rawArgs map[string]any, +) (bool, error) { + if _, ok := rawArgs["includeDeprecated"]; !ok { + var zeroVal bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + if tmp, ok := rawArgs["includeDeprecated"]; ok { + return ec.unmarshalOBoolean2bool(ctx, tmp) + } + + var zeroVal bool + return zeroVal, nil +} + +func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field___Type_fields_argsIncludeDeprecated(ctx, rawArgs) + if err != nil { + return nil, err + } + args["includeDeprecated"] = arg0 + return args, nil +} +func (ec *executionContext) field___Type_fields_argsIncludeDeprecated( + ctx context.Context, + rawArgs map[string]any, +) (bool, error) { + if _, ok := rawArgs["includeDeprecated"]; !ok { + var zeroVal bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + if tmp, ok := rawArgs["includeDeprecated"]; ok { + return ec.unmarshalOBoolean2bool(ctx, tmp) + } + + var zeroVal bool + return zeroVal, nil +} + +// endregion ***************************** args.gotpl ***************************** + +// region ************************** directives.gotpl ************************** + +// endregion ************************** directives.gotpl ************************** + +// region **************************** field.gotpl ***************************** + +func (ec *executionContext) _AuthResponse_message(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AuthResponse_message(ctx, field) + if err != nil { + return graphql.Null } ctx = graphql.WithFieldContext(ctx, fc) defer func() { @@ -3873,37 +4293,40 @@ func (ec *executionContext) _AuthResponse_should_show_totp_screen(ctx context.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.ShouldShowTotpScreen, nil + return obj.Message, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(*bool) + res := resTmp.(string) fc.Result = res - return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) + return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_AuthResponse_should_show_totp_screen(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_AuthResponse_message(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "AuthResponse", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") + return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } -func (ec *executionContext) _AuthResponse_access_token(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_AuthResponse_access_token(ctx, field) +func (ec *executionContext) _AuthResponse_should_show_email_otp_screen(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AuthResponse_should_show_email_otp_screen(ctx, field) if err != nil { return graphql.Null } @@ -3914,9 +4337,9 @@ func (ec *executionContext) _AuthResponse_access_token(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.AccessToken, nil + return obj.ShouldShowEmailOtpScreen, nil }) if err != nil { ec.Error(ctx, err) @@ -3925,26 +4348,26 @@ func (ec *executionContext) _AuthResponse_access_token(ctx context.Context, fiel if resTmp == nil { return graphql.Null } - res := resTmp.(*string) + res := resTmp.(*bool) fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_AuthResponse_access_token(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_AuthResponse_should_show_email_otp_screen(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "AuthResponse", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } -func (ec *executionContext) _AuthResponse_id_token(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_AuthResponse_id_token(ctx, field) +func (ec *executionContext) _AuthResponse_should_show_mobile_otp_screen(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AuthResponse_should_show_mobile_otp_screen(ctx, field) if err != nil { return graphql.Null } @@ -3955,9 +4378,9 @@ func (ec *executionContext) _AuthResponse_id_token(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.IDToken, nil + return obj.ShouldShowMobileOtpScreen, nil }) if err != nil { ec.Error(ctx, err) @@ -3966,26 +4389,26 @@ func (ec *executionContext) _AuthResponse_id_token(ctx context.Context, field gr if resTmp == nil { return graphql.Null } - res := resTmp.(*string) + res := resTmp.(*bool) fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_AuthResponse_id_token(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_AuthResponse_should_show_mobile_otp_screen(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "AuthResponse", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } -func (ec *executionContext) _AuthResponse_refresh_token(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_AuthResponse_refresh_token(ctx, field) +func (ec *executionContext) _AuthResponse_should_show_totp_screen(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AuthResponse_should_show_totp_screen(ctx, field) if err != nil { return graphql.Null } @@ -3996,9 +4419,9 @@ func (ec *executionContext) _AuthResponse_refresh_token(ctx context.Context, fie ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.RefreshToken, nil + return obj.ShouldShowTotpScreen, nil }) if err != nil { ec.Error(ctx, err) @@ -4007,26 +4430,26 @@ func (ec *executionContext) _AuthResponse_refresh_token(ctx context.Context, fie if resTmp == nil { return graphql.Null } - res := resTmp.(*string) + res := resTmp.(*bool) fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_AuthResponse_refresh_token(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_AuthResponse_should_show_totp_screen(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "AuthResponse", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } -func (ec *executionContext) _AuthResponse_expires_in(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_AuthResponse_expires_in(ctx, field) +func (ec *executionContext) _AuthResponse_access_token(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AuthResponse_access_token(ctx, field) if err != nil { return graphql.Null } @@ -4037,9 +4460,9 @@ func (ec *executionContext) _AuthResponse_expires_in(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.ExpiresIn, nil + return obj.AccessToken, nil }) if err != nil { ec.Error(ctx, err) @@ -4048,26 +4471,26 @@ func (ec *executionContext) _AuthResponse_expires_in(ctx context.Context, field if resTmp == nil { return graphql.Null } - res := resTmp.(*int64) + res := resTmp.(*string) fc.Result = res - return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_AuthResponse_expires_in(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_AuthResponse_access_token(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "AuthResponse", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int64 does not have child fields") + return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } -func (ec *executionContext) _AuthResponse_user(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_AuthResponse_user(ctx, field) +func (ec *executionContext) _AuthResponse_id_token(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AuthResponse_id_token(ctx, field) if err != nil { return graphql.Null } @@ -4078,9 +4501,9 @@ func (ec *executionContext) _AuthResponse_user(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.User, nil + return obj.IDToken, nil }) if err != nil { ec.Error(ctx, err) @@ -4089,34 +4512,157 @@ func (ec *executionContext) _AuthResponse_user(ctx context.Context, field graphq if resTmp == nil { return graphql.Null } - res := resTmp.(*model.User) + res := resTmp.(*string) fc.Result = res - return ec.marshalOUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_AuthResponse_user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_AuthResponse_id_token(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "AuthResponse", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "email": - return ec.fieldContext_User_email(ctx, field) - case "email_verified": - return ec.fieldContext_User_email_verified(ctx, field) - case "signup_methods": - return ec.fieldContext_User_signup_methods(ctx, field) - case "given_name": - return ec.fieldContext_User_given_name(ctx, field) - case "family_name": - return ec.fieldContext_User_family_name(ctx, field) - case "middle_name": - return ec.fieldContext_User_middle_name(ctx, field) - case "nickname": + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _AuthResponse_refresh_token(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AuthResponse_refresh_token(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.RefreshToken, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_AuthResponse_refresh_token(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "AuthResponse", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _AuthResponse_expires_in(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AuthResponse_expires_in(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.ExpiresIn, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_AuthResponse_expires_in(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "AuthResponse", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int64 does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _AuthResponse_user(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AuthResponse_user(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.User, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*model.User) + fc.Result = res + return ec.marshalOUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_AuthResponse_user(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "AuthResponse", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "email": + return ec.fieldContext_User_email(ctx, field) + case "email_verified": + return ec.fieldContext_User_email_verified(ctx, field) + case "signup_methods": + return ec.fieldContext_User_signup_methods(ctx, field) + case "given_name": + return ec.fieldContext_User_given_name(ctx, field) + case "family_name": + return ec.fieldContext_User_family_name(ctx, field) + case "middle_name": + return ec.fieldContext_User_middle_name(ctx, field) + case "nickname": return ec.fieldContext_User_nickname(ctx, field) case "preferred_username": return ec.fieldContext_User_preferred_username(ctx, field) @@ -4161,7 +4707,7 @@ func (ec *executionContext) _AuthResponse_authenticator_scanner_image(ctx contex ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AuthenticatorScannerImage, nil }) @@ -4177,7 +4723,7 @@ func (ec *executionContext) _AuthResponse_authenticator_scanner_image(ctx contex return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_AuthResponse_authenticator_scanner_image(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_AuthResponse_authenticator_scanner_image(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "AuthResponse", Field: field, @@ -4202,7 +4748,7 @@ func (ec *executionContext) _AuthResponse_authenticator_secret(ctx context.Conte ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AuthenticatorSecret, nil }) @@ -4218,7 +4764,7 @@ func (ec *executionContext) _AuthResponse_authenticator_secret(ctx context.Conte return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_AuthResponse_authenticator_secret(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_AuthResponse_authenticator_secret(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "AuthResponse", Field: field, @@ -4243,7 +4789,7 @@ func (ec *executionContext) _AuthResponse_authenticator_recovery_codes(ctx conte ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AuthenticatorRecoveryCodes, nil }) @@ -4259,7 +4805,7 @@ func (ec *executionContext) _AuthResponse_authenticator_recovery_codes(ctx conte return ec.marshalOString2ᚕᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_AuthResponse_authenticator_recovery_codes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_AuthResponse_authenticator_recovery_codes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "AuthResponse", Field: field, @@ -4284,7 +4830,7 @@ func (ec *executionContext) _EmailTemplate_id(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ID, nil }) @@ -4303,7 +4849,7 @@ func (ec *executionContext) _EmailTemplate_id(ctx context.Context, field graphql return ec.marshalNID2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EmailTemplate_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EmailTemplate_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EmailTemplate", Field: field, @@ -4328,7 +4874,7 @@ func (ec *executionContext) _EmailTemplate_event_name(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.EventName, nil }) @@ -4347,7 +4893,7 @@ func (ec *executionContext) _EmailTemplate_event_name(ctx context.Context, field return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EmailTemplate_event_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EmailTemplate_event_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EmailTemplate", Field: field, @@ -4372,7 +4918,7 @@ func (ec *executionContext) _EmailTemplate_template(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Template, nil }) @@ -4391,7 +4937,7 @@ func (ec *executionContext) _EmailTemplate_template(ctx context.Context, field g return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EmailTemplate_template(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EmailTemplate_template(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EmailTemplate", Field: field, @@ -4416,7 +4962,7 @@ func (ec *executionContext) _EmailTemplate_design(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Design, nil }) @@ -4435,7 +4981,7 @@ func (ec *executionContext) _EmailTemplate_design(ctx context.Context, field gra return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EmailTemplate_design(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EmailTemplate_design(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EmailTemplate", Field: field, @@ -4460,7 +5006,7 @@ func (ec *executionContext) _EmailTemplate_subject(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Subject, nil }) @@ -4479,7 +5025,7 @@ func (ec *executionContext) _EmailTemplate_subject(ctx context.Context, field gr return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EmailTemplate_subject(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EmailTemplate_subject(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EmailTemplate", Field: field, @@ -4504,7 +5050,7 @@ func (ec *executionContext) _EmailTemplate_created_at(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.CreatedAt, nil }) @@ -4520,7 +5066,7 @@ func (ec *executionContext) _EmailTemplate_created_at(ctx context.Context, field return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EmailTemplate_created_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EmailTemplate_created_at(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EmailTemplate", Field: field, @@ -4545,7 +5091,7 @@ func (ec *executionContext) _EmailTemplate_updated_at(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.UpdatedAt, nil }) @@ -4561,7 +5107,7 @@ func (ec *executionContext) _EmailTemplate_updated_at(ctx context.Context, field return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EmailTemplate_updated_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EmailTemplate_updated_at(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EmailTemplate", Field: field, @@ -4586,7 +5132,7 @@ func (ec *executionContext) _EmailTemplates_pagination(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Pagination, nil }) @@ -4602,10 +5148,10 @@ func (ec *executionContext) _EmailTemplates_pagination(ctx context.Context, fiel } res := resTmp.(*model.Pagination) fc.Result = res - return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res) + return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EmailTemplates_pagination(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EmailTemplates_pagination(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EmailTemplates", Field: field, @@ -4640,7 +5186,7 @@ func (ec *executionContext) _EmailTemplates_email_templates(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.EmailTemplates, nil }) @@ -4656,10 +5202,10 @@ func (ec *executionContext) _EmailTemplates_email_templates(ctx context.Context, } res := resTmp.([]*model.EmailTemplate) fc.Result = res - return ec.marshalNEmailTemplate2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐEmailTemplateᚄ(ctx, field.Selections, res) + return ec.marshalNEmailTemplate2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐEmailTemplateᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EmailTemplates_email_templates(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EmailTemplates_email_templates(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EmailTemplates", Field: field, @@ -4700,7 +5246,7 @@ func (ec *executionContext) _Env_ACCESS_TOKEN_EXPIRY_TIME(ctx context.Context, f ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AccessTokenExpiryTime, nil }) @@ -4716,7 +5262,7 @@ func (ec *executionContext) _Env_ACCESS_TOKEN_EXPIRY_TIME(ctx context.Context, f return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_ACCESS_TOKEN_EXPIRY_TIME(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_ACCESS_TOKEN_EXPIRY_TIME(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -4741,7 +5287,7 @@ func (ec *executionContext) _Env_ADMIN_SECRET(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AdminSecret, nil }) @@ -4757,7 +5303,7 @@ func (ec *executionContext) _Env_ADMIN_SECRET(ctx context.Context, field graphql return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_ADMIN_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_ADMIN_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -4782,7 +5328,7 @@ func (ec *executionContext) _Env_DATABASE_NAME(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DatabaseName, nil }) @@ -4798,7 +5344,7 @@ func (ec *executionContext) _Env_DATABASE_NAME(ctx context.Context, field graphq return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DATABASE_NAME(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DATABASE_NAME(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -4823,7 +5369,7 @@ func (ec *executionContext) _Env_DATABASE_URL(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DatabaseURL, nil }) @@ -4839,7 +5385,7 @@ func (ec *executionContext) _Env_DATABASE_URL(ctx context.Context, field graphql return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DATABASE_URL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DATABASE_URL(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -4864,7 +5410,7 @@ func (ec *executionContext) _Env_DATABASE_TYPE(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DatabaseType, nil }) @@ -4880,7 +5426,7 @@ func (ec *executionContext) _Env_DATABASE_TYPE(ctx context.Context, field graphq return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DATABASE_TYPE(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DATABASE_TYPE(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -4905,7 +5451,7 @@ func (ec *executionContext) _Env_DATABASE_USERNAME(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DatabaseUsername, nil }) @@ -4921,7 +5467,7 @@ func (ec *executionContext) _Env_DATABASE_USERNAME(ctx context.Context, field gr return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DATABASE_USERNAME(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DATABASE_USERNAME(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -4946,7 +5492,7 @@ func (ec *executionContext) _Env_DATABASE_PASSWORD(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DatabasePassword, nil }) @@ -4962,7 +5508,7 @@ func (ec *executionContext) _Env_DATABASE_PASSWORD(ctx context.Context, field gr return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DATABASE_PASSWORD(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DATABASE_PASSWORD(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -4987,7 +5533,7 @@ func (ec *executionContext) _Env_DATABASE_HOST(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DatabaseHost, nil }) @@ -5003,7 +5549,7 @@ func (ec *executionContext) _Env_DATABASE_HOST(ctx context.Context, field graphq return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DATABASE_HOST(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DATABASE_HOST(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5028,7 +5574,7 @@ func (ec *executionContext) _Env_DATABASE_PORT(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DatabasePort, nil }) @@ -5044,7 +5590,7 @@ func (ec *executionContext) _Env_DATABASE_PORT(ctx context.Context, field graphq return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DATABASE_PORT(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DATABASE_PORT(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5069,7 +5615,7 @@ func (ec *executionContext) _Env_CLIENT_ID(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ClientID, nil }) @@ -5088,7 +5634,7 @@ func (ec *executionContext) _Env_CLIENT_ID(ctx context.Context, field graphql.Co return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_CLIENT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5113,7 +5659,7 @@ func (ec *executionContext) _Env_CLIENT_SECRET(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ClientSecret, nil }) @@ -5132,7 +5678,7 @@ func (ec *executionContext) _Env_CLIENT_SECRET(ctx context.Context, field graphq return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_CLIENT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5157,7 +5703,7 @@ func (ec *executionContext) _Env_CUSTOM_ACCESS_TOKEN_SCRIPT(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.CustomAccessTokenScript, nil }) @@ -5173,7 +5719,7 @@ func (ec *executionContext) _Env_CUSTOM_ACCESS_TOKEN_SCRIPT(ctx context.Context, return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_CUSTOM_ACCESS_TOKEN_SCRIPT(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_CUSTOM_ACCESS_TOKEN_SCRIPT(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5198,7 +5744,7 @@ func (ec *executionContext) _Env_SMTP_HOST(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SMTPHost, nil }) @@ -5214,7 +5760,7 @@ func (ec *executionContext) _Env_SMTP_HOST(ctx context.Context, field graphql.Co return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_SMTP_HOST(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_SMTP_HOST(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5239,7 +5785,7 @@ func (ec *executionContext) _Env_SMTP_PORT(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SMTPPort, nil }) @@ -5255,7 +5801,7 @@ func (ec *executionContext) _Env_SMTP_PORT(ctx context.Context, field graphql.Co return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_SMTP_PORT(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_SMTP_PORT(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5280,7 +5826,7 @@ func (ec *executionContext) _Env_SMTP_USERNAME(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SMTPUsername, nil }) @@ -5296,7 +5842,7 @@ func (ec *executionContext) _Env_SMTP_USERNAME(ctx context.Context, field graphq return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_SMTP_USERNAME(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_SMTP_USERNAME(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5321,7 +5867,7 @@ func (ec *executionContext) _Env_SMTP_PASSWORD(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SMTPPassword, nil }) @@ -5337,7 +5883,7 @@ func (ec *executionContext) _Env_SMTP_PASSWORD(ctx context.Context, field graphq return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_SMTP_PASSWORD(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_SMTP_PASSWORD(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5362,7 +5908,7 @@ func (ec *executionContext) _Env_SMTP_LOCAL_NAME(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SMTPLocalName, nil }) @@ -5378,7 +5924,7 @@ func (ec *executionContext) _Env_SMTP_LOCAL_NAME(ctx context.Context, field grap return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_SMTP_LOCAL_NAME(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_SMTP_LOCAL_NAME(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5403,7 +5949,7 @@ func (ec *executionContext) _Env_SENDER_EMAIL(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SenderEmail, nil }) @@ -5419,7 +5965,7 @@ func (ec *executionContext) _Env_SENDER_EMAIL(ctx context.Context, field graphql return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_SENDER_EMAIL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_SENDER_EMAIL(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5444,7 +5990,7 @@ func (ec *executionContext) _Env_SENDER_NAME(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SenderName, nil }) @@ -5460,7 +6006,7 @@ func (ec *executionContext) _Env_SENDER_NAME(ctx context.Context, field graphql. return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_SENDER_NAME(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_SENDER_NAME(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5485,7 +6031,7 @@ func (ec *executionContext) _Env_JWT_TYPE(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.JwtType, nil }) @@ -5501,7 +6047,7 @@ func (ec *executionContext) _Env_JWT_TYPE(ctx context.Context, field graphql.Col return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_JWT_TYPE(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_JWT_TYPE(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5526,7 +6072,7 @@ func (ec *executionContext) _Env_JWT_SECRET(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.JwtSecret, nil }) @@ -5542,7 +6088,7 @@ func (ec *executionContext) _Env_JWT_SECRET(ctx context.Context, field graphql.C return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_JWT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_JWT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5567,7 +6113,7 @@ func (ec *executionContext) _Env_JWT_PRIVATE_KEY(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.JwtPrivateKey, nil }) @@ -5583,7 +6129,7 @@ func (ec *executionContext) _Env_JWT_PRIVATE_KEY(ctx context.Context, field grap return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_JWT_PRIVATE_KEY(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_JWT_PRIVATE_KEY(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5608,7 +6154,7 @@ func (ec *executionContext) _Env_JWT_PUBLIC_KEY(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.JwtPublicKey, nil }) @@ -5624,7 +6170,7 @@ func (ec *executionContext) _Env_JWT_PUBLIC_KEY(ctx context.Context, field graph return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_JWT_PUBLIC_KEY(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_JWT_PUBLIC_KEY(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5649,7 +6195,7 @@ func (ec *executionContext) _Env_ALLOWED_ORIGINS(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AllowedOrigins, nil }) @@ -5665,7 +6211,7 @@ func (ec *executionContext) _Env_ALLOWED_ORIGINS(ctx context.Context, field grap return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_ALLOWED_ORIGINS(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_ALLOWED_ORIGINS(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5690,7 +6236,7 @@ func (ec *executionContext) _Env_APP_URL(ctx context.Context, field graphql.Coll ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AppURL, nil }) @@ -5706,7 +6252,7 @@ func (ec *executionContext) _Env_APP_URL(ctx context.Context, field graphql.Coll return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_APP_URL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_APP_URL(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5731,7 +6277,7 @@ func (ec *executionContext) _Env_REDIS_URL(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.RedisURL, nil }) @@ -5747,7 +6293,7 @@ func (ec *executionContext) _Env_REDIS_URL(ctx context.Context, field graphql.Co return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_REDIS_URL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_REDIS_URL(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5772,7 +6318,7 @@ func (ec *executionContext) _Env_RESET_PASSWORD_URL(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ResetPasswordURL, nil }) @@ -5788,7 +6334,7 @@ func (ec *executionContext) _Env_RESET_PASSWORD_URL(ctx context.Context, field g return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_RESET_PASSWORD_URL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_RESET_PASSWORD_URL(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5813,7 +6359,7 @@ func (ec *executionContext) _Env_DISABLE_EMAIL_VERIFICATION(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisableEmailVerification, nil }) @@ -5832,7 +6378,7 @@ func (ec *executionContext) _Env_DISABLE_EMAIL_VERIFICATION(ctx context.Context, return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_EMAIL_VERIFICATION(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_EMAIL_VERIFICATION(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5857,7 +6403,7 @@ func (ec *executionContext) _Env_DISABLE_BASIC_AUTHENTICATION(ctx context.Contex ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisableBasicAuthentication, nil }) @@ -5876,7 +6422,7 @@ func (ec *executionContext) _Env_DISABLE_BASIC_AUTHENTICATION(ctx context.Contex return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_BASIC_AUTHENTICATION(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_BASIC_AUTHENTICATION(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5901,7 +6447,7 @@ func (ec *executionContext) _Env_DISABLE_MOBILE_BASIC_AUTHENTICATION(ctx context ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisableMobileBasicAuthentication, nil }) @@ -5920,7 +6466,7 @@ func (ec *executionContext) _Env_DISABLE_MOBILE_BASIC_AUTHENTICATION(ctx context return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_MOBILE_BASIC_AUTHENTICATION(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_MOBILE_BASIC_AUTHENTICATION(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5945,7 +6491,7 @@ func (ec *executionContext) _Env_DISABLE_MAGIC_LINK_LOGIN(ctx context.Context, f ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisableMagicLinkLogin, nil }) @@ -5964,7 +6510,7 @@ func (ec *executionContext) _Env_DISABLE_MAGIC_LINK_LOGIN(ctx context.Context, f return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_MAGIC_LINK_LOGIN(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_MAGIC_LINK_LOGIN(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -5989,7 +6535,7 @@ func (ec *executionContext) _Env_DISABLE_LOGIN_PAGE(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisableLoginPage, nil }) @@ -6008,7 +6554,7 @@ func (ec *executionContext) _Env_DISABLE_LOGIN_PAGE(ctx context.Context, field g return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_LOGIN_PAGE(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_LOGIN_PAGE(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6033,7 +6579,7 @@ func (ec *executionContext) _Env_DISABLE_SIGN_UP(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisableSignUp, nil }) @@ -6052,7 +6598,7 @@ func (ec *executionContext) _Env_DISABLE_SIGN_UP(ctx context.Context, field grap return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_SIGN_UP(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_SIGN_UP(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6077,7 +6623,7 @@ func (ec *executionContext) _Env_DISABLE_REDIS_FOR_ENV(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisableRedisForEnv, nil }) @@ -6096,7 +6642,7 @@ func (ec *executionContext) _Env_DISABLE_REDIS_FOR_ENV(ctx context.Context, fiel return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_REDIS_FOR_ENV(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_REDIS_FOR_ENV(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6121,7 +6667,7 @@ func (ec *executionContext) _Env_DISABLE_STRONG_PASSWORD(ctx context.Context, fi ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisableStrongPassword, nil }) @@ -6140,7 +6686,7 @@ func (ec *executionContext) _Env_DISABLE_STRONG_PASSWORD(ctx context.Context, fi return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_STRONG_PASSWORD(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_STRONG_PASSWORD(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6165,7 +6711,7 @@ func (ec *executionContext) _Env_DISABLE_MULTI_FACTOR_AUTHENTICATION(ctx context ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisableMultiFactorAuthentication, nil }) @@ -6184,7 +6730,7 @@ func (ec *executionContext) _Env_DISABLE_MULTI_FACTOR_AUTHENTICATION(ctx context return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_MULTI_FACTOR_AUTHENTICATION(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_MULTI_FACTOR_AUTHENTICATION(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6209,7 +6755,7 @@ func (ec *executionContext) _Env_ENFORCE_MULTI_FACTOR_AUTHENTICATION(ctx context ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.EnforceMultiFactorAuthentication, nil }) @@ -6228,7 +6774,7 @@ func (ec *executionContext) _Env_ENFORCE_MULTI_FACTOR_AUTHENTICATION(ctx context return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_ENFORCE_MULTI_FACTOR_AUTHENTICATION(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_ENFORCE_MULTI_FACTOR_AUTHENTICATION(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6253,7 +6799,7 @@ func (ec *executionContext) _Env_ROLES(ctx context.Context, field graphql.Collec ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Roles, nil }) @@ -6269,7 +6815,7 @@ func (ec *executionContext) _Env_ROLES(ctx context.Context, field graphql.Collec return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_ROLES(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_ROLES(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6294,7 +6840,7 @@ func (ec *executionContext) _Env_PROTECTED_ROLES(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ProtectedRoles, nil }) @@ -6310,7 +6856,7 @@ func (ec *executionContext) _Env_PROTECTED_ROLES(ctx context.Context, field grap return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_PROTECTED_ROLES(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_PROTECTED_ROLES(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6335,7 +6881,7 @@ func (ec *executionContext) _Env_DEFAULT_ROLES(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DefaultRoles, nil }) @@ -6351,7 +6897,7 @@ func (ec *executionContext) _Env_DEFAULT_ROLES(ctx context.Context, field graphq return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DEFAULT_ROLES(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DEFAULT_ROLES(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6376,7 +6922,7 @@ func (ec *executionContext) _Env_JWT_ROLE_CLAIM(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.JwtRoleClaim, nil }) @@ -6392,7 +6938,7 @@ func (ec *executionContext) _Env_JWT_ROLE_CLAIM(ctx context.Context, field graph return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_JWT_ROLE_CLAIM(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_JWT_ROLE_CLAIM(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6417,7 +6963,7 @@ func (ec *executionContext) _Env_GOOGLE_CLIENT_ID(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.GoogleClientID, nil }) @@ -6433,7 +6979,7 @@ func (ec *executionContext) _Env_GOOGLE_CLIENT_ID(ctx context.Context, field gra return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_GOOGLE_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_GOOGLE_CLIENT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6458,7 +7004,7 @@ func (ec *executionContext) _Env_GOOGLE_CLIENT_SECRET(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.GoogleClientSecret, nil }) @@ -6474,7 +7020,7 @@ func (ec *executionContext) _Env_GOOGLE_CLIENT_SECRET(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_GOOGLE_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_GOOGLE_CLIENT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6499,7 +7045,7 @@ func (ec *executionContext) _Env_GITHUB_CLIENT_ID(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.GithubClientID, nil }) @@ -6515,7 +7061,7 @@ func (ec *executionContext) _Env_GITHUB_CLIENT_ID(ctx context.Context, field gra return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_GITHUB_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_GITHUB_CLIENT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6540,7 +7086,7 @@ func (ec *executionContext) _Env_GITHUB_CLIENT_SECRET(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.GithubClientSecret, nil }) @@ -6556,7 +7102,7 @@ func (ec *executionContext) _Env_GITHUB_CLIENT_SECRET(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_GITHUB_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_GITHUB_CLIENT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6581,7 +7127,7 @@ func (ec *executionContext) _Env_FACEBOOK_CLIENT_ID(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.FacebookClientID, nil }) @@ -6597,7 +7143,7 @@ func (ec *executionContext) _Env_FACEBOOK_CLIENT_ID(ctx context.Context, field g return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_FACEBOOK_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_FACEBOOK_CLIENT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6622,7 +7168,7 @@ func (ec *executionContext) _Env_FACEBOOK_CLIENT_SECRET(ctx context.Context, fie ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.FacebookClientSecret, nil }) @@ -6638,7 +7184,7 @@ func (ec *executionContext) _Env_FACEBOOK_CLIENT_SECRET(ctx context.Context, fie return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_FACEBOOK_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_FACEBOOK_CLIENT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6663,7 +7209,7 @@ func (ec *executionContext) _Env_LINKEDIN_CLIENT_ID(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.LinkedinClientID, nil }) @@ -6679,7 +7225,7 @@ func (ec *executionContext) _Env_LINKEDIN_CLIENT_ID(ctx context.Context, field g return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_LINKEDIN_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_LINKEDIN_CLIENT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6704,7 +7250,7 @@ func (ec *executionContext) _Env_LINKEDIN_CLIENT_SECRET(ctx context.Context, fie ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.LinkedinClientSecret, nil }) @@ -6720,7 +7266,7 @@ func (ec *executionContext) _Env_LINKEDIN_CLIENT_SECRET(ctx context.Context, fie return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_LINKEDIN_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_LINKEDIN_CLIENT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6745,7 +7291,7 @@ func (ec *executionContext) _Env_APPLE_CLIENT_ID(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AppleClientID, nil }) @@ -6761,7 +7307,7 @@ func (ec *executionContext) _Env_APPLE_CLIENT_ID(ctx context.Context, field grap return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_APPLE_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_APPLE_CLIENT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6786,7 +7332,7 @@ func (ec *executionContext) _Env_APPLE_CLIENT_SECRET(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AppleClientSecret, nil }) @@ -6802,7 +7348,7 @@ func (ec *executionContext) _Env_APPLE_CLIENT_SECRET(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_APPLE_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_APPLE_CLIENT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6827,7 +7373,7 @@ func (ec *executionContext) _Env_DISCORD_CLIENT_ID(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DiscordClientID, nil }) @@ -6843,7 +7389,7 @@ func (ec *executionContext) _Env_DISCORD_CLIENT_ID(ctx context.Context, field gr return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISCORD_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISCORD_CLIENT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6868,7 +7414,7 @@ func (ec *executionContext) _Env_DISCORD_CLIENT_SECRET(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DiscordClientSecret, nil }) @@ -6884,7 +7430,7 @@ func (ec *executionContext) _Env_DISCORD_CLIENT_SECRET(ctx context.Context, fiel return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISCORD_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISCORD_CLIENT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6909,7 +7455,7 @@ func (ec *executionContext) _Env_TWITTER_CLIENT_ID(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.TwitterClientID, nil }) @@ -6925,7 +7471,7 @@ func (ec *executionContext) _Env_TWITTER_CLIENT_ID(ctx context.Context, field gr return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_TWITTER_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_TWITTER_CLIENT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6950,7 +7496,7 @@ func (ec *executionContext) _Env_TWITTER_CLIENT_SECRET(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.TwitterClientSecret, nil }) @@ -6966,7 +7512,7 @@ func (ec *executionContext) _Env_TWITTER_CLIENT_SECRET(ctx context.Context, fiel return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_TWITTER_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_TWITTER_CLIENT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -6991,7 +7537,7 @@ func (ec *executionContext) _Env_MICROSOFT_CLIENT_ID(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.MicrosoftClientID, nil }) @@ -7007,7 +7553,7 @@ func (ec *executionContext) _Env_MICROSOFT_CLIENT_ID(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_MICROSOFT_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_MICROSOFT_CLIENT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7032,7 +7578,7 @@ func (ec *executionContext) _Env_MICROSOFT_CLIENT_SECRET(ctx context.Context, fi ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.MicrosoftClientSecret, nil }) @@ -7048,7 +7594,7 @@ func (ec *executionContext) _Env_MICROSOFT_CLIENT_SECRET(ctx context.Context, fi return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_MICROSOFT_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_MICROSOFT_CLIENT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7073,7 +7619,7 @@ func (ec *executionContext) _Env_MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID(ctx contex ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.MicrosoftActiveDirectoryTenantID, nil }) @@ -7089,7 +7635,7 @@ func (ec *executionContext) _Env_MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID(ctx contex return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7114,7 +7660,7 @@ func (ec *executionContext) _Env_TWITCH_CLIENT_ID(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.TwitchClientID, nil }) @@ -7130,7 +7676,7 @@ func (ec *executionContext) _Env_TWITCH_CLIENT_ID(ctx context.Context, field gra return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_TWITCH_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_TWITCH_CLIENT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7155,7 +7701,7 @@ func (ec *executionContext) _Env_TWITCH_CLIENT_SECRET(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.TwitchClientSecret, nil }) @@ -7171,7 +7717,7 @@ func (ec *executionContext) _Env_TWITCH_CLIENT_SECRET(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_TWITCH_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_TWITCH_CLIENT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7196,7 +7742,7 @@ func (ec *executionContext) _Env_ROBLOX_CLIENT_ID(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.RobloxClientID, nil }) @@ -7212,7 +7758,7 @@ func (ec *executionContext) _Env_ROBLOX_CLIENT_ID(ctx context.Context, field gra return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_ROBLOX_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_ROBLOX_CLIENT_ID(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7237,7 +7783,7 @@ func (ec *executionContext) _Env_ROBLOX_CLIENT_SECRET(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.RobloxClientSecret, nil }) @@ -7253,7 +7799,7 @@ func (ec *executionContext) _Env_ROBLOX_CLIENT_SECRET(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_ROBLOX_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_ROBLOX_CLIENT_SECRET(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7278,7 +7824,7 @@ func (ec *executionContext) _Env_ORGANIZATION_NAME(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.OrganizationName, nil }) @@ -7294,7 +7840,7 @@ func (ec *executionContext) _Env_ORGANIZATION_NAME(ctx context.Context, field gr return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_ORGANIZATION_NAME(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_ORGANIZATION_NAME(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7319,7 +7865,7 @@ func (ec *executionContext) _Env_ORGANIZATION_LOGO(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.OrganizationLogo, nil }) @@ -7335,7 +7881,7 @@ func (ec *executionContext) _Env_ORGANIZATION_LOGO(ctx context.Context, field gr return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_ORGANIZATION_LOGO(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_ORGANIZATION_LOGO(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7360,7 +7906,7 @@ func (ec *executionContext) _Env_APP_COOKIE_SECURE(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AppCookieSecure, nil }) @@ -7379,7 +7925,7 @@ func (ec *executionContext) _Env_APP_COOKIE_SECURE(ctx context.Context, field gr return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_APP_COOKIE_SECURE(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_APP_COOKIE_SECURE(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7404,7 +7950,7 @@ func (ec *executionContext) _Env_ADMIN_COOKIE_SECURE(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AdminCookieSecure, nil }) @@ -7423,7 +7969,7 @@ func (ec *executionContext) _Env_ADMIN_COOKIE_SECURE(ctx context.Context, field return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_ADMIN_COOKIE_SECURE(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_ADMIN_COOKIE_SECURE(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7448,7 +7994,7 @@ func (ec *executionContext) _Env_DEFAULT_AUTHORIZE_RESPONSE_TYPE(ctx context.Con ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DefaultAuthorizeResponseType, nil }) @@ -7464,7 +8010,7 @@ func (ec *executionContext) _Env_DEFAULT_AUTHORIZE_RESPONSE_TYPE(ctx context.Con return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DEFAULT_AUTHORIZE_RESPONSE_TYPE(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DEFAULT_AUTHORIZE_RESPONSE_TYPE(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7489,7 +8035,7 @@ func (ec *executionContext) _Env_DEFAULT_AUTHORIZE_RESPONSE_MODE(ctx context.Con ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DefaultAuthorizeResponseMode, nil }) @@ -7505,7 +8051,7 @@ func (ec *executionContext) _Env_DEFAULT_AUTHORIZE_RESPONSE_MODE(ctx context.Con return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DEFAULT_AUTHORIZE_RESPONSE_MODE(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DEFAULT_AUTHORIZE_RESPONSE_MODE(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7530,7 +8076,7 @@ func (ec *executionContext) _Env_DISABLE_PLAYGROUND(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisablePlayground, nil }) @@ -7549,7 +8095,7 @@ func (ec *executionContext) _Env_DISABLE_PLAYGROUND(ctx context.Context, field g return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_PLAYGROUND(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_PLAYGROUND(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7574,7 +8120,7 @@ func (ec *executionContext) _Env_DISABLE_MAIL_OTP_LOGIN(ctx context.Context, fie ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisableMailOtpLogin, nil }) @@ -7593,7 +8139,7 @@ func (ec *executionContext) _Env_DISABLE_MAIL_OTP_LOGIN(ctx context.Context, fie return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_MAIL_OTP_LOGIN(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_MAIL_OTP_LOGIN(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7618,7 +8164,7 @@ func (ec *executionContext) _Env_DISABLE_TOTP_LOGIN(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DisableTotpLogin, nil }) @@ -7637,7 +8183,7 @@ func (ec *executionContext) _Env_DISABLE_TOTP_LOGIN(ctx context.Context, field g return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Env_DISABLE_TOTP_LOGIN(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Env_DISABLE_TOTP_LOGIN(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Env", Field: field, @@ -7662,7 +8208,7 @@ func (ec *executionContext) _Error_message(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Message, nil }) @@ -7681,7 +8227,7 @@ func (ec *executionContext) _Error_message(ctx context.Context, field graphql.Co return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Error_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Error_message(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Error", Field: field, @@ -7706,7 +8252,7 @@ func (ec *executionContext) _Error_reason(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Reason, nil }) @@ -7725,7 +8271,7 @@ func (ec *executionContext) _Error_reason(ctx context.Context, field graphql.Col return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Error_reason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Error_reason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Error", Field: field, @@ -7750,7 +8296,7 @@ func (ec *executionContext) _ForgotPasswordResponse_message(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Message, nil }) @@ -7769,7 +8315,7 @@ func (ec *executionContext) _ForgotPasswordResponse_message(ctx context.Context, return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ForgotPasswordResponse_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ForgotPasswordResponse_message(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ForgotPasswordResponse", Field: field, @@ -7794,7 +8340,7 @@ func (ec *executionContext) _ForgotPasswordResponse_should_show_mobile_otp_scree ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ShouldShowMobileOtpScreen, nil }) @@ -7810,7 +8356,7 @@ func (ec *executionContext) _ForgotPasswordResponse_should_show_mobile_otp_scree return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ForgotPasswordResponse_should_show_mobile_otp_screen(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ForgotPasswordResponse_should_show_mobile_otp_screen(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ForgotPasswordResponse", Field: field, @@ -7835,7 +8381,7 @@ func (ec *executionContext) _GenerateJWTKeysResponse_secret(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Secret, nil }) @@ -7851,7 +8397,7 @@ func (ec *executionContext) _GenerateJWTKeysResponse_secret(ctx context.Context, return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GenerateJWTKeysResponse_secret(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GenerateJWTKeysResponse_secret(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GenerateJWTKeysResponse", Field: field, @@ -7876,7 +8422,7 @@ func (ec *executionContext) _GenerateJWTKeysResponse_public_key(ctx context.Cont ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.PublicKey, nil }) @@ -7892,7 +8438,7 @@ func (ec *executionContext) _GenerateJWTKeysResponse_public_key(ctx context.Cont return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GenerateJWTKeysResponse_public_key(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GenerateJWTKeysResponse_public_key(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GenerateJWTKeysResponse", Field: field, @@ -7917,7 +8463,7 @@ func (ec *executionContext) _GenerateJWTKeysResponse_private_key(ctx context.Con ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.PrivateKey, nil }) @@ -7933,7 +8479,7 @@ func (ec *executionContext) _GenerateJWTKeysResponse_private_key(ctx context.Con return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GenerateJWTKeysResponse_private_key(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GenerateJWTKeysResponse_private_key(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GenerateJWTKeysResponse", Field: field, @@ -7958,7 +8504,7 @@ func (ec *executionContext) _InviteMembersResponse_message(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Message, nil }) @@ -7977,7 +8523,7 @@ func (ec *executionContext) _InviteMembersResponse_message(ctx context.Context, return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_InviteMembersResponse_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_InviteMembersResponse_message(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "InviteMembersResponse", Field: field, @@ -8002,7 +8548,7 @@ func (ec *executionContext) _InviteMembersResponse_Users(ctx context.Context, fi ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Users, nil }) @@ -8018,10 +8564,10 @@ func (ec *executionContext) _InviteMembersResponse_Users(ctx context.Context, fi } res := resTmp.([]*model.User) fc.Result = res - return ec.marshalNUser2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUserᚄ(ctx, field.Selections, res) + return ec.marshalNUser2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUserᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_InviteMembersResponse_Users(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_InviteMembersResponse_Users(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "InviteMembersResponse", Field: field, @@ -8088,7 +8634,7 @@ func (ec *executionContext) _Meta_version(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Version, nil }) @@ -8107,7 +8653,7 @@ func (ec *executionContext) _Meta_version(ctx context.Context, field graphql.Col return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_version(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_version(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8132,7 +8678,7 @@ func (ec *executionContext) _Meta_client_id(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ClientID, nil }) @@ -8151,7 +8697,7 @@ func (ec *executionContext) _Meta_client_id(ctx context.Context, field graphql.C return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_client_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_client_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8176,7 +8722,7 @@ func (ec *executionContext) _Meta_is_google_login_enabled(ctx context.Context, f ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsGoogleLoginEnabled, nil }) @@ -8195,7 +8741,7 @@ func (ec *executionContext) _Meta_is_google_login_enabled(ctx context.Context, f return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_google_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_google_login_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8220,7 +8766,7 @@ func (ec *executionContext) _Meta_is_facebook_login_enabled(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsFacebookLoginEnabled, nil }) @@ -8239,7 +8785,7 @@ func (ec *executionContext) _Meta_is_facebook_login_enabled(ctx context.Context, return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_facebook_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_facebook_login_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8264,7 +8810,7 @@ func (ec *executionContext) _Meta_is_github_login_enabled(ctx context.Context, f ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsGithubLoginEnabled, nil }) @@ -8283,7 +8829,7 @@ func (ec *executionContext) _Meta_is_github_login_enabled(ctx context.Context, f return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_github_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_github_login_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8308,7 +8854,7 @@ func (ec *executionContext) _Meta_is_linkedin_login_enabled(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsLinkedinLoginEnabled, nil }) @@ -8327,7 +8873,7 @@ func (ec *executionContext) _Meta_is_linkedin_login_enabled(ctx context.Context, return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_linkedin_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_linkedin_login_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8352,7 +8898,7 @@ func (ec *executionContext) _Meta_is_apple_login_enabled(ctx context.Context, fi ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsAppleLoginEnabled, nil }) @@ -8371,7 +8917,7 @@ func (ec *executionContext) _Meta_is_apple_login_enabled(ctx context.Context, fi return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_apple_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_apple_login_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8396,7 +8942,7 @@ func (ec *executionContext) _Meta_is_discord_login_enabled(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsDiscordLoginEnabled, nil }) @@ -8415,7 +8961,7 @@ func (ec *executionContext) _Meta_is_discord_login_enabled(ctx context.Context, return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_discord_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_discord_login_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8440,7 +8986,7 @@ func (ec *executionContext) _Meta_is_twitter_login_enabled(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsTwitterLoginEnabled, nil }) @@ -8459,7 +9005,7 @@ func (ec *executionContext) _Meta_is_twitter_login_enabled(ctx context.Context, return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_twitter_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_twitter_login_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8484,7 +9030,7 @@ func (ec *executionContext) _Meta_is_microsoft_login_enabled(ctx context.Context ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsMicrosoftLoginEnabled, nil }) @@ -8503,7 +9049,7 @@ func (ec *executionContext) _Meta_is_microsoft_login_enabled(ctx context.Context return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_microsoft_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_microsoft_login_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8528,7 +9074,7 @@ func (ec *executionContext) _Meta_is_twitch_login_enabled(ctx context.Context, f ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsTwitchLoginEnabled, nil }) @@ -8547,7 +9093,7 @@ func (ec *executionContext) _Meta_is_twitch_login_enabled(ctx context.Context, f return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_twitch_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_twitch_login_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8572,7 +9118,7 @@ func (ec *executionContext) _Meta_is_roblox_login_enabled(ctx context.Context, f ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsRobloxLoginEnabled, nil }) @@ -8591,7 +9137,7 @@ func (ec *executionContext) _Meta_is_roblox_login_enabled(ctx context.Context, f return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_roblox_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_roblox_login_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8616,7 +9162,7 @@ func (ec *executionContext) _Meta_is_email_verification_enabled(ctx context.Cont ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsEmailVerificationEnabled, nil }) @@ -8635,7 +9181,7 @@ func (ec *executionContext) _Meta_is_email_verification_enabled(ctx context.Cont return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_email_verification_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_email_verification_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8660,7 +9206,7 @@ func (ec *executionContext) _Meta_is_basic_authentication_enabled(ctx context.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsBasicAuthenticationEnabled, nil }) @@ -8679,7 +9225,7 @@ func (ec *executionContext) _Meta_is_basic_authentication_enabled(ctx context.Co return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_basic_authentication_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_basic_authentication_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8704,7 +9250,7 @@ func (ec *executionContext) _Meta_is_magic_link_login_enabled(ctx context.Contex ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsMagicLinkLoginEnabled, nil }) @@ -8723,7 +9269,7 @@ func (ec *executionContext) _Meta_is_magic_link_login_enabled(ctx context.Contex return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_magic_link_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_magic_link_login_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8748,7 +9294,7 @@ func (ec *executionContext) _Meta_is_sign_up_enabled(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsSignUpEnabled, nil }) @@ -8767,7 +9313,7 @@ func (ec *executionContext) _Meta_is_sign_up_enabled(ctx context.Context, field return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_sign_up_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_sign_up_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8792,7 +9338,7 @@ func (ec *executionContext) _Meta_is_strong_password_enabled(ctx context.Context ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsStrongPasswordEnabled, nil }) @@ -8811,7 +9357,7 @@ func (ec *executionContext) _Meta_is_strong_password_enabled(ctx context.Context return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_strong_password_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_strong_password_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8836,7 +9382,7 @@ func (ec *executionContext) _Meta_is_multi_factor_auth_enabled(ctx context.Conte ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsMultiFactorAuthEnabled, nil }) @@ -8855,7 +9401,7 @@ func (ec *executionContext) _Meta_is_multi_factor_auth_enabled(ctx context.Conte return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_multi_factor_auth_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_multi_factor_auth_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8880,7 +9426,7 @@ func (ec *executionContext) _Meta_is_mobile_basic_authentication_enabled(ctx con ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsMobileBasicAuthenticationEnabled, nil }) @@ -8899,7 +9445,7 @@ func (ec *executionContext) _Meta_is_mobile_basic_authentication_enabled(ctx con return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_mobile_basic_authentication_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_mobile_basic_authentication_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8924,7 +9470,7 @@ func (ec *executionContext) _Meta_is_phone_verification_enabled(ctx context.Cont ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsPhoneVerificationEnabled, nil }) @@ -8943,7 +9489,7 @@ func (ec *executionContext) _Meta_is_phone_verification_enabled(ctx context.Cont return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Meta_is_phone_verification_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Meta_is_phone_verification_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Meta", Field: field, @@ -8968,9 +9514,9 @@ func (ec *executionContext) _Mutation_signup(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().Signup(rctx, fc.Args["params"].(model.SignUpInput)) + return ec.resolvers.Mutation().Signup(rctx, fc.Args["params"].(model.SignUpRequest)) }) if err != nil { ec.Error(ctx, err) @@ -8984,7 +9530,7 @@ func (ec *executionContext) _Mutation_signup(ctx context.Context, field graphql. } res := resTmp.(*model.AuthResponse) fc.Result = res - return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) + return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_signup(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9049,9 +9595,9 @@ func (ec *executionContext) _Mutation_mobile_signup(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().MobileSignup(rctx, fc.Args["params"].(*model.MobileSignUpInput)) + return ec.resolvers.Mutation().MobileSignup(rctx, fc.Args["params"].(*model.MobileSignUpRequest)) }) if err != nil { ec.Error(ctx, err) @@ -9065,7 +9611,7 @@ func (ec *executionContext) _Mutation_mobile_signup(ctx context.Context, field g } res := resTmp.(*model.AuthResponse) fc.Result = res - return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) + return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_mobile_signup(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9130,9 +9676,9 @@ func (ec *executionContext) _Mutation_login(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().Login(rctx, fc.Args["params"].(model.LoginInput)) + return ec.resolvers.Mutation().Login(rctx, fc.Args["params"].(model.LoginRequest)) }) if err != nil { ec.Error(ctx, err) @@ -9146,7 +9692,7 @@ func (ec *executionContext) _Mutation_login(ctx context.Context, field graphql.C } res := resTmp.(*model.AuthResponse) fc.Result = res - return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) + return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_login(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9211,9 +9757,9 @@ func (ec *executionContext) _Mutation_mobile_login(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().MobileLogin(rctx, fc.Args["params"].(model.MobileLoginInput)) + return ec.resolvers.Mutation().MobileLogin(rctx, fc.Args["params"].(model.MobileLoginRequest)) }) if err != nil { ec.Error(ctx, err) @@ -9227,7 +9773,7 @@ func (ec *executionContext) _Mutation_mobile_login(ctx context.Context, field gr } res := resTmp.(*model.AuthResponse) fc.Result = res - return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) + return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_mobile_login(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9292,9 +9838,9 @@ func (ec *executionContext) _Mutation_magic_link_login(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().MagicLinkLogin(rctx, fc.Args["params"].(model.MagicLinkLoginInput)) + return ec.resolvers.Mutation().MagicLinkLogin(rctx, fc.Args["params"].(model.MagicLinkLoginRequest)) }) if err != nil { ec.Error(ctx, err) @@ -9308,7 +9854,7 @@ func (ec *executionContext) _Mutation_magic_link_login(ctx context.Context, fiel } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_magic_link_login(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9351,7 +9897,7 @@ func (ec *executionContext) _Mutation_logout(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().Logout(rctx) }) @@ -9367,10 +9913,10 @@ func (ec *executionContext) _Mutation_logout(ctx context.Context, field graphql. } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Mutation_logout(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Mutation_logout(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, @@ -9399,9 +9945,9 @@ func (ec *executionContext) _Mutation_update_profile(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().UpdateProfile(rctx, fc.Args["params"].(model.UpdateProfileInput)) + return ec.resolvers.Mutation().UpdateProfile(rctx, fc.Args["params"].(model.UpdateProfileRequest)) }) if err != nil { ec.Error(ctx, err) @@ -9415,7 +9961,7 @@ func (ec *executionContext) _Mutation_update_profile(ctx context.Context, field } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_update_profile(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9458,9 +10004,9 @@ func (ec *executionContext) _Mutation_verify_email(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().VerifyEmail(rctx, fc.Args["params"].(model.VerifyEmailInput)) + return ec.resolvers.Mutation().VerifyEmail(rctx, fc.Args["params"].(model.VerifyEmailRequest)) }) if err != nil { ec.Error(ctx, err) @@ -9474,7 +10020,7 @@ func (ec *executionContext) _Mutation_verify_email(ctx context.Context, field gr } res := resTmp.(*model.AuthResponse) fc.Result = res - return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) + return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_verify_email(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9539,9 +10085,9 @@ func (ec *executionContext) _Mutation_resend_verify_email(ctx context.Context, f ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().ResendVerifyEmail(rctx, fc.Args["params"].(model.ResendVerifyEmailInput)) + return ec.resolvers.Mutation().ResendVerifyEmail(rctx, fc.Args["params"].(model.ResendVerifyEmailRequest)) }) if err != nil { ec.Error(ctx, err) @@ -9555,7 +10101,7 @@ func (ec *executionContext) _Mutation_resend_verify_email(ctx context.Context, f } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_resend_verify_email(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9598,9 +10144,9 @@ func (ec *executionContext) _Mutation_forgot_password(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().ForgotPassword(rctx, fc.Args["params"].(model.ForgotPasswordInput)) + return ec.resolvers.Mutation().ForgotPassword(rctx, fc.Args["params"].(model.ForgotPasswordRequest)) }) if err != nil { ec.Error(ctx, err) @@ -9614,7 +10160,7 @@ func (ec *executionContext) _Mutation_forgot_password(ctx context.Context, field } res := resTmp.(*model.ForgotPasswordResponse) fc.Result = res - return ec.marshalNForgotPasswordResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐForgotPasswordResponse(ctx, field.Selections, res) + return ec.marshalNForgotPasswordResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐForgotPasswordResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_forgot_password(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9659,9 +10205,9 @@ func (ec *executionContext) _Mutation_reset_password(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().ResetPassword(rctx, fc.Args["params"].(model.ResetPasswordInput)) + return ec.resolvers.Mutation().ResetPassword(rctx, fc.Args["params"].(model.ResetPasswordRequest)) }) if err != nil { ec.Error(ctx, err) @@ -9675,7 +10221,7 @@ func (ec *executionContext) _Mutation_reset_password(ctx context.Context, field } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_reset_password(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9718,9 +10264,9 @@ func (ec *executionContext) _Mutation_revoke(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().Revoke(rctx, fc.Args["params"].(model.OAuthRevokeInput)) + return ec.resolvers.Mutation().Revoke(rctx, fc.Args["params"].(model.OAuthRevokeRequest)) }) if err != nil { ec.Error(ctx, err) @@ -9734,7 +10280,7 @@ func (ec *executionContext) _Mutation_revoke(ctx context.Context, field graphql. } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_revoke(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9777,7 +10323,7 @@ func (ec *executionContext) _Mutation_verify_otp(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().VerifyOtp(rctx, fc.Args["params"].(model.VerifyOTPRequest)) }) @@ -9793,7 +10339,7 @@ func (ec *executionContext) _Mutation_verify_otp(ctx context.Context, field grap } res := resTmp.(*model.AuthResponse) fc.Result = res - return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) + return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_verify_otp(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9858,7 +10404,7 @@ func (ec *executionContext) _Mutation_resend_otp(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().ResendOtp(rctx, fc.Args["params"].(model.ResendOTPRequest)) }) @@ -9874,7 +10420,7 @@ func (ec *executionContext) _Mutation_resend_otp(ctx context.Context, field grap } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_resend_otp(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -9917,7 +10463,7 @@ func (ec *executionContext) _Mutation_deactivate_account(ctx context.Context, fi ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().DeactivateAccount(rctx) }) @@ -9933,10 +10479,10 @@ func (ec *executionContext) _Mutation_deactivate_account(ctx context.Context, fi } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Mutation_deactivate_account(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Mutation_deactivate_account(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, @@ -9965,9 +10511,9 @@ func (ec *executionContext) _Mutation__delete_user(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().DeleteUser(rctx, fc.Args["params"].(model.DeleteUserInput)) + return ec.resolvers.Mutation().DeleteUser(rctx, fc.Args["params"].(model.DeleteUserRequest)) }) if err != nil { ec.Error(ctx, err) @@ -9981,7 +10527,7 @@ func (ec *executionContext) _Mutation__delete_user(ctx context.Context, field gr } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__delete_user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10024,9 +10570,9 @@ func (ec *executionContext) _Mutation__update_user(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().UpdateUser(rctx, fc.Args["params"].(model.UpdateUserInput)) + return ec.resolvers.Mutation().UpdateUser(rctx, fc.Args["params"].(model.UpdateUserRequest)) }) if err != nil { ec.Error(ctx, err) @@ -10040,7 +10586,7 @@ func (ec *executionContext) _Mutation__update_user(ctx context.Context, field gr } res := resTmp.(*model.User) fc.Result = res - return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) + return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__update_user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10121,9 +10667,9 @@ func (ec *executionContext) _Mutation__admin_signup(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().AdminSignup(rctx, fc.Args["params"].(model.AdminSignupInput)) + return ec.resolvers.Mutation().AdminSignup(rctx, fc.Args["params"].(model.AdminSignupRequest)) }) if err != nil { ec.Error(ctx, err) @@ -10137,7 +10683,7 @@ func (ec *executionContext) _Mutation__admin_signup(ctx context.Context, field g } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__admin_signup(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10180,9 +10726,9 @@ func (ec *executionContext) _Mutation__admin_login(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().AdminLogin(rctx, fc.Args["params"].(model.AdminLoginInput)) + return ec.resolvers.Mutation().AdminLogin(rctx, fc.Args["params"].(model.AdminLoginRequest)) }) if err != nil { ec.Error(ctx, err) @@ -10196,7 +10742,7 @@ func (ec *executionContext) _Mutation__admin_login(ctx context.Context, field gr } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__admin_login(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10239,7 +10785,7 @@ func (ec *executionContext) _Mutation__admin_logout(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().AdminLogout(rctx) }) @@ -10255,10 +10801,10 @@ func (ec *executionContext) _Mutation__admin_logout(ctx context.Context, field g } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Mutation__admin_logout(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Mutation__admin_logout(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, @@ -10287,9 +10833,9 @@ func (ec *executionContext) _Mutation__update_env(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().UpdateEnv(rctx, fc.Args["params"].(model.UpdateEnvInput)) + return ec.resolvers.Mutation().UpdateEnv(rctx, fc.Args["params"].(model.UpdateEnvRequest)) }) if err != nil { ec.Error(ctx, err) @@ -10303,7 +10849,7 @@ func (ec *executionContext) _Mutation__update_env(ctx context.Context, field gra } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__update_env(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10346,9 +10892,9 @@ func (ec *executionContext) _Mutation__invite_members(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().InviteMembers(rctx, fc.Args["params"].(model.InviteMemberInput)) + return ec.resolvers.Mutation().InviteMembers(rctx, fc.Args["params"].(model.InviteMemberRequest)) }) if err != nil { ec.Error(ctx, err) @@ -10362,7 +10908,7 @@ func (ec *executionContext) _Mutation__invite_members(ctx context.Context, field } res := resTmp.(*model.InviteMembersResponse) fc.Result = res - return ec.marshalNInviteMembersResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐInviteMembersResponse(ctx, field.Selections, res) + return ec.marshalNInviteMembersResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐInviteMembersResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__invite_members(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10407,9 +10953,9 @@ func (ec *executionContext) _Mutation__revoke_access(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().RevokeAccess(rctx, fc.Args["param"].(model.UpdateAccessInput)) + return ec.resolvers.Mutation().RevokeAccess(rctx, fc.Args["param"].(model.UpdateAccessRequest)) }) if err != nil { ec.Error(ctx, err) @@ -10423,7 +10969,7 @@ func (ec *executionContext) _Mutation__revoke_access(ctx context.Context, field } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__revoke_access(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10466,9 +11012,9 @@ func (ec *executionContext) _Mutation__enable_access(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().EnableAccess(rctx, fc.Args["param"].(model.UpdateAccessInput)) + return ec.resolvers.Mutation().EnableAccess(rctx, fc.Args["param"].(model.UpdateAccessRequest)) }) if err != nil { ec.Error(ctx, err) @@ -10482,7 +11028,7 @@ func (ec *executionContext) _Mutation__enable_access(ctx context.Context, field } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__enable_access(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10525,9 +11071,9 @@ func (ec *executionContext) _Mutation__generate_jwt_keys(ctx context.Context, fi ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().GenerateJwtKeys(rctx, fc.Args["params"].(model.GenerateJWTKeysInput)) + return ec.resolvers.Mutation().GenerateJwtKeys(rctx, fc.Args["params"].(model.GenerateJWTKeysRequest)) }) if err != nil { ec.Error(ctx, err) @@ -10541,7 +11087,7 @@ func (ec *executionContext) _Mutation__generate_jwt_keys(ctx context.Context, fi } res := resTmp.(*model.GenerateJWTKeysResponse) fc.Result = res - return ec.marshalNGenerateJWTKeysResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐGenerateJWTKeysResponse(ctx, field.Selections, res) + return ec.marshalNGenerateJWTKeysResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐGenerateJWTKeysResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__generate_jwt_keys(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10588,7 +11134,7 @@ func (ec *executionContext) _Mutation__add_webhook(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().AddWebhook(rctx, fc.Args["params"].(model.AddWebhookRequest)) }) @@ -10604,7 +11150,7 @@ func (ec *executionContext) _Mutation__add_webhook(ctx context.Context, field gr } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__add_webhook(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10647,7 +11193,7 @@ func (ec *executionContext) _Mutation__update_webhook(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().UpdateWebhook(rctx, fc.Args["params"].(model.UpdateWebhookRequest)) }) @@ -10663,7 +11209,7 @@ func (ec *executionContext) _Mutation__update_webhook(ctx context.Context, field } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__update_webhook(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10706,7 +11252,7 @@ func (ec *executionContext) _Mutation__delete_webhook(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().DeleteWebhook(rctx, fc.Args["params"].(model.WebhookRequest)) }) @@ -10722,7 +11268,7 @@ func (ec *executionContext) _Mutation__delete_webhook(ctx context.Context, field } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__delete_webhook(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10765,7 +11311,7 @@ func (ec *executionContext) _Mutation__test_endpoint(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().TestEndpoint(rctx, fc.Args["params"].(model.TestEndpointRequest)) }) @@ -10781,7 +11327,7 @@ func (ec *executionContext) _Mutation__test_endpoint(ctx context.Context, field } res := resTmp.(*model.TestEndpointResponse) fc.Result = res - return ec.marshalNTestEndpointResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐTestEndpointResponse(ctx, field.Selections, res) + return ec.marshalNTestEndpointResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐTestEndpointResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__test_endpoint(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10826,7 +11372,7 @@ func (ec *executionContext) _Mutation__add_email_template(ctx context.Context, f ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().AddEmailTemplate(rctx, fc.Args["params"].(model.AddEmailTemplateRequest)) }) @@ -10842,7 +11388,7 @@ func (ec *executionContext) _Mutation__add_email_template(ctx context.Context, f } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__add_email_template(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10885,7 +11431,7 @@ func (ec *executionContext) _Mutation__update_email_template(ctx context.Context ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().UpdateEmailTemplate(rctx, fc.Args["params"].(model.UpdateEmailTemplateRequest)) }) @@ -10901,7 +11447,7 @@ func (ec *executionContext) _Mutation__update_email_template(ctx context.Context } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__update_email_template(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -10944,7 +11490,7 @@ func (ec *executionContext) _Mutation__delete_email_template(ctx context.Context ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().DeleteEmailTemplate(rctx, fc.Args["params"].(model.DeleteEmailTemplateRequest)) }) @@ -10960,7 +11506,7 @@ func (ec *executionContext) _Mutation__delete_email_template(ctx context.Context } res := resTmp.(*model.Response) fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation__delete_email_template(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -11003,7 +11549,7 @@ func (ec *executionContext) _Pagination_limit(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Limit, nil }) @@ -11022,7 +11568,7 @@ func (ec *executionContext) _Pagination_limit(ctx context.Context, field graphql return ec.marshalNInt642int64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Pagination_limit(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Pagination_limit(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Pagination", Field: field, @@ -11047,7 +11593,7 @@ func (ec *executionContext) _Pagination_page(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Page, nil }) @@ -11066,7 +11612,7 @@ func (ec *executionContext) _Pagination_page(ctx context.Context, field graphql. return ec.marshalNInt642int64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Pagination_page(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Pagination_page(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Pagination", Field: field, @@ -11091,7 +11637,7 @@ func (ec *executionContext) _Pagination_offset(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Offset, nil }) @@ -11110,7 +11656,7 @@ func (ec *executionContext) _Pagination_offset(ctx context.Context, field graphq return ec.marshalNInt642int64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Pagination_offset(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Pagination_offset(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Pagination", Field: field, @@ -11135,7 +11681,7 @@ func (ec *executionContext) _Pagination_total(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Total, nil }) @@ -11154,7 +11700,7 @@ func (ec *executionContext) _Pagination_total(ctx context.Context, field graphql return ec.marshalNInt642int64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Pagination_total(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Pagination_total(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Pagination", Field: field, @@ -11179,7 +11725,7 @@ func (ec *executionContext) _Query_meta(ctx context.Context, field graphql.Colle ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().Meta(rctx) }) @@ -11195,10 +11741,10 @@ func (ec *executionContext) _Query_meta(ctx context.Context, field graphql.Colle } res := resTmp.(*model.Meta) fc.Result = res - return ec.marshalNMeta2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMeta(ctx, field.Selections, res) + return ec.marshalNMeta2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐMeta(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query_meta(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_meta(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, @@ -11265,9 +11811,9 @@ func (ec *executionContext) _Query_session(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Session(rctx, fc.Args["params"].(*model.SessionQueryInput)) + return ec.resolvers.Query().Session(rctx, fc.Args["params"].(*model.SessionQueryRequest)) }) if err != nil { ec.Error(ctx, err) @@ -11281,7 +11827,7 @@ func (ec *executionContext) _Query_session(ctx context.Context, field graphql.Co } res := resTmp.(*model.AuthResponse) fc.Result = res - return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) + return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Query_session(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -11346,659 +11892,82 @@ func (ec *executionContext) _Query_profile(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Profile(rctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.User) - fc.Result = res - return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_profile(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "email": - return ec.fieldContext_User_email(ctx, field) - case "email_verified": - return ec.fieldContext_User_email_verified(ctx, field) - case "signup_methods": - return ec.fieldContext_User_signup_methods(ctx, field) - case "given_name": - return ec.fieldContext_User_given_name(ctx, field) - case "family_name": - return ec.fieldContext_User_family_name(ctx, field) - case "middle_name": - return ec.fieldContext_User_middle_name(ctx, field) - case "nickname": - return ec.fieldContext_User_nickname(ctx, field) - case "preferred_username": - return ec.fieldContext_User_preferred_username(ctx, field) - case "gender": - return ec.fieldContext_User_gender(ctx, field) - case "birthdate": - return ec.fieldContext_User_birthdate(ctx, field) - case "phone_number": - return ec.fieldContext_User_phone_number(ctx, field) - case "phone_number_verified": - return ec.fieldContext_User_phone_number_verified(ctx, field) - case "picture": - return ec.fieldContext_User_picture(ctx, field) - case "roles": - return ec.fieldContext_User_roles(ctx, field) - case "created_at": - return ec.fieldContext_User_created_at(ctx, field) - case "updated_at": - return ec.fieldContext_User_updated_at(ctx, field) - case "revoked_timestamp": - return ec.fieldContext_User_revoked_timestamp(ctx, field) - case "is_multi_factor_auth_enabled": - return ec.fieldContext_User_is_multi_factor_auth_enabled(ctx, field) - case "app_data": - return ec.fieldContext_User_app_data(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_validate_jwt_token(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_validate_jwt_token(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().ValidateJwtToken(rctx, fc.Args["params"].(model.ValidateJWTTokenInput)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.ValidateJWTTokenResponse) - fc.Result = res - return ec.marshalNValidateJWTTokenResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateJWTTokenResponse(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_validate_jwt_token(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "is_valid": - return ec.fieldContext_ValidateJWTTokenResponse_is_valid(ctx, field) - case "claims": - return ec.fieldContext_ValidateJWTTokenResponse_claims(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type ValidateJWTTokenResponse", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_validate_jwt_token_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_validate_session(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_validate_session(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().ValidateSession(rctx, fc.Args["params"].(*model.ValidateSessionInput)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.ValidateSessionResponse) - fc.Result = res - return ec.marshalNValidateSessionResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateSessionResponse(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_validate_session(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "is_valid": - return ec.fieldContext_ValidateSessionResponse_is_valid(ctx, field) - case "user": - return ec.fieldContext_ValidateSessionResponse_user(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type ValidateSessionResponse", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_validate_session_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query__users(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__users(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Users(rctx, fc.Args["params"].(*model.PaginatedInput)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.Users) - fc.Result = res - return ec.marshalNUsers2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUsers(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query__users(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "pagination": - return ec.fieldContext_Users_pagination(ctx, field) - case "users": - return ec.fieldContext_Users_users(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Users", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query__users_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query__user(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__user(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().User(rctx, fc.Args["params"].(model.GetUserRequest)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.User) - fc.Result = res - return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query__user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "email": - return ec.fieldContext_User_email(ctx, field) - case "email_verified": - return ec.fieldContext_User_email_verified(ctx, field) - case "signup_methods": - return ec.fieldContext_User_signup_methods(ctx, field) - case "given_name": - return ec.fieldContext_User_given_name(ctx, field) - case "family_name": - return ec.fieldContext_User_family_name(ctx, field) - case "middle_name": - return ec.fieldContext_User_middle_name(ctx, field) - case "nickname": - return ec.fieldContext_User_nickname(ctx, field) - case "preferred_username": - return ec.fieldContext_User_preferred_username(ctx, field) - case "gender": - return ec.fieldContext_User_gender(ctx, field) - case "birthdate": - return ec.fieldContext_User_birthdate(ctx, field) - case "phone_number": - return ec.fieldContext_User_phone_number(ctx, field) - case "phone_number_verified": - return ec.fieldContext_User_phone_number_verified(ctx, field) - case "picture": - return ec.fieldContext_User_picture(ctx, field) - case "roles": - return ec.fieldContext_User_roles(ctx, field) - case "created_at": - return ec.fieldContext_User_created_at(ctx, field) - case "updated_at": - return ec.fieldContext_User_updated_at(ctx, field) - case "revoked_timestamp": - return ec.fieldContext_User_revoked_timestamp(ctx, field) - case "is_multi_factor_auth_enabled": - return ec.fieldContext_User_is_multi_factor_auth_enabled(ctx, field) - case "app_data": - return ec.fieldContext_User_app_data(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query__user_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query__verification_requests(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__verification_requests(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().VerificationRequests(rctx, fc.Args["params"].(*model.PaginatedInput)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.VerificationRequests) - fc.Result = res - return ec.marshalNVerificationRequests2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerificationRequests(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query__verification_requests(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "pagination": - return ec.fieldContext_VerificationRequests_pagination(ctx, field) - case "verification_requests": - return ec.fieldContext_VerificationRequests_verification_requests(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type VerificationRequests", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query__verification_requests_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query__admin_session(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__admin_session(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().AdminSession(rctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.Response) - fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query__admin_session(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "message": - return ec.fieldContext_Response_message(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Response", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query__env(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__env(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Env(rctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.Env) - fc.Result = res - return ec.marshalNEnv2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐEnv(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query__env(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "ACCESS_TOKEN_EXPIRY_TIME": - return ec.fieldContext_Env_ACCESS_TOKEN_EXPIRY_TIME(ctx, field) - case "ADMIN_SECRET": - return ec.fieldContext_Env_ADMIN_SECRET(ctx, field) - case "DATABASE_NAME": - return ec.fieldContext_Env_DATABASE_NAME(ctx, field) - case "DATABASE_URL": - return ec.fieldContext_Env_DATABASE_URL(ctx, field) - case "DATABASE_TYPE": - return ec.fieldContext_Env_DATABASE_TYPE(ctx, field) - case "DATABASE_USERNAME": - return ec.fieldContext_Env_DATABASE_USERNAME(ctx, field) - case "DATABASE_PASSWORD": - return ec.fieldContext_Env_DATABASE_PASSWORD(ctx, field) - case "DATABASE_HOST": - return ec.fieldContext_Env_DATABASE_HOST(ctx, field) - case "DATABASE_PORT": - return ec.fieldContext_Env_DATABASE_PORT(ctx, field) - case "CLIENT_ID": - return ec.fieldContext_Env_CLIENT_ID(ctx, field) - case "CLIENT_SECRET": - return ec.fieldContext_Env_CLIENT_SECRET(ctx, field) - case "CUSTOM_ACCESS_TOKEN_SCRIPT": - return ec.fieldContext_Env_CUSTOM_ACCESS_TOKEN_SCRIPT(ctx, field) - case "SMTP_HOST": - return ec.fieldContext_Env_SMTP_HOST(ctx, field) - case "SMTP_PORT": - return ec.fieldContext_Env_SMTP_PORT(ctx, field) - case "SMTP_USERNAME": - return ec.fieldContext_Env_SMTP_USERNAME(ctx, field) - case "SMTP_PASSWORD": - return ec.fieldContext_Env_SMTP_PASSWORD(ctx, field) - case "SMTP_LOCAL_NAME": - return ec.fieldContext_Env_SMTP_LOCAL_NAME(ctx, field) - case "SENDER_EMAIL": - return ec.fieldContext_Env_SENDER_EMAIL(ctx, field) - case "SENDER_NAME": - return ec.fieldContext_Env_SENDER_NAME(ctx, field) - case "JWT_TYPE": - return ec.fieldContext_Env_JWT_TYPE(ctx, field) - case "JWT_SECRET": - return ec.fieldContext_Env_JWT_SECRET(ctx, field) - case "JWT_PRIVATE_KEY": - return ec.fieldContext_Env_JWT_PRIVATE_KEY(ctx, field) - case "JWT_PUBLIC_KEY": - return ec.fieldContext_Env_JWT_PUBLIC_KEY(ctx, field) - case "ALLOWED_ORIGINS": - return ec.fieldContext_Env_ALLOWED_ORIGINS(ctx, field) - case "APP_URL": - return ec.fieldContext_Env_APP_URL(ctx, field) - case "REDIS_URL": - return ec.fieldContext_Env_REDIS_URL(ctx, field) - case "RESET_PASSWORD_URL": - return ec.fieldContext_Env_RESET_PASSWORD_URL(ctx, field) - case "DISABLE_EMAIL_VERIFICATION": - return ec.fieldContext_Env_DISABLE_EMAIL_VERIFICATION(ctx, field) - case "DISABLE_BASIC_AUTHENTICATION": - return ec.fieldContext_Env_DISABLE_BASIC_AUTHENTICATION(ctx, field) - case "DISABLE_MOBILE_BASIC_AUTHENTICATION": - return ec.fieldContext_Env_DISABLE_MOBILE_BASIC_AUTHENTICATION(ctx, field) - case "DISABLE_MAGIC_LINK_LOGIN": - return ec.fieldContext_Env_DISABLE_MAGIC_LINK_LOGIN(ctx, field) - case "DISABLE_LOGIN_PAGE": - return ec.fieldContext_Env_DISABLE_LOGIN_PAGE(ctx, field) - case "DISABLE_SIGN_UP": - return ec.fieldContext_Env_DISABLE_SIGN_UP(ctx, field) - case "DISABLE_REDIS_FOR_ENV": - return ec.fieldContext_Env_DISABLE_REDIS_FOR_ENV(ctx, field) - case "DISABLE_STRONG_PASSWORD": - return ec.fieldContext_Env_DISABLE_STRONG_PASSWORD(ctx, field) - case "DISABLE_MULTI_FACTOR_AUTHENTICATION": - return ec.fieldContext_Env_DISABLE_MULTI_FACTOR_AUTHENTICATION(ctx, field) - case "ENFORCE_MULTI_FACTOR_AUTHENTICATION": - return ec.fieldContext_Env_ENFORCE_MULTI_FACTOR_AUTHENTICATION(ctx, field) - case "ROLES": - return ec.fieldContext_Env_ROLES(ctx, field) - case "PROTECTED_ROLES": - return ec.fieldContext_Env_PROTECTED_ROLES(ctx, field) - case "DEFAULT_ROLES": - return ec.fieldContext_Env_DEFAULT_ROLES(ctx, field) - case "JWT_ROLE_CLAIM": - return ec.fieldContext_Env_JWT_ROLE_CLAIM(ctx, field) - case "GOOGLE_CLIENT_ID": - return ec.fieldContext_Env_GOOGLE_CLIENT_ID(ctx, field) - case "GOOGLE_CLIENT_SECRET": - return ec.fieldContext_Env_GOOGLE_CLIENT_SECRET(ctx, field) - case "GITHUB_CLIENT_ID": - return ec.fieldContext_Env_GITHUB_CLIENT_ID(ctx, field) - case "GITHUB_CLIENT_SECRET": - return ec.fieldContext_Env_GITHUB_CLIENT_SECRET(ctx, field) - case "FACEBOOK_CLIENT_ID": - return ec.fieldContext_Env_FACEBOOK_CLIENT_ID(ctx, field) - case "FACEBOOK_CLIENT_SECRET": - return ec.fieldContext_Env_FACEBOOK_CLIENT_SECRET(ctx, field) - case "LINKEDIN_CLIENT_ID": - return ec.fieldContext_Env_LINKEDIN_CLIENT_ID(ctx, field) - case "LINKEDIN_CLIENT_SECRET": - return ec.fieldContext_Env_LINKEDIN_CLIENT_SECRET(ctx, field) - case "APPLE_CLIENT_ID": - return ec.fieldContext_Env_APPLE_CLIENT_ID(ctx, field) - case "APPLE_CLIENT_SECRET": - return ec.fieldContext_Env_APPLE_CLIENT_SECRET(ctx, field) - case "DISCORD_CLIENT_ID": - return ec.fieldContext_Env_DISCORD_CLIENT_ID(ctx, field) - case "DISCORD_CLIENT_SECRET": - return ec.fieldContext_Env_DISCORD_CLIENT_SECRET(ctx, field) - case "TWITTER_CLIENT_ID": - return ec.fieldContext_Env_TWITTER_CLIENT_ID(ctx, field) - case "TWITTER_CLIENT_SECRET": - return ec.fieldContext_Env_TWITTER_CLIENT_SECRET(ctx, field) - case "MICROSOFT_CLIENT_ID": - return ec.fieldContext_Env_MICROSOFT_CLIENT_ID(ctx, field) - case "MICROSOFT_CLIENT_SECRET": - return ec.fieldContext_Env_MICROSOFT_CLIENT_SECRET(ctx, field) - case "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID": - return ec.fieldContext_Env_MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID(ctx, field) - case "TWITCH_CLIENT_ID": - return ec.fieldContext_Env_TWITCH_CLIENT_ID(ctx, field) - case "TWITCH_CLIENT_SECRET": - return ec.fieldContext_Env_TWITCH_CLIENT_SECRET(ctx, field) - case "ROBLOX_CLIENT_ID": - return ec.fieldContext_Env_ROBLOX_CLIENT_ID(ctx, field) - case "ROBLOX_CLIENT_SECRET": - return ec.fieldContext_Env_ROBLOX_CLIENT_SECRET(ctx, field) - case "ORGANIZATION_NAME": - return ec.fieldContext_Env_ORGANIZATION_NAME(ctx, field) - case "ORGANIZATION_LOGO": - return ec.fieldContext_Env_ORGANIZATION_LOGO(ctx, field) - case "APP_COOKIE_SECURE": - return ec.fieldContext_Env_APP_COOKIE_SECURE(ctx, field) - case "ADMIN_COOKIE_SECURE": - return ec.fieldContext_Env_ADMIN_COOKIE_SECURE(ctx, field) - case "DEFAULT_AUTHORIZE_RESPONSE_TYPE": - return ec.fieldContext_Env_DEFAULT_AUTHORIZE_RESPONSE_TYPE(ctx, field) - case "DEFAULT_AUTHORIZE_RESPONSE_MODE": - return ec.fieldContext_Env_DEFAULT_AUTHORIZE_RESPONSE_MODE(ctx, field) - case "DISABLE_PLAYGROUND": - return ec.fieldContext_Env_DISABLE_PLAYGROUND(ctx, field) - case "DISABLE_MAIL_OTP_LOGIN": - return ec.fieldContext_Env_DISABLE_MAIL_OTP_LOGIN(ctx, field) - case "DISABLE_TOTP_LOGIN": - return ec.fieldContext_Env_DISABLE_TOTP_LOGIN(ctx, field) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Profile(rctx) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.User) + fc.Result = res + return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_profile(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "email": + return ec.fieldContext_User_email(ctx, field) + case "email_verified": + return ec.fieldContext_User_email_verified(ctx, field) + case "signup_methods": + return ec.fieldContext_User_signup_methods(ctx, field) + case "given_name": + return ec.fieldContext_User_given_name(ctx, field) + case "family_name": + return ec.fieldContext_User_family_name(ctx, field) + case "middle_name": + return ec.fieldContext_User_middle_name(ctx, field) + case "nickname": + return ec.fieldContext_User_nickname(ctx, field) + case "preferred_username": + return ec.fieldContext_User_preferred_username(ctx, field) + case "gender": + return ec.fieldContext_User_gender(ctx, field) + case "birthdate": + return ec.fieldContext_User_birthdate(ctx, field) + case "phone_number": + return ec.fieldContext_User_phone_number(ctx, field) + case "phone_number_verified": + return ec.fieldContext_User_phone_number_verified(ctx, field) + case "picture": + return ec.fieldContext_User_picture(ctx, field) + case "roles": + return ec.fieldContext_User_roles(ctx, field) + case "created_at": + return ec.fieldContext_User_created_at(ctx, field) + case "updated_at": + return ec.fieldContext_User_updated_at(ctx, field) + case "revoked_timestamp": + return ec.fieldContext_User_revoked_timestamp(ctx, field) + case "is_multi_factor_auth_enabled": + return ec.fieldContext_User_is_multi_factor_auth_enabled(ctx, field) + case "app_data": + return ec.fieldContext_User_app_data(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type Env", field.Name) + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } return fc, nil } -func (ec *executionContext) _Query__webhook(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__webhook(ctx, field) +func (ec *executionContext) _Query_validate_jwt_token(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_validate_jwt_token(ctx, field) if err != nil { return graphql.Null } @@ -12009,9 +11978,9 @@ func (ec *executionContext) _Query__webhook(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Webhook(rctx, fc.Args["params"].(model.WebhookRequest)) + return ec.resolvers.Query().ValidateJwtToken(rctx, fc.Args["params"].(model.ValidateJWTTokenRequest)) }) if err != nil { ec.Error(ctx, err) @@ -12023,12 +11992,12 @@ func (ec *executionContext) _Query__webhook(ctx context.Context, field graphql.C } return graphql.Null } - res := resTmp.(*model.Webhook) + res := resTmp.(*model.ValidateJWTTokenResponse) fc.Result = res - return ec.marshalNWebhook2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhook(ctx, field.Selections, res) + return ec.marshalNValidateJWTTokenResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐValidateJWTTokenResponse(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query__webhook(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_validate_jwt_token(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, @@ -12036,24 +12005,12 @@ func (ec *executionContext) fieldContext_Query__webhook(ctx context.Context, fie IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "id": - return ec.fieldContext_Webhook_id(ctx, field) - case "event_name": - return ec.fieldContext_Webhook_event_name(ctx, field) - case "event_description": - return ec.fieldContext_Webhook_event_description(ctx, field) - case "endpoint": - return ec.fieldContext_Webhook_endpoint(ctx, field) - case "enabled": - return ec.fieldContext_Webhook_enabled(ctx, field) - case "headers": - return ec.fieldContext_Webhook_headers(ctx, field) - case "created_at": - return ec.fieldContext_Webhook_created_at(ctx, field) - case "updated_at": - return ec.fieldContext_Webhook_updated_at(ctx, field) + case "is_valid": + return ec.fieldContext_ValidateJWTTokenResponse_is_valid(ctx, field) + case "claims": + return ec.fieldContext_ValidateJWTTokenResponse_claims(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type Webhook", field.Name) + return nil, fmt.Errorf("no field named %q was found under type ValidateJWTTokenResponse", field.Name) }, } defer func() { @@ -12063,15 +12020,15 @@ func (ec *executionContext) fieldContext_Query__webhook(ctx context.Context, fie } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query__webhook_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_validate_jwt_token_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query__webhooks(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__webhooks(ctx, field) +func (ec *executionContext) _Query_validate_session(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_validate_session(ctx, field) if err != nil { return graphql.Null } @@ -12082,9 +12039,9 @@ func (ec *executionContext) _Query__webhooks(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Webhooks(rctx, fc.Args["params"].(*model.PaginatedInput)) + return ec.resolvers.Query().ValidateSession(rctx, fc.Args["params"].(*model.ValidateSessionRequest)) }) if err != nil { ec.Error(ctx, err) @@ -12096,12 +12053,12 @@ func (ec *executionContext) _Query__webhooks(ctx context.Context, field graphql. } return graphql.Null } - res := resTmp.(*model.Webhooks) + res := resTmp.(*model.ValidateSessionResponse) fc.Result = res - return ec.marshalNWebhooks2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhooks(ctx, field.Selections, res) + return ec.marshalNValidateSessionResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐValidateSessionResponse(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query__webhooks(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_validate_session(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, @@ -12109,12 +12066,12 @@ func (ec *executionContext) fieldContext_Query__webhooks(ctx context.Context, fi IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "pagination": - return ec.fieldContext_Webhooks_pagination(ctx, field) - case "webhooks": - return ec.fieldContext_Webhooks_webhooks(ctx, field) + case "is_valid": + return ec.fieldContext_ValidateSessionResponse_is_valid(ctx, field) + case "user": + return ec.fieldContext_ValidateSessionResponse_user(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type Webhooks", field.Name) + return nil, fmt.Errorf("no field named %q was found under type ValidateSessionResponse", field.Name) }, } defer func() { @@ -12124,15 +12081,15 @@ func (ec *executionContext) fieldContext_Query__webhooks(ctx context.Context, fi } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query__webhooks_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_validate_session_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query__webhook_logs(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__webhook_logs(ctx, field) +func (ec *executionContext) _Query__users(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query__users(ctx, field) if err != nil { return graphql.Null } @@ -12143,9 +12100,9 @@ func (ec *executionContext) _Query__webhook_logs(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().WebhookLogs(rctx, fc.Args["params"].(*model.ListWebhookLogRequest)) + return ec.resolvers.Query().Users(rctx, fc.Args["params"].(*model.PaginatedRequest)) }) if err != nil { ec.Error(ctx, err) @@ -12157,12 +12114,12 @@ func (ec *executionContext) _Query__webhook_logs(ctx context.Context, field grap } return graphql.Null } - res := resTmp.(*model.WebhookLogs) + res := resTmp.(*model.Users) fc.Result = res - return ec.marshalNWebhookLogs2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookLogs(ctx, field.Selections, res) + return ec.marshalNUsers2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUsers(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query__webhook_logs(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query__users(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, @@ -12171,11 +12128,11 @@ func (ec *executionContext) fieldContext_Query__webhook_logs(ctx context.Context Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "pagination": - return ec.fieldContext_WebhookLogs_pagination(ctx, field) - case "webhook_logs": - return ec.fieldContext_WebhookLogs_webhook_logs(ctx, field) + return ec.fieldContext_Users_pagination(ctx, field) + case "users": + return ec.fieldContext_Users_users(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type WebhookLogs", field.Name) + return nil, fmt.Errorf("no field named %q was found under type Users", field.Name) }, } defer func() { @@ -12185,15 +12142,15 @@ func (ec *executionContext) fieldContext_Query__webhook_logs(ctx context.Context } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query__webhook_logs_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query__users_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query__email_templates(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__email_templates(ctx, field) +func (ec *executionContext) _Query__user(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query__user(ctx, field) if err != nil { return graphql.Null } @@ -12204,9 +12161,9 @@ func (ec *executionContext) _Query__email_templates(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().EmailTemplates(rctx, fc.Args["params"].(*model.PaginatedInput)) + return ec.resolvers.Query().User(rctx, fc.Args["params"].(model.GetUserRequest)) }) if err != nil { ec.Error(ctx, err) @@ -12218,12 +12175,12 @@ func (ec *executionContext) _Query__email_templates(ctx context.Context, field g } return graphql.Null } - res := resTmp.(*model.EmailTemplates) + res := resTmp.(*model.User) fc.Result = res - return ec.marshalNEmailTemplates2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐEmailTemplates(ctx, field.Selections, res) + return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query__email_templates(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query__user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, @@ -12231,12 +12188,48 @@ func (ec *executionContext) fieldContext_Query__email_templates(ctx context.Cont IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "pagination": - return ec.fieldContext_EmailTemplates_pagination(ctx, field) - case "email_templates": - return ec.fieldContext_EmailTemplates_email_templates(ctx, field) + case "id": + return ec.fieldContext_User_id(ctx, field) + case "email": + return ec.fieldContext_User_email(ctx, field) + case "email_verified": + return ec.fieldContext_User_email_verified(ctx, field) + case "signup_methods": + return ec.fieldContext_User_signup_methods(ctx, field) + case "given_name": + return ec.fieldContext_User_given_name(ctx, field) + case "family_name": + return ec.fieldContext_User_family_name(ctx, field) + case "middle_name": + return ec.fieldContext_User_middle_name(ctx, field) + case "nickname": + return ec.fieldContext_User_nickname(ctx, field) + case "preferred_username": + return ec.fieldContext_User_preferred_username(ctx, field) + case "gender": + return ec.fieldContext_User_gender(ctx, field) + case "birthdate": + return ec.fieldContext_User_birthdate(ctx, field) + case "phone_number": + return ec.fieldContext_User_phone_number(ctx, field) + case "phone_number_verified": + return ec.fieldContext_User_phone_number_verified(ctx, field) + case "picture": + return ec.fieldContext_User_picture(ctx, field) + case "roles": + return ec.fieldContext_User_roles(ctx, field) + case "created_at": + return ec.fieldContext_User_created_at(ctx, field) + case "updated_at": + return ec.fieldContext_User_updated_at(ctx, field) + case "revoked_timestamp": + return ec.fieldContext_User_revoked_timestamp(ctx, field) + case "is_multi_factor_auth_enabled": + return ec.fieldContext_User_is_multi_factor_auth_enabled(ctx, field) + case "app_data": + return ec.fieldContext_User_app_data(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type EmailTemplates", field.Name) + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } defer func() { @@ -12246,15 +12239,15 @@ func (ec *executionContext) fieldContext_Query__email_templates(ctx context.Cont } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query__email_templates_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query__user_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___type(ctx, field) +func (ec *executionContext) _Query__verification_requests(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query__verification_requests(ctx, field) if err != nil { return graphql.Null } @@ -12265,70 +12258,105 @@ func (ec *executionContext) _Query___type(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.introspectType(fc.Args["name"].(string)) + return ec.resolvers.Query().VerificationRequests(rctx, fc.Args["params"].(*model.PaginatedRequest)) }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(*introspection.Type) + res := resTmp.(*model.VerificationRequests) fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) + return ec.marshalNVerificationRequests2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐVerificationRequests(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query__verification_requests(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, - IsResolver: false, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "pagination": + return ec.fieldContext_VerificationRequests_pagination(ctx, field) + case "verification_requests": + return ec.fieldContext_VerificationRequests_verification_requests(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + return nil, fmt.Errorf("no field named %q was found under type VerificationRequests", field.Name) }, } defer func() { if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query__verification_requests_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query__admin_session(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query__admin_session(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null } }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().AdminSession(rctx) + }) + if err != nil { ec.Error(ctx, err) - return fc, err + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Response) + fc.Result = res + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query__admin_session(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "message": + return ec.fieldContext_Response_message(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Response", field.Name) + }, } return fc, nil } -func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___schema(ctx, field) +func (ec *executionContext) _Query__env(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query__env(ctx, field) if err != nil { return graphql.Null } @@ -12339,51 +12367,184 @@ func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.introspectSchema() + return ec.resolvers.Query().Env(rctx) }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(*introspection.Schema) + res := resTmp.(*model.Env) fc.Result = res - return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) + return ec.marshalNEnv2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐEnv(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query__env(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, - IsResolver: false, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "description": - return ec.fieldContext___Schema_description(ctx, field) - case "types": - return ec.fieldContext___Schema_types(ctx, field) - case "queryType": - return ec.fieldContext___Schema_queryType(ctx, field) - case "mutationType": - return ec.fieldContext___Schema_mutationType(ctx, field) - case "subscriptionType": - return ec.fieldContext___Schema_subscriptionType(ctx, field) - case "directives": - return ec.fieldContext___Schema_directives(ctx, field) + case "ACCESS_TOKEN_EXPIRY_TIME": + return ec.fieldContext_Env_ACCESS_TOKEN_EXPIRY_TIME(ctx, field) + case "ADMIN_SECRET": + return ec.fieldContext_Env_ADMIN_SECRET(ctx, field) + case "DATABASE_NAME": + return ec.fieldContext_Env_DATABASE_NAME(ctx, field) + case "DATABASE_URL": + return ec.fieldContext_Env_DATABASE_URL(ctx, field) + case "DATABASE_TYPE": + return ec.fieldContext_Env_DATABASE_TYPE(ctx, field) + case "DATABASE_USERNAME": + return ec.fieldContext_Env_DATABASE_USERNAME(ctx, field) + case "DATABASE_PASSWORD": + return ec.fieldContext_Env_DATABASE_PASSWORD(ctx, field) + case "DATABASE_HOST": + return ec.fieldContext_Env_DATABASE_HOST(ctx, field) + case "DATABASE_PORT": + return ec.fieldContext_Env_DATABASE_PORT(ctx, field) + case "CLIENT_ID": + return ec.fieldContext_Env_CLIENT_ID(ctx, field) + case "CLIENT_SECRET": + return ec.fieldContext_Env_CLIENT_SECRET(ctx, field) + case "CUSTOM_ACCESS_TOKEN_SCRIPT": + return ec.fieldContext_Env_CUSTOM_ACCESS_TOKEN_SCRIPT(ctx, field) + case "SMTP_HOST": + return ec.fieldContext_Env_SMTP_HOST(ctx, field) + case "SMTP_PORT": + return ec.fieldContext_Env_SMTP_PORT(ctx, field) + case "SMTP_USERNAME": + return ec.fieldContext_Env_SMTP_USERNAME(ctx, field) + case "SMTP_PASSWORD": + return ec.fieldContext_Env_SMTP_PASSWORD(ctx, field) + case "SMTP_LOCAL_NAME": + return ec.fieldContext_Env_SMTP_LOCAL_NAME(ctx, field) + case "SENDER_EMAIL": + return ec.fieldContext_Env_SENDER_EMAIL(ctx, field) + case "SENDER_NAME": + return ec.fieldContext_Env_SENDER_NAME(ctx, field) + case "JWT_TYPE": + return ec.fieldContext_Env_JWT_TYPE(ctx, field) + case "JWT_SECRET": + return ec.fieldContext_Env_JWT_SECRET(ctx, field) + case "JWT_PRIVATE_KEY": + return ec.fieldContext_Env_JWT_PRIVATE_KEY(ctx, field) + case "JWT_PUBLIC_KEY": + return ec.fieldContext_Env_JWT_PUBLIC_KEY(ctx, field) + case "ALLOWED_ORIGINS": + return ec.fieldContext_Env_ALLOWED_ORIGINS(ctx, field) + case "APP_URL": + return ec.fieldContext_Env_APP_URL(ctx, field) + case "REDIS_URL": + return ec.fieldContext_Env_REDIS_URL(ctx, field) + case "RESET_PASSWORD_URL": + return ec.fieldContext_Env_RESET_PASSWORD_URL(ctx, field) + case "DISABLE_EMAIL_VERIFICATION": + return ec.fieldContext_Env_DISABLE_EMAIL_VERIFICATION(ctx, field) + case "DISABLE_BASIC_AUTHENTICATION": + return ec.fieldContext_Env_DISABLE_BASIC_AUTHENTICATION(ctx, field) + case "DISABLE_MOBILE_BASIC_AUTHENTICATION": + return ec.fieldContext_Env_DISABLE_MOBILE_BASIC_AUTHENTICATION(ctx, field) + case "DISABLE_MAGIC_LINK_LOGIN": + return ec.fieldContext_Env_DISABLE_MAGIC_LINK_LOGIN(ctx, field) + case "DISABLE_LOGIN_PAGE": + return ec.fieldContext_Env_DISABLE_LOGIN_PAGE(ctx, field) + case "DISABLE_SIGN_UP": + return ec.fieldContext_Env_DISABLE_SIGN_UP(ctx, field) + case "DISABLE_REDIS_FOR_ENV": + return ec.fieldContext_Env_DISABLE_REDIS_FOR_ENV(ctx, field) + case "DISABLE_STRONG_PASSWORD": + return ec.fieldContext_Env_DISABLE_STRONG_PASSWORD(ctx, field) + case "DISABLE_MULTI_FACTOR_AUTHENTICATION": + return ec.fieldContext_Env_DISABLE_MULTI_FACTOR_AUTHENTICATION(ctx, field) + case "ENFORCE_MULTI_FACTOR_AUTHENTICATION": + return ec.fieldContext_Env_ENFORCE_MULTI_FACTOR_AUTHENTICATION(ctx, field) + case "ROLES": + return ec.fieldContext_Env_ROLES(ctx, field) + case "PROTECTED_ROLES": + return ec.fieldContext_Env_PROTECTED_ROLES(ctx, field) + case "DEFAULT_ROLES": + return ec.fieldContext_Env_DEFAULT_ROLES(ctx, field) + case "JWT_ROLE_CLAIM": + return ec.fieldContext_Env_JWT_ROLE_CLAIM(ctx, field) + case "GOOGLE_CLIENT_ID": + return ec.fieldContext_Env_GOOGLE_CLIENT_ID(ctx, field) + case "GOOGLE_CLIENT_SECRET": + return ec.fieldContext_Env_GOOGLE_CLIENT_SECRET(ctx, field) + case "GITHUB_CLIENT_ID": + return ec.fieldContext_Env_GITHUB_CLIENT_ID(ctx, field) + case "GITHUB_CLIENT_SECRET": + return ec.fieldContext_Env_GITHUB_CLIENT_SECRET(ctx, field) + case "FACEBOOK_CLIENT_ID": + return ec.fieldContext_Env_FACEBOOK_CLIENT_ID(ctx, field) + case "FACEBOOK_CLIENT_SECRET": + return ec.fieldContext_Env_FACEBOOK_CLIENT_SECRET(ctx, field) + case "LINKEDIN_CLIENT_ID": + return ec.fieldContext_Env_LINKEDIN_CLIENT_ID(ctx, field) + case "LINKEDIN_CLIENT_SECRET": + return ec.fieldContext_Env_LINKEDIN_CLIENT_SECRET(ctx, field) + case "APPLE_CLIENT_ID": + return ec.fieldContext_Env_APPLE_CLIENT_ID(ctx, field) + case "APPLE_CLIENT_SECRET": + return ec.fieldContext_Env_APPLE_CLIENT_SECRET(ctx, field) + case "DISCORD_CLIENT_ID": + return ec.fieldContext_Env_DISCORD_CLIENT_ID(ctx, field) + case "DISCORD_CLIENT_SECRET": + return ec.fieldContext_Env_DISCORD_CLIENT_SECRET(ctx, field) + case "TWITTER_CLIENT_ID": + return ec.fieldContext_Env_TWITTER_CLIENT_ID(ctx, field) + case "TWITTER_CLIENT_SECRET": + return ec.fieldContext_Env_TWITTER_CLIENT_SECRET(ctx, field) + case "MICROSOFT_CLIENT_ID": + return ec.fieldContext_Env_MICROSOFT_CLIENT_ID(ctx, field) + case "MICROSOFT_CLIENT_SECRET": + return ec.fieldContext_Env_MICROSOFT_CLIENT_SECRET(ctx, field) + case "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID": + return ec.fieldContext_Env_MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID(ctx, field) + case "TWITCH_CLIENT_ID": + return ec.fieldContext_Env_TWITCH_CLIENT_ID(ctx, field) + case "TWITCH_CLIENT_SECRET": + return ec.fieldContext_Env_TWITCH_CLIENT_SECRET(ctx, field) + case "ROBLOX_CLIENT_ID": + return ec.fieldContext_Env_ROBLOX_CLIENT_ID(ctx, field) + case "ROBLOX_CLIENT_SECRET": + return ec.fieldContext_Env_ROBLOX_CLIENT_SECRET(ctx, field) + case "ORGANIZATION_NAME": + return ec.fieldContext_Env_ORGANIZATION_NAME(ctx, field) + case "ORGANIZATION_LOGO": + return ec.fieldContext_Env_ORGANIZATION_LOGO(ctx, field) + case "APP_COOKIE_SECURE": + return ec.fieldContext_Env_APP_COOKIE_SECURE(ctx, field) + case "ADMIN_COOKIE_SECURE": + return ec.fieldContext_Env_ADMIN_COOKIE_SECURE(ctx, field) + case "DEFAULT_AUTHORIZE_RESPONSE_TYPE": + return ec.fieldContext_Env_DEFAULT_AUTHORIZE_RESPONSE_TYPE(ctx, field) + case "DEFAULT_AUTHORIZE_RESPONSE_MODE": + return ec.fieldContext_Env_DEFAULT_AUTHORIZE_RESPONSE_MODE(ctx, field) + case "DISABLE_PLAYGROUND": + return ec.fieldContext_Env_DISABLE_PLAYGROUND(ctx, field) + case "DISABLE_MAIL_OTP_LOGIN": + return ec.fieldContext_Env_DISABLE_MAIL_OTP_LOGIN(ctx, field) + case "DISABLE_TOTP_LOGIN": + return ec.fieldContext_Env_DISABLE_TOTP_LOGIN(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name) + return nil, fmt.Errorf("no field named %q was found under type Env", field.Name) }, } return fc, nil } -func (ec *executionContext) _Response_message(ctx context.Context, field graphql.CollectedField, obj *model.Response) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Response_message(ctx, field) +func (ec *executionContext) _Query__webhook(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query__webhook(ctx, field) if err != nil { return graphql.Null } @@ -12394,9 +12555,9 @@ func (ec *executionContext) _Response_message(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.Message, nil + return ec.resolvers.Query().Webhook(rctx, fc.Args["params"].(model.WebhookRequest)) }) if err != nil { ec.Error(ctx, err) @@ -12408,26 +12569,55 @@ func (ec *executionContext) _Response_message(ctx context.Context, field graphql } return graphql.Null } - res := resTmp.(string) + res := resTmp.(*model.Webhook) fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) + return ec.marshalNWebhook2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhook(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Response_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query__webhook(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Response", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + switch field.Name { + case "id": + return ec.fieldContext_Webhook_id(ctx, field) + case "event_name": + return ec.fieldContext_Webhook_event_name(ctx, field) + case "event_description": + return ec.fieldContext_Webhook_event_description(ctx, field) + case "endpoint": + return ec.fieldContext_Webhook_endpoint(ctx, field) + case "enabled": + return ec.fieldContext_Webhook_enabled(ctx, field) + case "headers": + return ec.fieldContext_Webhook_headers(ctx, field) + case "created_at": + return ec.fieldContext_Webhook_created_at(ctx, field) + case "updated_at": + return ec.fieldContext_Webhook_updated_at(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Webhook", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query__webhook_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _SMSVerificationRequests_id(ctx context.Context, field graphql.CollectedField, obj *model.SMSVerificationRequests) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SMSVerificationRequests_id(ctx, field) +func (ec *executionContext) _Query__webhooks(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query__webhooks(ctx, field) if err != nil { return graphql.Null } @@ -12438,9 +12628,9 @@ func (ec *executionContext) _SMSVerificationRequests_id(ctx context.Context, fie ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.ID, nil + return ec.resolvers.Query().Webhooks(rctx, fc.Args["params"].(*model.PaginatedRequest)) }) if err != nil { ec.Error(ctx, err) @@ -12452,26 +12642,43 @@ func (ec *executionContext) _SMSVerificationRequests_id(ctx context.Context, fie } return graphql.Null } - res := resTmp.(string) + res := resTmp.(*model.Webhooks) fc.Result = res - return ec.marshalNID2string(ctx, field.Selections, res) + return ec.marshalNWebhooks2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhooks(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SMSVerificationRequests_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query__webhooks(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SMSVerificationRequests", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + switch field.Name { + case "pagination": + return ec.fieldContext_Webhooks_pagination(ctx, field) + case "webhooks": + return ec.fieldContext_Webhooks_webhooks(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Webhooks", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query__webhooks_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _SMSVerificationRequests_code(ctx context.Context, field graphql.CollectedField, obj *model.SMSVerificationRequests) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SMSVerificationRequests_code(ctx, field) +func (ec *executionContext) _Query__webhook_logs(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query__webhook_logs(ctx, field) if err != nil { return graphql.Null } @@ -12482,9 +12689,9 @@ func (ec *executionContext) _SMSVerificationRequests_code(ctx context.Context, f ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.Code, nil + return ec.resolvers.Query().WebhookLogs(rctx, fc.Args["params"].(*model.ListWebhookLogRequest)) }) if err != nil { ec.Error(ctx, err) @@ -12496,26 +12703,43 @@ func (ec *executionContext) _SMSVerificationRequests_code(ctx context.Context, f } return graphql.Null } - res := resTmp.(string) + res := resTmp.(*model.WebhookLogs) fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) + return ec.marshalNWebhookLogs2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookLogs(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SMSVerificationRequests_code(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query__webhook_logs(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SMSVerificationRequests", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + switch field.Name { + case "pagination": + return ec.fieldContext_WebhookLogs_pagination(ctx, field) + case "webhook_logs": + return ec.fieldContext_WebhookLogs_webhook_logs(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type WebhookLogs", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query__webhook_logs_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _SMSVerificationRequests_code_expires_at(ctx context.Context, field graphql.CollectedField, obj *model.SMSVerificationRequests) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SMSVerificationRequests_code_expires_at(ctx, field) +func (ec *executionContext) _Query__email_templates(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query__email_templates(ctx, field) if err != nil { return graphql.Null } @@ -12526,9 +12750,9 @@ func (ec *executionContext) _SMSVerificationRequests_code_expires_at(ctx context ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.CodeExpiresAt, nil + return ec.resolvers.Query().EmailTemplates(rctx, fc.Args["params"].(*model.PaginatedRequest)) }) if err != nil { ec.Error(ctx, err) @@ -12540,26 +12764,43 @@ func (ec *executionContext) _SMSVerificationRequests_code_expires_at(ctx context } return graphql.Null } - res := resTmp.(int64) + res := resTmp.(*model.EmailTemplates) fc.Result = res - return ec.marshalNInt642int64(ctx, field.Selections, res) + return ec.marshalNEmailTemplates2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐEmailTemplates(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SMSVerificationRequests_code_expires_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query__email_templates(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SMSVerificationRequests", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int64 does not have child fields") + switch field.Name { + case "pagination": + return ec.fieldContext_EmailTemplates_pagination(ctx, field) + case "email_templates": + return ec.fieldContext_EmailTemplates_email_templates(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type EmailTemplates", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query__email_templates_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _SMSVerificationRequests_phone_number(ctx context.Context, field graphql.CollectedField, obj *model.SMSVerificationRequests) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SMSVerificationRequests_phone_number(ctx, field) +func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query___type(ctx, field) if err != nil { return graphql.Null } @@ -12570,40 +12811,72 @@ func (ec *executionContext) _SMSVerificationRequests_phone_number(ctx context.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.PhoneNumber, nil + return ec.introspectType(fc.Args["name"].(string)) }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(string) + res := resTmp.(*introspection.Type) fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SMSVerificationRequests_phone_number(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SMSVerificationRequests", + Object: "Query", Field: field, - IsMethod: false, + IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "isOneOf": + return ec.fieldContext___Type_isOneOf(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _SMSVerificationRequests_created_at(ctx context.Context, field graphql.CollectedField, obj *model.SMSVerificationRequests) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SMSVerificationRequests_created_at(ctx, field) +func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query___schema(ctx, field) if err != nil { return graphql.Null } @@ -12614,40 +12887,51 @@ func (ec *executionContext) _SMSVerificationRequests_created_at(ctx context.Cont ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.CreatedAt, nil + return ec.introspectSchema() }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(int64) + res := resTmp.(*introspection.Schema) fc.Result = res - return ec.marshalNInt642int64(ctx, field.Selections, res) + return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SMSVerificationRequests_created_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query___schema(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SMSVerificationRequests", + Object: "Query", Field: field, - IsMethod: false, + IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int64 does not have child fields") + switch field.Name { + case "description": + return ec.fieldContext___Schema_description(ctx, field) + case "types": + return ec.fieldContext___Schema_types(ctx, field) + case "queryType": + return ec.fieldContext___Schema_queryType(ctx, field) + case "mutationType": + return ec.fieldContext___Schema_mutationType(ctx, field) + case "subscriptionType": + return ec.fieldContext___Schema_subscriptionType(ctx, field) + case "directives": + return ec.fieldContext___Schema_directives(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name) }, } return fc, nil } -func (ec *executionContext) _SMSVerificationRequests_updated_at(ctx context.Context, field graphql.CollectedField, obj *model.SMSVerificationRequests) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SMSVerificationRequests_updated_at(ctx, field) +func (ec *executionContext) _Response_message(ctx context.Context, field graphql.CollectedField, obj *model.Response) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Response_message(ctx, field) if err != nil { return graphql.Null } @@ -12658,30 +12942,33 @@ func (ec *executionContext) _SMSVerificationRequests_updated_at(ctx context.Cont ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.UpdatedAt, nil + return obj.Message, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(*int64) + res := resTmp.(string) fc.Result = res - return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) + return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SMSVerificationRequests_updated_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Response_message(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SMSVerificationRequests", + Object: "Response", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int64 does not have child fields") + return nil, errors.New("field of type String does not have child fields") }, } return fc, nil @@ -12699,7 +12986,7 @@ func (ec *executionContext) _TestEndpointResponse_http_status(ctx context.Contex ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.HTTPStatus, nil }) @@ -12715,7 +13002,7 @@ func (ec *executionContext) _TestEndpointResponse_http_status(ctx context.Contex return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_TestEndpointResponse_http_status(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_TestEndpointResponse_http_status(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TestEndpointResponse", Field: field, @@ -12740,7 +13027,7 @@ func (ec *executionContext) _TestEndpointResponse_response(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Response, nil }) @@ -12756,7 +13043,7 @@ func (ec *executionContext) _TestEndpointResponse_response(ctx context.Context, return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_TestEndpointResponse_response(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_TestEndpointResponse_response(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TestEndpointResponse", Field: field, @@ -12781,7 +13068,7 @@ func (ec *executionContext) _User_id(ctx context.Context, field graphql.Collecte ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ID, nil }) @@ -12800,7 +13087,7 @@ func (ec *executionContext) _User_id(ctx context.Context, field graphql.Collecte return ec.marshalNID2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -12825,7 +13112,7 @@ func (ec *executionContext) _User_email(ctx context.Context, field graphql.Colle ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Email, nil }) @@ -12841,7 +13128,7 @@ func (ec *executionContext) _User_email(ctx context.Context, field graphql.Colle return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_email(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_email(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -12866,7 +13153,7 @@ func (ec *executionContext) _User_email_verified(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.EmailVerified, nil }) @@ -12885,7 +13172,7 @@ func (ec *executionContext) _User_email_verified(ctx context.Context, field grap return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_email_verified(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_email_verified(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -12910,7 +13197,7 @@ func (ec *executionContext) _User_signup_methods(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SignupMethods, nil }) @@ -12929,7 +13216,7 @@ func (ec *executionContext) _User_signup_methods(ctx context.Context, field grap return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_signup_methods(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_signup_methods(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -12954,7 +13241,7 @@ func (ec *executionContext) _User_given_name(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.GivenName, nil }) @@ -12970,7 +13257,7 @@ func (ec *executionContext) _User_given_name(ctx context.Context, field graphql. return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_given_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_given_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -12995,7 +13282,7 @@ func (ec *executionContext) _User_family_name(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.FamilyName, nil }) @@ -13011,7 +13298,7 @@ func (ec *executionContext) _User_family_name(ctx context.Context, field graphql return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_family_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_family_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13036,7 +13323,7 @@ func (ec *executionContext) _User_middle_name(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.MiddleName, nil }) @@ -13052,7 +13339,7 @@ func (ec *executionContext) _User_middle_name(ctx context.Context, field graphql return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_middle_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_middle_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13077,7 +13364,7 @@ func (ec *executionContext) _User_nickname(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Nickname, nil }) @@ -13093,7 +13380,7 @@ func (ec *executionContext) _User_nickname(ctx context.Context, field graphql.Co return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_nickname(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_nickname(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13118,7 +13405,7 @@ func (ec *executionContext) _User_preferred_username(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.PreferredUsername, nil }) @@ -13134,7 +13421,7 @@ func (ec *executionContext) _User_preferred_username(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_preferred_username(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_preferred_username(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13159,7 +13446,7 @@ func (ec *executionContext) _User_gender(ctx context.Context, field graphql.Coll ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Gender, nil }) @@ -13175,7 +13462,7 @@ func (ec *executionContext) _User_gender(ctx context.Context, field graphql.Coll return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_gender(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_gender(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13200,7 +13487,7 @@ func (ec *executionContext) _User_birthdate(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Birthdate, nil }) @@ -13216,7 +13503,7 @@ func (ec *executionContext) _User_birthdate(ctx context.Context, field graphql.C return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_birthdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_birthdate(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13241,7 +13528,7 @@ func (ec *executionContext) _User_phone_number(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.PhoneNumber, nil }) @@ -13257,7 +13544,7 @@ func (ec *executionContext) _User_phone_number(ctx context.Context, field graphq return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_phone_number(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_phone_number(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13282,7 +13569,7 @@ func (ec *executionContext) _User_phone_number_verified(ctx context.Context, fie ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.PhoneNumberVerified, nil }) @@ -13291,14 +13578,17 @@ func (ec *executionContext) _User_phone_number_verified(ctx context.Context, fie return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(*bool) + res := resTmp.(bool) fc.Result = res - return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) + return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_phone_number_verified(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_phone_number_verified(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13323,7 +13613,7 @@ func (ec *executionContext) _User_picture(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Picture, nil }) @@ -13339,7 +13629,7 @@ func (ec *executionContext) _User_picture(ctx context.Context, field graphql.Col return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_picture(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_picture(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13364,7 +13654,7 @@ func (ec *executionContext) _User_roles(ctx context.Context, field graphql.Colle ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Roles, nil }) @@ -13383,7 +13673,7 @@ func (ec *executionContext) _User_roles(ctx context.Context, field graphql.Colle return ec.marshalNString2ᚕstringᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_roles(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_roles(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13408,7 +13698,7 @@ func (ec *executionContext) _User_created_at(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.CreatedAt, nil }) @@ -13424,7 +13714,7 @@ func (ec *executionContext) _User_created_at(ctx context.Context, field graphql. return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_created_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_created_at(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13449,7 +13739,7 @@ func (ec *executionContext) _User_updated_at(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.UpdatedAt, nil }) @@ -13465,7 +13755,7 @@ func (ec *executionContext) _User_updated_at(ctx context.Context, field graphql. return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_updated_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_updated_at(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13490,7 +13780,7 @@ func (ec *executionContext) _User_revoked_timestamp(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.RevokedTimestamp, nil }) @@ -13506,7 +13796,7 @@ func (ec *executionContext) _User_revoked_timestamp(ctx context.Context, field g return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_revoked_timestamp(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_revoked_timestamp(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13531,7 +13821,7 @@ func (ec *executionContext) _User_is_multi_factor_auth_enabled(ctx context.Conte ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsMultiFactorAuthEnabled, nil }) @@ -13547,7 +13837,7 @@ func (ec *executionContext) _User_is_multi_factor_auth_enabled(ctx context.Conte return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_is_multi_factor_auth_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_is_multi_factor_auth_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13572,7 +13862,7 @@ func (ec *executionContext) _User_app_data(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AppData, nil }) @@ -13583,12 +13873,12 @@ func (ec *executionContext) _User_app_data(ctx context.Context, field graphql.Co if resTmp == nil { return graphql.Null } - res := resTmp.(map[string]interface{}) + res := resTmp.(map[string]any) fc.Result = res return ec.marshalOMap2map(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_app_data(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_app_data(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -13613,7 +13903,7 @@ func (ec *executionContext) _Users_pagination(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Pagination, nil }) @@ -13629,10 +13919,10 @@ func (ec *executionContext) _Users_pagination(ctx context.Context, field graphql } res := resTmp.(*model.Pagination) fc.Result = res - return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res) + return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Users_pagination(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Users_pagination(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Users", Field: field, @@ -13667,7 +13957,7 @@ func (ec *executionContext) _Users_users(ctx context.Context, field graphql.Coll ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Users, nil }) @@ -13683,10 +13973,10 @@ func (ec *executionContext) _Users_users(ctx context.Context, field graphql.Coll } res := resTmp.([]*model.User) fc.Result = res - return ec.marshalNUser2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUserᚄ(ctx, field.Selections, res) + return ec.marshalNUser2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUserᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Users_users(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Users_users(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Users", Field: field, @@ -13753,7 +14043,7 @@ func (ec *executionContext) _ValidateJWTTokenResponse_is_valid(ctx context.Conte ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsValid, nil }) @@ -13772,7 +14062,7 @@ func (ec *executionContext) _ValidateJWTTokenResponse_is_valid(ctx context.Conte return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ValidateJWTTokenResponse_is_valid(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ValidateJWTTokenResponse_is_valid(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ValidateJWTTokenResponse", Field: field, @@ -13797,7 +14087,7 @@ func (ec *executionContext) _ValidateJWTTokenResponse_claims(ctx context.Context ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Claims, nil }) @@ -13808,12 +14098,12 @@ func (ec *executionContext) _ValidateJWTTokenResponse_claims(ctx context.Context if resTmp == nil { return graphql.Null } - res := resTmp.(map[string]interface{}) + res := resTmp.(map[string]any) fc.Result = res return ec.marshalOMap2map(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ValidateJWTTokenResponse_claims(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ValidateJWTTokenResponse_claims(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ValidateJWTTokenResponse", Field: field, @@ -13838,7 +14128,7 @@ func (ec *executionContext) _ValidateSessionResponse_is_valid(ctx context.Contex ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsValid, nil }) @@ -13857,7 +14147,7 @@ func (ec *executionContext) _ValidateSessionResponse_is_valid(ctx context.Contex return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ValidateSessionResponse_is_valid(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ValidateSessionResponse_is_valid(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ValidateSessionResponse", Field: field, @@ -13882,7 +14172,7 @@ func (ec *executionContext) _ValidateSessionResponse_user(ctx context.Context, f ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.User, nil }) @@ -13898,10 +14188,10 @@ func (ec *executionContext) _ValidateSessionResponse_user(ctx context.Context, f } res := resTmp.(*model.User) fc.Result = res - return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) + return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ValidateSessionResponse_user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ValidateSessionResponse_user(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ValidateSessionResponse", Field: field, @@ -13968,7 +14258,7 @@ func (ec *executionContext) _VerificationRequest_id(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ID, nil }) @@ -13987,7 +14277,7 @@ func (ec *executionContext) _VerificationRequest_id(ctx context.Context, field g return ec.marshalNID2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_VerificationRequest_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_VerificationRequest_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "VerificationRequest", Field: field, @@ -14012,7 +14302,7 @@ func (ec *executionContext) _VerificationRequest_identifier(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Identifier, nil }) @@ -14028,7 +14318,7 @@ func (ec *executionContext) _VerificationRequest_identifier(ctx context.Context, return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_VerificationRequest_identifier(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_VerificationRequest_identifier(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "VerificationRequest", Field: field, @@ -14053,7 +14343,7 @@ func (ec *executionContext) _VerificationRequest_token(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Token, nil }) @@ -14069,7 +14359,7 @@ func (ec *executionContext) _VerificationRequest_token(ctx context.Context, fiel return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_VerificationRequest_token(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_VerificationRequest_token(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "VerificationRequest", Field: field, @@ -14094,7 +14384,7 @@ func (ec *executionContext) _VerificationRequest_email(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Email, nil }) @@ -14110,7 +14400,7 @@ func (ec *executionContext) _VerificationRequest_email(ctx context.Context, fiel return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_VerificationRequest_email(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_VerificationRequest_email(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "VerificationRequest", Field: field, @@ -14135,7 +14425,7 @@ func (ec *executionContext) _VerificationRequest_expires(ctx context.Context, fi ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Expires, nil }) @@ -14151,7 +14441,7 @@ func (ec *executionContext) _VerificationRequest_expires(ctx context.Context, fi return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_VerificationRequest_expires(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_VerificationRequest_expires(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "VerificationRequest", Field: field, @@ -14176,7 +14466,7 @@ func (ec *executionContext) _VerificationRequest_created_at(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.CreatedAt, nil }) @@ -14192,7 +14482,7 @@ func (ec *executionContext) _VerificationRequest_created_at(ctx context.Context, return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_VerificationRequest_created_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_VerificationRequest_created_at(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "VerificationRequest", Field: field, @@ -14217,7 +14507,7 @@ func (ec *executionContext) _VerificationRequest_updated_at(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.UpdatedAt, nil }) @@ -14233,7 +14523,7 @@ func (ec *executionContext) _VerificationRequest_updated_at(ctx context.Context, return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_VerificationRequest_updated_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_VerificationRequest_updated_at(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "VerificationRequest", Field: field, @@ -14258,7 +14548,7 @@ func (ec *executionContext) _VerificationRequest_nonce(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Nonce, nil }) @@ -14274,7 +14564,7 @@ func (ec *executionContext) _VerificationRequest_nonce(ctx context.Context, fiel return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_VerificationRequest_nonce(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_VerificationRequest_nonce(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "VerificationRequest", Field: field, @@ -14299,7 +14589,7 @@ func (ec *executionContext) _VerificationRequest_redirect_uri(ctx context.Contex ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.RedirectURI, nil }) @@ -14315,7 +14605,7 @@ func (ec *executionContext) _VerificationRequest_redirect_uri(ctx context.Contex return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_VerificationRequest_redirect_uri(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_VerificationRequest_redirect_uri(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "VerificationRequest", Field: field, @@ -14340,7 +14630,7 @@ func (ec *executionContext) _VerificationRequests_pagination(ctx context.Context ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Pagination, nil }) @@ -14356,10 +14646,10 @@ func (ec *executionContext) _VerificationRequests_pagination(ctx context.Context } res := resTmp.(*model.Pagination) fc.Result = res - return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res) + return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_VerificationRequests_pagination(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_VerificationRequests_pagination(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "VerificationRequests", Field: field, @@ -14394,7 +14684,7 @@ func (ec *executionContext) _VerificationRequests_verification_requests(ctx cont ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.VerificationRequests, nil }) @@ -14410,10 +14700,10 @@ func (ec *executionContext) _VerificationRequests_verification_requests(ctx cont } res := resTmp.([]*model.VerificationRequest) fc.Result = res - return ec.marshalNVerificationRequest2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerificationRequestᚄ(ctx, field.Selections, res) + return ec.marshalNVerificationRequest2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐVerificationRequestᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_VerificationRequests_verification_requests(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_VerificationRequests_verification_requests(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "VerificationRequests", Field: field, @@ -14458,7 +14748,7 @@ func (ec *executionContext) _Webhook_id(ctx context.Context, field graphql.Colle ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ID, nil }) @@ -14477,7 +14767,7 @@ func (ec *executionContext) _Webhook_id(ctx context.Context, field graphql.Colle return ec.marshalNID2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Webhook_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Webhook_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Webhook", Field: field, @@ -14502,7 +14792,7 @@ func (ec *executionContext) _Webhook_event_name(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.EventName, nil }) @@ -14518,7 +14808,7 @@ func (ec *executionContext) _Webhook_event_name(ctx context.Context, field graph return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Webhook_event_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Webhook_event_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Webhook", Field: field, @@ -14543,7 +14833,7 @@ func (ec *executionContext) _Webhook_event_description(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.EventDescription, nil }) @@ -14559,7 +14849,7 @@ func (ec *executionContext) _Webhook_event_description(ctx context.Context, fiel return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Webhook_event_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Webhook_event_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Webhook", Field: field, @@ -14584,7 +14874,7 @@ func (ec *executionContext) _Webhook_endpoint(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Endpoint, nil }) @@ -14600,7 +14890,7 @@ func (ec *executionContext) _Webhook_endpoint(ctx context.Context, field graphql return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Webhook_endpoint(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Webhook_endpoint(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Webhook", Field: field, @@ -14625,7 +14915,7 @@ func (ec *executionContext) _Webhook_enabled(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Enabled, nil }) @@ -14641,7 +14931,7 @@ func (ec *executionContext) _Webhook_enabled(ctx context.Context, field graphql. return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Webhook_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Webhook_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Webhook", Field: field, @@ -14666,7 +14956,7 @@ func (ec *executionContext) _Webhook_headers(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Headers, nil }) @@ -14677,12 +14967,12 @@ func (ec *executionContext) _Webhook_headers(ctx context.Context, field graphql. if resTmp == nil { return graphql.Null } - res := resTmp.(map[string]interface{}) + res := resTmp.(map[string]any) fc.Result = res return ec.marshalOMap2map(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Webhook_headers(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Webhook_headers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Webhook", Field: field, @@ -14707,7 +14997,7 @@ func (ec *executionContext) _Webhook_created_at(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.CreatedAt, nil }) @@ -14723,7 +15013,7 @@ func (ec *executionContext) _Webhook_created_at(ctx context.Context, field graph return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Webhook_created_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Webhook_created_at(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Webhook", Field: field, @@ -14748,7 +15038,7 @@ func (ec *executionContext) _Webhook_updated_at(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.UpdatedAt, nil }) @@ -14764,7 +15054,7 @@ func (ec *executionContext) _Webhook_updated_at(ctx context.Context, field graph return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Webhook_updated_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Webhook_updated_at(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Webhook", Field: field, @@ -14789,7 +15079,7 @@ func (ec *executionContext) _WebhookLog_id(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ID, nil }) @@ -14808,7 +15098,7 @@ func (ec *executionContext) _WebhookLog_id(ctx context.Context, field graphql.Co return ec.marshalNID2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_WebhookLog_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_WebhookLog_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "WebhookLog", Field: field, @@ -14833,7 +15123,7 @@ func (ec *executionContext) _WebhookLog_http_status(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.HTTPStatus, nil }) @@ -14849,7 +15139,7 @@ func (ec *executionContext) _WebhookLog_http_status(ctx context.Context, field g return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_WebhookLog_http_status(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_WebhookLog_http_status(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "WebhookLog", Field: field, @@ -14874,7 +15164,7 @@ func (ec *executionContext) _WebhookLog_response(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Response, nil }) @@ -14890,7 +15180,7 @@ func (ec *executionContext) _WebhookLog_response(ctx context.Context, field grap return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_WebhookLog_response(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_WebhookLog_response(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "WebhookLog", Field: field, @@ -14915,7 +15205,7 @@ func (ec *executionContext) _WebhookLog_request(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Request, nil }) @@ -14931,7 +15221,7 @@ func (ec *executionContext) _WebhookLog_request(ctx context.Context, field graph return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_WebhookLog_request(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_WebhookLog_request(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "WebhookLog", Field: field, @@ -14956,7 +15246,7 @@ func (ec *executionContext) _WebhookLog_webhook_id(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.WebhookID, nil }) @@ -14972,7 +15262,7 @@ func (ec *executionContext) _WebhookLog_webhook_id(ctx context.Context, field gr return ec.marshalOID2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_WebhookLog_webhook_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_WebhookLog_webhook_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "WebhookLog", Field: field, @@ -14997,7 +15287,7 @@ func (ec *executionContext) _WebhookLog_created_at(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.CreatedAt, nil }) @@ -15013,7 +15303,7 @@ func (ec *executionContext) _WebhookLog_created_at(ctx context.Context, field gr return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_WebhookLog_created_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_WebhookLog_created_at(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "WebhookLog", Field: field, @@ -15038,7 +15328,7 @@ func (ec *executionContext) _WebhookLog_updated_at(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.UpdatedAt, nil }) @@ -15054,7 +15344,7 @@ func (ec *executionContext) _WebhookLog_updated_at(ctx context.Context, field gr return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_WebhookLog_updated_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_WebhookLog_updated_at(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "WebhookLog", Field: field, @@ -15079,7 +15369,7 @@ func (ec *executionContext) _WebhookLogs_pagination(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Pagination, nil }) @@ -15095,10 +15385,10 @@ func (ec *executionContext) _WebhookLogs_pagination(ctx context.Context, field g } res := resTmp.(*model.Pagination) fc.Result = res - return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res) + return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_WebhookLogs_pagination(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_WebhookLogs_pagination(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "WebhookLogs", Field: field, @@ -15133,7 +15423,7 @@ func (ec *executionContext) _WebhookLogs_webhook_logs(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.WebhookLogs, nil }) @@ -15149,10 +15439,10 @@ func (ec *executionContext) _WebhookLogs_webhook_logs(ctx context.Context, field } res := resTmp.([]*model.WebhookLog) fc.Result = res - return ec.marshalNWebhookLog2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookLogᚄ(ctx, field.Selections, res) + return ec.marshalNWebhookLog2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookLogᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_WebhookLogs_webhook_logs(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_WebhookLogs_webhook_logs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "WebhookLogs", Field: field, @@ -15193,7 +15483,7 @@ func (ec *executionContext) _Webhooks_pagination(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Pagination, nil }) @@ -15209,10 +15499,10 @@ func (ec *executionContext) _Webhooks_pagination(ctx context.Context, field grap } res := resTmp.(*model.Pagination) fc.Result = res - return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res) + return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Webhooks_pagination(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Webhooks_pagination(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Webhooks", Field: field, @@ -15247,7 +15537,7 @@ func (ec *executionContext) _Webhooks_webhooks(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Webhooks, nil }) @@ -15263,10 +15553,10 @@ func (ec *executionContext) _Webhooks_webhooks(ctx context.Context, field graphq } res := resTmp.([]*model.Webhook) fc.Result = res - return ec.marshalNWebhook2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookᚄ(ctx, field.Selections, res) + return ec.marshalNWebhook2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Webhooks_webhooks(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Webhooks_webhooks(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Webhooks", Field: field, @@ -15309,7 +15599,7 @@ func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -15328,7 +15618,7 @@ func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Directive_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Directive_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, @@ -15353,7 +15643,7 @@ func (ec *executionContext) ___Directive_description(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -15369,7 +15659,7 @@ func (ec *executionContext) ___Directive_description(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Directive_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Directive_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, @@ -15382,8 +15672,8 @@ func (ec *executionContext) fieldContext___Directive_description(ctx context.Con return fc, nil } -func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_locations(ctx, field) +func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_isRepeatable(ctx, field) if err != nil { return graphql.Null } @@ -15394,9 +15684,9 @@ func (ec *executionContext) ___Directive_locations(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.Locations, nil + return obj.IsRepeatable, nil }) if err != nil { ec.Error(ctx, err) @@ -15408,26 +15698,26 @@ func (ec *executionContext) ___Directive_locations(ctx context.Context, field gr } return graphql.Null } - res := resTmp.([]string) + res := resTmp.(bool) fc.Result = res - return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res) + return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Directive_locations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Directive_isRepeatable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type __DirectiveLocation does not have child fields") + return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } -func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_args(ctx, field) +func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_locations(ctx, field) if err != nil { return graphql.Null } @@ -15438,9 +15728,9 @@ func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.Args, nil + return obj.Locations, nil }) if err != nil { ec.Error(ctx, err) @@ -15452,36 +15742,26 @@ func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql } return graphql.Null } - res := resTmp.([]introspection.InputValue) + res := resTmp.([]string) fc.Result = res - return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) + return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Directive_locations(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) + return nil, errors.New("field of type __DirectiveLocation does not have child fields") }, } return fc, nil } -func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_isRepeatable(ctx, field) +func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_args(ctx, field) if err != nil { return graphql.Null } @@ -15492,9 +15772,9 @@ func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.IsRepeatable, nil + return obj.Args, nil }) if err != nil { ec.Error(ctx, err) @@ -15506,21 +15786,46 @@ func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field } return graphql.Null } - res := resTmp.(bool) + res := resTmp.([]introspection.InputValue) fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) + return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") + switch field.Name { + case "name": + return ec.fieldContext___InputValue_name(ctx, field) + case "description": + return ec.fieldContext___InputValue_description(ctx, field) + case "type": + return ec.fieldContext___InputValue_type(ctx, field) + case "defaultValue": + return ec.fieldContext___InputValue_defaultValue(ctx, field) + case "isDeprecated": + return ec.fieldContext___InputValue_isDeprecated(ctx, field) + case "deprecationReason": + return ec.fieldContext___InputValue_deprecationReason(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field___Directive_args_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } @@ -15536,7 +15841,7 @@ func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -15555,7 +15860,7 @@ func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___EnumValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___EnumValue_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, @@ -15580,7 +15885,7 @@ func (ec *executionContext) ___EnumValue_description(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -15596,7 +15901,7 @@ func (ec *executionContext) ___EnumValue_description(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___EnumValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___EnumValue_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, @@ -15621,7 +15926,7 @@ func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsDeprecated(), nil }) @@ -15640,7 +15945,7 @@ func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___EnumValue_isDeprecated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, @@ -15665,7 +15970,7 @@ func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DeprecationReason(), nil }) @@ -15681,7 +15986,7 @@ func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___EnumValue_deprecationReason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, @@ -15706,7 +16011,7 @@ func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -15725,7 +16030,7 @@ func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.Col return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Field_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Field_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, @@ -15750,7 +16055,7 @@ func (ec *executionContext) ___Field_description(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -15766,7 +16071,7 @@ func (ec *executionContext) ___Field_description(ctx context.Context, field grap return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Field_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Field_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, @@ -15791,7 +16096,7 @@ func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Args, nil }) @@ -15826,10 +16131,25 @@ func (ec *executionContext) fieldContext___Field_args(ctx context.Context, field return ec.fieldContext___InputValue_type(ctx, field) case "defaultValue": return ec.fieldContext___InputValue_defaultValue(ctx, field) + case "isDeprecated": + return ec.fieldContext___InputValue_isDeprecated(ctx, field) + case "deprecationReason": + return ec.fieldContext___InputValue_deprecationReason(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field___Field_args_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } @@ -15845,7 +16165,7 @@ func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Type, nil }) @@ -15864,7 +16184,7 @@ func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.Col return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Field_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, @@ -15878,6 +16198,8 @@ func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": @@ -15890,8 +16212,8 @@ func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "isOneOf": + return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, @@ -15911,7 +16233,7 @@ func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsDeprecated(), nil }) @@ -15930,7 +16252,7 @@ func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field gra return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Field_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Field_isDeprecated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, @@ -15955,7 +16277,7 @@ func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DeprecationReason(), nil }) @@ -15971,7 +16293,7 @@ func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, fiel return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Field_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Field_deprecationReason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, @@ -15996,7 +16318,7 @@ func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -16015,7 +16337,7 @@ func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphq return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___InputValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___InputValue_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, @@ -16040,7 +16362,7 @@ func (ec *executionContext) ___InputValue_description(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -16056,7 +16378,7 @@ func (ec *executionContext) ___InputValue_description(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___InputValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___InputValue_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, @@ -16081,7 +16403,7 @@ func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Type, nil }) @@ -16100,7 +16422,7 @@ func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphq return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___InputValue_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, @@ -16114,6 +16436,8 @@ func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": @@ -16126,8 +16450,8 @@ func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "isOneOf": + return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, @@ -16147,7 +16471,7 @@ func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DefaultValue, nil }) @@ -16163,7 +16487,7 @@ func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, fiel return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___InputValue_defaultValue(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, @@ -16176,6 +16500,91 @@ func (ec *executionContext) fieldContext___InputValue_defaultValue(ctx context.C return fc, nil } +func (ec *executionContext) ___InputValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___InputValue_isDeprecated(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsDeprecated(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___InputValue_isDeprecated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___InputValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___InputValue_deprecationReason(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeprecationReason(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___InputValue_deprecationReason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) ___Schema_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { fc, err := ec.fieldContext___Schema_description(ctx, field) if err != nil { @@ -16188,7 +16597,7 @@ func (ec *executionContext) ___Schema_description(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -16204,7 +16613,7 @@ func (ec *executionContext) ___Schema_description(ctx context.Context, field gra return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -16229,7 +16638,7 @@ func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Types(), nil }) @@ -16248,7 +16657,7 @@ func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.C return ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_types(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -16262,6 +16671,8 @@ func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, fie return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": @@ -16274,8 +16685,8 @@ func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, fie return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "isOneOf": + return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, @@ -16295,7 +16706,7 @@ func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.QueryType(), nil }) @@ -16314,7 +16725,7 @@ func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graph return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_queryType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -16328,6 +16739,8 @@ func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": @@ -16340,8 +16753,8 @@ func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "isOneOf": + return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, @@ -16361,7 +16774,7 @@ func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.MutationType(), nil }) @@ -16377,7 +16790,7 @@ func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field gr return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_mutationType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -16391,6 +16804,8 @@ func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Conte return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": @@ -16403,8 +16818,8 @@ func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Conte return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "isOneOf": + return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, @@ -16424,7 +16839,7 @@ func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SubscriptionType(), nil }) @@ -16440,7 +16855,7 @@ func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, fiel return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_subscriptionType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -16454,6 +16869,8 @@ func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.C return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": @@ -16466,8 +16883,8 @@ func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.C return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "isOneOf": + return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, @@ -16487,7 +16904,7 @@ func (ec *executionContext) ___Schema_directives(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Directives(), nil }) @@ -16506,7 +16923,7 @@ func (ec *executionContext) ___Schema_directives(ctx context.Context, field grap return ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_directives(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_directives(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -16518,12 +16935,12 @@ func (ec *executionContext) fieldContext___Schema_directives(ctx context.Context return ec.fieldContext___Directive_name(ctx, field) case "description": return ec.fieldContext___Directive_description(ctx, field) + case "isRepeatable": + return ec.fieldContext___Directive_isRepeatable(ctx, field) case "locations": return ec.fieldContext___Directive_locations(ctx, field) case "args": return ec.fieldContext___Directive_args(ctx, field) - case "isRepeatable": - return ec.fieldContext___Directive_isRepeatable(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Directive", field.Name) }, @@ -16543,7 +16960,7 @@ func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.Coll ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Kind(), nil }) @@ -16562,7 +16979,7 @@ func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.Coll return ec.marshalN__TypeKind2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_kind(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_kind(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -16587,7 +17004,7 @@ func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.Coll ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name(), nil }) @@ -16603,7 +17020,7 @@ func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.Coll return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -16628,7 +17045,7 @@ func (ec *executionContext) ___Type_description(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -16644,7 +17061,48 @@ func (ec *executionContext) ___Type_description(ctx context.Context, field graph return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_specifiedByURL(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.SpecifiedByURL(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_specifiedByURL(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -16669,7 +17127,7 @@ func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Fields(fc.Args["includeDeprecated"].(bool)), nil }) @@ -16735,7 +17193,7 @@ func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Interfaces(), nil }) @@ -16751,7 +17209,7 @@ func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphq return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_interfaces(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -16765,6 +17223,8 @@ func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": @@ -16777,8 +17237,8 @@ func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "isOneOf": + return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, @@ -16798,7 +17258,7 @@ func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.PossibleTypes(), nil }) @@ -16814,7 +17274,7 @@ func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field gra return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_possibleTypes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -16828,6 +17288,8 @@ func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Contex return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": @@ -16840,8 +17302,8 @@ func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Contex return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "isOneOf": + return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, @@ -16861,7 +17323,7 @@ func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.EnumValues(fc.Args["includeDeprecated"].(bool)), nil }) @@ -16923,7 +17385,7 @@ func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.InputFields(), nil }) @@ -16939,7 +17401,7 @@ func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graph return ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_inputFields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_inputFields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -16955,6 +17417,10 @@ func (ec *executionContext) fieldContext___Type_inputFields(ctx context.Context, return ec.fieldContext___InputValue_type(ctx, field) case "defaultValue": return ec.fieldContext___InputValue_defaultValue(ctx, field) + case "isDeprecated": + return ec.fieldContext___InputValue_isDeprecated(ctx, field) + case "deprecationReason": + return ec.fieldContext___InputValue_deprecationReason(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) }, @@ -16974,7 +17440,7 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.OfType(), nil }) @@ -16990,7 +17456,7 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_ofType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -17004,6 +17470,8 @@ func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, fiel return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": @@ -17016,8 +17484,8 @@ func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, fiel return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "isOneOf": + return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, @@ -17025,8 +17493,8 @@ func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, fiel return fc, nil } -func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_specifiedByURL(ctx, field) +func (ec *executionContext) ___Type_isOneOf(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_isOneOf(ctx, field) if err != nil { return graphql.Null } @@ -17037,9 +17505,9 @@ func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.SpecifiedByURL(), nil + return obj.IsOneOf(), nil }) if err != nil { ec.Error(ctx, err) @@ -17048,19 +17516,19 @@ func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field gr if resTmp == nil { return graphql.Null } - res := resTmp.(*string) + res := resTmp.(bool) fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) + return ec.marshalOBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_isOneOf(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil @@ -17070,10 +17538,10 @@ func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Conte // region **************************** input.gotpl ***************************** -func (ec *executionContext) unmarshalInputAddEmailTemplateRequest(ctx context.Context, obj interface{}) (model.AddEmailTemplateRequest, error) { +func (ec *executionContext) unmarshalInputAddEmailTemplateRequest(ctx context.Context, obj any) (model.AddEmailTemplateRequest, error) { var it model.AddEmailTemplateRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17118,10 +17586,10 @@ func (ec *executionContext) unmarshalInputAddEmailTemplateRequest(ctx context.Co return it, nil } -func (ec *executionContext) unmarshalInputAddWebhookRequest(ctx context.Context, obj interface{}) (model.AddWebhookRequest, error) { +func (ec *executionContext) unmarshalInputAddWebhookRequest(ctx context.Context, obj any) (model.AddWebhookRequest, error) { var it model.AddWebhookRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17173,10 +17641,10 @@ func (ec *executionContext) unmarshalInputAddWebhookRequest(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputAdminLoginInput(ctx context.Context, obj interface{}) (model.AdminLoginInput, error) { - var it model.AdminLoginInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputAdminLoginRequest(ctx context.Context, obj any) (model.AdminLoginRequest, error) { + var it model.AdminLoginRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17200,10 +17668,10 @@ func (ec *executionContext) unmarshalInputAdminLoginInput(ctx context.Context, o return it, nil } -func (ec *executionContext) unmarshalInputAdminSignupInput(ctx context.Context, obj interface{}) (model.AdminSignupInput, error) { - var it model.AdminSignupInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputAdminSignupRequest(ctx context.Context, obj any) (model.AdminSignupRequest, error) { + var it model.AdminSignupRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17227,10 +17695,10 @@ func (ec *executionContext) unmarshalInputAdminSignupInput(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputDeleteEmailTemplateRequest(ctx context.Context, obj interface{}) (model.DeleteEmailTemplateRequest, error) { +func (ec *executionContext) unmarshalInputDeleteEmailTemplateRequest(ctx context.Context, obj any) (model.DeleteEmailTemplateRequest, error) { var it model.DeleteEmailTemplateRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17254,10 +17722,10 @@ func (ec *executionContext) unmarshalInputDeleteEmailTemplateRequest(ctx context return it, nil } -func (ec *executionContext) unmarshalInputDeleteUserInput(ctx context.Context, obj interface{}) (model.DeleteUserInput, error) { - var it model.DeleteUserInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputDeleteUserRequest(ctx context.Context, obj any) (model.DeleteUserRequest, error) { + var it model.DeleteUserRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17281,10 +17749,10 @@ func (ec *executionContext) unmarshalInputDeleteUserInput(ctx context.Context, o return it, nil } -func (ec *executionContext) unmarshalInputForgotPasswordInput(ctx context.Context, obj interface{}) (model.ForgotPasswordInput, error) { - var it model.ForgotPasswordInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputForgotPasswordRequest(ctx context.Context, obj any) (model.ForgotPasswordRequest, error) { + var it model.ForgotPasswordRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17329,10 +17797,10 @@ func (ec *executionContext) unmarshalInputForgotPasswordInput(ctx context.Contex return it, nil } -func (ec *executionContext) unmarshalInputGenerateJWTKeysInput(ctx context.Context, obj interface{}) (model.GenerateJWTKeysInput, error) { - var it model.GenerateJWTKeysInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputGenerateJWTKeysRequest(ctx context.Context, obj any) (model.GenerateJWTKeysRequest, error) { + var it model.GenerateJWTKeysRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17356,10 +17824,10 @@ func (ec *executionContext) unmarshalInputGenerateJWTKeysInput(ctx context.Conte return it, nil } -func (ec *executionContext) unmarshalInputGetUserRequest(ctx context.Context, obj interface{}) (model.GetUserRequest, error) { +func (ec *executionContext) unmarshalInputGetUserRequest(ctx context.Context, obj any) (model.GetUserRequest, error) { var it model.GetUserRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17390,10 +17858,10 @@ func (ec *executionContext) unmarshalInputGetUserRequest(ctx context.Context, ob return it, nil } -func (ec *executionContext) unmarshalInputInviteMemberInput(ctx context.Context, obj interface{}) (model.InviteMemberInput, error) { - var it model.InviteMemberInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputInviteMemberRequest(ctx context.Context, obj any) (model.InviteMemberRequest, error) { + var it model.InviteMemberRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17424,10 +17892,10 @@ func (ec *executionContext) unmarshalInputInviteMemberInput(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputListWebhookLogRequest(ctx context.Context, obj interface{}) (model.ListWebhookLogRequest, error) { +func (ec *executionContext) unmarshalInputListWebhookLogRequest(ctx context.Context, obj any) (model.ListWebhookLogRequest, error) { var it model.ListWebhookLogRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17440,7 +17908,7 @@ func (ec *executionContext) unmarshalInputListWebhookLogRequest(ctx context.Cont switch k { case "pagination": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("pagination")) - data, err := ec.unmarshalOPaginationInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginationInput(ctx, v) + data, err := ec.unmarshalOPaginationRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPaginationRequest(ctx, v) if err != nil { return it, err } @@ -17458,10 +17926,10 @@ func (ec *executionContext) unmarshalInputListWebhookLogRequest(ctx context.Cont return it, nil } -func (ec *executionContext) unmarshalInputLoginInput(ctx context.Context, obj interface{}) (model.LoginInput, error) { - var it model.LoginInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputLoginRequest(ctx context.Context, obj any) (model.LoginRequest, error) { + var it model.LoginRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17520,10 +17988,10 @@ func (ec *executionContext) unmarshalInputLoginInput(ctx context.Context, obj in return it, nil } -func (ec *executionContext) unmarshalInputMagicLinkLoginInput(ctx context.Context, obj interface{}) (model.MagicLinkLoginInput, error) { - var it model.MagicLinkLoginInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputMagicLinkLoginRequest(ctx context.Context, obj any) (model.MagicLinkLoginRequest, error) { + var it model.MagicLinkLoginRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17575,10 +18043,10 @@ func (ec *executionContext) unmarshalInputMagicLinkLoginInput(ctx context.Contex return it, nil } -func (ec *executionContext) unmarshalInputMobileLoginInput(ctx context.Context, obj interface{}) (model.MobileLoginInput, error) { - var it model.MobileLoginInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputMobileLoginRequest(ctx context.Context, obj any) (model.MobileLoginRequest, error) { + var it model.MobileLoginRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17630,10 +18098,10 @@ func (ec *executionContext) unmarshalInputMobileLoginInput(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputMobileSignUpInput(ctx context.Context, obj interface{}) (model.MobileSignUpInput, error) { - var it model.MobileSignUpInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputMobileSignUpRequest(ctx context.Context, obj any) (model.MobileSignUpRequest, error) { + var it model.MobileSignUpRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17769,10 +18237,10 @@ func (ec *executionContext) unmarshalInputMobileSignUpInput(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputOAuthRevokeInput(ctx context.Context, obj interface{}) (model.OAuthRevokeInput, error) { - var it model.OAuthRevokeInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputOAuthRevokeRequest(ctx context.Context, obj any) (model.OAuthRevokeRequest, error) { + var it model.OAuthRevokeRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17796,10 +18264,10 @@ func (ec *executionContext) unmarshalInputOAuthRevokeInput(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputPaginatedInput(ctx context.Context, obj interface{}) (model.PaginatedInput, error) { - var it model.PaginatedInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputPaginatedRequest(ctx context.Context, obj any) (model.PaginatedRequest, error) { + var it model.PaginatedRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17812,7 +18280,7 @@ func (ec *executionContext) unmarshalInputPaginatedInput(ctx context.Context, ob switch k { case "pagination": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("pagination")) - data, err := ec.unmarshalOPaginationInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginationInput(ctx, v) + data, err := ec.unmarshalOPaginationRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPaginationRequest(ctx, v) if err != nil { return it, err } @@ -17823,10 +18291,10 @@ func (ec *executionContext) unmarshalInputPaginatedInput(ctx context.Context, ob return it, nil } -func (ec *executionContext) unmarshalInputPaginationInput(ctx context.Context, obj interface{}) (model.PaginationInput, error) { - var it model.PaginationInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputPaginationRequest(ctx context.Context, obj any) (model.PaginationRequest, error) { + var it model.PaginationRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17857,10 +18325,10 @@ func (ec *executionContext) unmarshalInputPaginationInput(ctx context.Context, o return it, nil } -func (ec *executionContext) unmarshalInputResendOTPRequest(ctx context.Context, obj interface{}) (model.ResendOTPRequest, error) { +func (ec *executionContext) unmarshalInputResendOTPRequest(ctx context.Context, obj any) (model.ResendOTPRequest, error) { var it model.ResendOTPRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17898,10 +18366,10 @@ func (ec *executionContext) unmarshalInputResendOTPRequest(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputResendVerifyEmailInput(ctx context.Context, obj interface{}) (model.ResendVerifyEmailInput, error) { - var it model.ResendVerifyEmailInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputResendVerifyEmailRequest(ctx context.Context, obj any) (model.ResendVerifyEmailRequest, error) { + var it model.ResendVerifyEmailRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17939,10 +18407,10 @@ func (ec *executionContext) unmarshalInputResendVerifyEmailInput(ctx context.Con return it, nil } -func (ec *executionContext) unmarshalInputResetPasswordInput(ctx context.Context, obj interface{}) (model.ResetPasswordInput, error) { - var it model.ResetPasswordInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputResetPasswordRequest(ctx context.Context, obj any) (model.ResetPasswordRequest, error) { + var it model.ResetPasswordRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -17994,10 +18462,10 @@ func (ec *executionContext) unmarshalInputResetPasswordInput(ctx context.Context return it, nil } -func (ec *executionContext) unmarshalInputSessionQueryInput(ctx context.Context, obj interface{}) (model.SessionQueryInput, error) { - var it model.SessionQueryInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputSessionQueryRequest(ctx context.Context, obj any) (model.SessionQueryRequest, error) { + var it model.SessionQueryRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -18028,10 +18496,10 @@ func (ec *executionContext) unmarshalInputSessionQueryInput(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj interface{}) (model.SignUpInput, error) { - var it model.SignUpInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputSignUpRequest(ctx context.Context, obj any) (model.SignUpRequest, error) { + var it model.SignUpRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -18167,10 +18635,10 @@ func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj i return it, nil } -func (ec *executionContext) unmarshalInputTestEndpointRequest(ctx context.Context, obj interface{}) (model.TestEndpointRequest, error) { +func (ec *executionContext) unmarshalInputTestEndpointRequest(ctx context.Context, obj any) (model.TestEndpointRequest, error) { var it model.TestEndpointRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -18215,10 +18683,10 @@ func (ec *executionContext) unmarshalInputTestEndpointRequest(ctx context.Contex return it, nil } -func (ec *executionContext) unmarshalInputUpdateAccessInput(ctx context.Context, obj interface{}) (model.UpdateAccessInput, error) { - var it model.UpdateAccessInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputUpdateAccessRequest(ctx context.Context, obj any) (model.UpdateAccessRequest, error) { + var it model.UpdateAccessRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -18242,10 +18710,10 @@ func (ec *executionContext) unmarshalInputUpdateAccessInput(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputUpdateEmailTemplateRequest(ctx context.Context, obj interface{}) (model.UpdateEmailTemplateRequest, error) { +func (ec *executionContext) unmarshalInputUpdateEmailTemplateRequest(ctx context.Context, obj any) (model.UpdateEmailTemplateRequest, error) { var it model.UpdateEmailTemplateRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -18297,10 +18765,10 @@ func (ec *executionContext) unmarshalInputUpdateEmailTemplateRequest(ctx context return it, nil } -func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, obj interface{}) (model.UpdateEnvInput, error) { - var it model.UpdateEnvInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputUpdateEnvRequest(ctx context.Context, obj any) (model.UpdateEnvRequest, error) { + var it model.UpdateEnvRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -18751,10 +19219,10 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob return it, nil } -func (ec *executionContext) unmarshalInputUpdateProfileInput(ctx context.Context, obj interface{}) (model.UpdateProfileInput, error) { - var it model.UpdateProfileInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputUpdateProfileRequest(ctx context.Context, obj any) (model.UpdateProfileRequest, error) { + var it model.UpdateProfileRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -18869,10 +19337,10 @@ func (ec *executionContext) unmarshalInputUpdateProfileInput(ctx context.Context return it, nil } -func (ec *executionContext) unmarshalInputUpdateUserInput(ctx context.Context, obj interface{}) (model.UpdateUserInput, error) { - var it model.UpdateUserInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputUpdateUserRequest(ctx context.Context, obj any) (model.UpdateUserRequest, error) { + var it model.UpdateUserRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -18994,10 +19462,10 @@ func (ec *executionContext) unmarshalInputUpdateUserInput(ctx context.Context, o return it, nil } -func (ec *executionContext) unmarshalInputUpdateWebhookRequest(ctx context.Context, obj interface{}) (model.UpdateWebhookRequest, error) { +func (ec *executionContext) unmarshalInputUpdateWebhookRequest(ctx context.Context, obj any) (model.UpdateWebhookRequest, error) { var it model.UpdateWebhookRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -19056,10 +19524,10 @@ func (ec *executionContext) unmarshalInputUpdateWebhookRequest(ctx context.Conte return it, nil } -func (ec *executionContext) unmarshalInputValidateJWTTokenInput(ctx context.Context, obj interface{}) (model.ValidateJWTTokenInput, error) { - var it model.ValidateJWTTokenInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputValidateJWTTokenRequest(ctx context.Context, obj any) (model.ValidateJWTTokenRequest, error) { + var it model.ValidateJWTTokenRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -19097,10 +19565,10 @@ func (ec *executionContext) unmarshalInputValidateJWTTokenInput(ctx context.Cont return it, nil } -func (ec *executionContext) unmarshalInputValidateSessionInput(ctx context.Context, obj interface{}) (model.ValidateSessionInput, error) { - var it model.ValidateSessionInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputValidateSessionRequest(ctx context.Context, obj any) (model.ValidateSessionRequest, error) { + var it model.ValidateSessionRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -19131,10 +19599,10 @@ func (ec *executionContext) unmarshalInputValidateSessionInput(ctx context.Conte return it, nil } -func (ec *executionContext) unmarshalInputVerifyEmailInput(ctx context.Context, obj interface{}) (model.VerifyEmailInput, error) { - var it model.VerifyEmailInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { +func (ec *executionContext) unmarshalInputVerifyEmailRequest(ctx context.Context, obj any) (model.VerifyEmailRequest, error) { + var it model.VerifyEmailRequest + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -19165,10 +19633,10 @@ func (ec *executionContext) unmarshalInputVerifyEmailInput(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context, obj interface{}) (model.VerifyOTPRequest, error) { +func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context, obj any) (model.VerifyOTPRequest, error) { var it model.VerifyOTPRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -19220,10 +19688,10 @@ func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputWebhookRequest(ctx context.Context, obj interface{}) (model.WebhookRequest, error) { +func (ec *executionContext) unmarshalInputWebhookRequest(ctx context.Context, obj any) (model.WebhookRequest, error) { var it model.WebhookRequest - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -20670,67 +21138,6 @@ func (ec *executionContext) _Response(ctx context.Context, sel ast.SelectionSet, return out } -var sMSVerificationRequestsImplementors = []string{"SMSVerificationRequests"} - -func (ec *executionContext) _SMSVerificationRequests(ctx context.Context, sel ast.SelectionSet, obj *model.SMSVerificationRequests) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, sMSVerificationRequestsImplementors) - - out := graphql.NewFieldSet(fields) - deferred := make(map[string]*graphql.FieldSet) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("SMSVerificationRequests") - case "id": - out.Values[i] = ec._SMSVerificationRequests_id(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "code": - out.Values[i] = ec._SMSVerificationRequests_code(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "code_expires_at": - out.Values[i] = ec._SMSVerificationRequests_code_expires_at(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "phone_number": - out.Values[i] = ec._SMSVerificationRequests_phone_number(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "created_at": - out.Values[i] = ec._SMSVerificationRequests_created_at(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "updated_at": - out.Values[i] = ec._SMSVerificationRequests_updated_at(ctx, field, obj) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.deferred, int32(len(deferred))) - - for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ - Label: label, - Path: graphql.GetPath(ctx), - FieldSet: dfs, - Context: ctx, - }) - } - - return out -} - var testEndpointResponseImplementors = []string{"TestEndpointResponse"} func (ec *executionContext) _TestEndpointResponse(ctx context.Context, sel ast.SelectionSet, obj *model.TestEndpointResponse) graphql.Marshaler { @@ -20815,6 +21222,9 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj out.Values[i] = ec._User_phone_number(ctx, field, obj) case "phone_number_verified": out.Values[i] = ec._User_phone_number_verified(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "picture": out.Values[i] = ec._User_picture(ctx, field, obj) case "roles": @@ -21293,6 +21703,11 @@ func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionS } case "description": out.Values[i] = ec.___Directive_description(ctx, field, obj) + case "isRepeatable": + out.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "locations": out.Values[i] = ec.___Directive_locations(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -21303,11 +21718,6 @@ func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionS if out.Values[i] == graphql.Null { out.Invalids++ } - case "isRepeatable": - out.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -21462,6 +21872,13 @@ func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.Selection } case "defaultValue": out.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj) + case "isDeprecated": + out.Values[i] = ec.___InputValue_isDeprecated(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "deprecationReason": + out.Values[i] = ec.___InputValue_deprecationReason(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -21560,6 +21977,8 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o out.Values[i] = ec.___Type_name(ctx, field, obj) case "description": out.Values[i] = ec.___Type_description(ctx, field, obj) + case "specifiedByURL": + out.Values[i] = ec.___Type_specifiedByURL(ctx, field, obj) case "fields": out.Values[i] = ec.___Type_fields(ctx, field, obj) case "interfaces": @@ -21572,8 +21991,8 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o out.Values[i] = ec.___Type_inputFields(ctx, field, obj) case "ofType": out.Values[i] = ec.___Type_ofType(ctx, field, obj) - case "specifiedByURL": - out.Values[i] = ec.___Type_specifiedByURL(ctx, field, obj) + case "isOneOf": + out.Values[i] = ec.___Type_isOneOf(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -21601,31 +22020,31 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o // region ***************************** type.gotpl ***************************** -func (ec *executionContext) unmarshalNAddEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAddEmailTemplateRequest(ctx context.Context, v interface{}) (model.AddEmailTemplateRequest, error) { +func (ec *executionContext) unmarshalNAddEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAddEmailTemplateRequest(ctx context.Context, v any) (model.AddEmailTemplateRequest, error) { res, err := ec.unmarshalInputAddEmailTemplateRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNAddWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAddWebhookRequest(ctx context.Context, v interface{}) (model.AddWebhookRequest, error) { +func (ec *executionContext) unmarshalNAddWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAddWebhookRequest(ctx context.Context, v any) (model.AddWebhookRequest, error) { res, err := ec.unmarshalInputAddWebhookRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNAdminLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminLoginInput(ctx context.Context, v interface{}) (model.AdminLoginInput, error) { - res, err := ec.unmarshalInputAdminLoginInput(ctx, v) +func (ec *executionContext) unmarshalNAdminLoginRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAdminLoginRequest(ctx context.Context, v any) (model.AdminLoginRequest, error) { + res, err := ec.unmarshalInputAdminLoginRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNAdminSignupInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminSignupInput(ctx context.Context, v interface{}) (model.AdminSignupInput, error) { - res, err := ec.unmarshalInputAdminSignupInput(ctx, v) +func (ec *executionContext) unmarshalNAdminSignupRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAdminSignupRequest(ctx context.Context, v any) (model.AdminSignupRequest, error) { + res, err := ec.unmarshalInputAdminSignupRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNAuthResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx context.Context, sel ast.SelectionSet, v model.AuthResponse) graphql.Marshaler { +func (ec *executionContext) marshalNAuthResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAuthResponse(ctx context.Context, sel ast.SelectionSet, v model.AuthResponse) graphql.Marshaler { return ec._AuthResponse(ctx, sel, &v) } -func (ec *executionContext) marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx context.Context, sel ast.SelectionSet, v *model.AuthResponse) graphql.Marshaler { +func (ec *executionContext) marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐAuthResponse(ctx context.Context, sel ast.SelectionSet, v *model.AuthResponse) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -21635,12 +22054,13 @@ func (ec *executionContext) marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdev return ec._AuthResponse(ctx, sel, v) } -func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { +func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v any) (bool, error) { res, err := graphql.UnmarshalBoolean(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { + _ = sel res := graphql.MarshalBoolean(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -21650,17 +22070,17 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se return res } -func (ec *executionContext) unmarshalNDeleteEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐDeleteEmailTemplateRequest(ctx context.Context, v interface{}) (model.DeleteEmailTemplateRequest, error) { +func (ec *executionContext) unmarshalNDeleteEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐDeleteEmailTemplateRequest(ctx context.Context, v any) (model.DeleteEmailTemplateRequest, error) { res, err := ec.unmarshalInputDeleteEmailTemplateRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNDeleteUserInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐDeleteUserInput(ctx context.Context, v interface{}) (model.DeleteUserInput, error) { - res, err := ec.unmarshalInputDeleteUserInput(ctx, v) +func (ec *executionContext) unmarshalNDeleteUserRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐDeleteUserRequest(ctx context.Context, v any) (model.DeleteUserRequest, error) { + res, err := ec.unmarshalInputDeleteUserRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNEmailTemplate2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐEmailTemplateᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.EmailTemplate) graphql.Marshaler { +func (ec *executionContext) marshalNEmailTemplate2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐEmailTemplateᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.EmailTemplate) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -21684,7 +22104,7 @@ func (ec *executionContext) marshalNEmailTemplate2ᚕᚖgithubᚗcomᚋauthorize if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNEmailTemplate2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐEmailTemplate(ctx, sel, v[i]) + ret[i] = ec.marshalNEmailTemplate2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐEmailTemplate(ctx, sel, v[i]) } if isLen1 { f(i) @@ -21704,7 +22124,7 @@ func (ec *executionContext) marshalNEmailTemplate2ᚕᚖgithubᚗcomᚋauthorize return ret } -func (ec *executionContext) marshalNEmailTemplate2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐEmailTemplate(ctx context.Context, sel ast.SelectionSet, v *model.EmailTemplate) graphql.Marshaler { +func (ec *executionContext) marshalNEmailTemplate2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐEmailTemplate(ctx context.Context, sel ast.SelectionSet, v *model.EmailTemplate) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -21714,11 +22134,11 @@ func (ec *executionContext) marshalNEmailTemplate2ᚖgithubᚗcomᚋauthorizerde return ec._EmailTemplate(ctx, sel, v) } -func (ec *executionContext) marshalNEmailTemplates2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐEmailTemplates(ctx context.Context, sel ast.SelectionSet, v model.EmailTemplates) graphql.Marshaler { +func (ec *executionContext) marshalNEmailTemplates2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐEmailTemplates(ctx context.Context, sel ast.SelectionSet, v model.EmailTemplates) graphql.Marshaler { return ec._EmailTemplates(ctx, sel, &v) } -func (ec *executionContext) marshalNEmailTemplates2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐEmailTemplates(ctx context.Context, sel ast.SelectionSet, v *model.EmailTemplates) graphql.Marshaler { +func (ec *executionContext) marshalNEmailTemplates2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐEmailTemplates(ctx context.Context, sel ast.SelectionSet, v *model.EmailTemplates) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -21728,11 +22148,11 @@ func (ec *executionContext) marshalNEmailTemplates2ᚖgithubᚗcomᚋauthorizerd return ec._EmailTemplates(ctx, sel, v) } -func (ec *executionContext) marshalNEnv2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐEnv(ctx context.Context, sel ast.SelectionSet, v model.Env) graphql.Marshaler { +func (ec *executionContext) marshalNEnv2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐEnv(ctx context.Context, sel ast.SelectionSet, v model.Env) graphql.Marshaler { return ec._Env(ctx, sel, &v) } -func (ec *executionContext) marshalNEnv2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐEnv(ctx context.Context, sel ast.SelectionSet, v *model.Env) graphql.Marshaler { +func (ec *executionContext) marshalNEnv2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐEnv(ctx context.Context, sel ast.SelectionSet, v *model.Env) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -21742,16 +22162,16 @@ func (ec *executionContext) marshalNEnv2ᚖgithubᚗcomᚋauthorizerdevᚋauthor return ec._Env(ctx, sel, v) } -func (ec *executionContext) unmarshalNForgotPasswordInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐForgotPasswordInput(ctx context.Context, v interface{}) (model.ForgotPasswordInput, error) { - res, err := ec.unmarshalInputForgotPasswordInput(ctx, v) +func (ec *executionContext) unmarshalNForgotPasswordRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐForgotPasswordRequest(ctx context.Context, v any) (model.ForgotPasswordRequest, error) { + res, err := ec.unmarshalInputForgotPasswordRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNForgotPasswordResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐForgotPasswordResponse(ctx context.Context, sel ast.SelectionSet, v model.ForgotPasswordResponse) graphql.Marshaler { +func (ec *executionContext) marshalNForgotPasswordResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐForgotPasswordResponse(ctx context.Context, sel ast.SelectionSet, v model.ForgotPasswordResponse) graphql.Marshaler { return ec._ForgotPasswordResponse(ctx, sel, &v) } -func (ec *executionContext) marshalNForgotPasswordResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐForgotPasswordResponse(ctx context.Context, sel ast.SelectionSet, v *model.ForgotPasswordResponse) graphql.Marshaler { +func (ec *executionContext) marshalNForgotPasswordResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐForgotPasswordResponse(ctx context.Context, sel ast.SelectionSet, v *model.ForgotPasswordResponse) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -21761,16 +22181,16 @@ func (ec *executionContext) marshalNForgotPasswordResponse2ᚖgithubᚗcomᚋaut return ec._ForgotPasswordResponse(ctx, sel, v) } -func (ec *executionContext) unmarshalNGenerateJWTKeysInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐGenerateJWTKeysInput(ctx context.Context, v interface{}) (model.GenerateJWTKeysInput, error) { - res, err := ec.unmarshalInputGenerateJWTKeysInput(ctx, v) +func (ec *executionContext) unmarshalNGenerateJWTKeysRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐGenerateJWTKeysRequest(ctx context.Context, v any) (model.GenerateJWTKeysRequest, error) { + res, err := ec.unmarshalInputGenerateJWTKeysRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNGenerateJWTKeysResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐGenerateJWTKeysResponse(ctx context.Context, sel ast.SelectionSet, v model.GenerateJWTKeysResponse) graphql.Marshaler { +func (ec *executionContext) marshalNGenerateJWTKeysResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐGenerateJWTKeysResponse(ctx context.Context, sel ast.SelectionSet, v model.GenerateJWTKeysResponse) graphql.Marshaler { return ec._GenerateJWTKeysResponse(ctx, sel, &v) } -func (ec *executionContext) marshalNGenerateJWTKeysResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐGenerateJWTKeysResponse(ctx context.Context, sel ast.SelectionSet, v *model.GenerateJWTKeysResponse) graphql.Marshaler { +func (ec *executionContext) marshalNGenerateJWTKeysResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐGenerateJWTKeysResponse(ctx context.Context, sel ast.SelectionSet, v *model.GenerateJWTKeysResponse) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -21780,17 +22200,18 @@ func (ec *executionContext) marshalNGenerateJWTKeysResponse2ᚖgithubᚗcomᚋau return ec._GenerateJWTKeysResponse(ctx, sel, v) } -func (ec *executionContext) unmarshalNGetUserRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐGetUserRequest(ctx context.Context, v interface{}) (model.GetUserRequest, error) { +func (ec *executionContext) unmarshalNGetUserRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐGetUserRequest(ctx context.Context, v any) (model.GetUserRequest, error) { res, err := ec.unmarshalInputGetUserRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNID2string(ctx context.Context, v interface{}) (string, error) { +func (ec *executionContext) unmarshalNID2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalID(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + _ = sel res := graphql.MarshalID(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -21800,12 +22221,13 @@ func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.Selec return res } -func (ec *executionContext) unmarshalNInt642int64(ctx context.Context, v interface{}) (int64, error) { +func (ec *executionContext) unmarshalNInt642int64(ctx context.Context, v any) (int64, error) { res, err := graphql.UnmarshalInt64(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNInt642int64(ctx context.Context, sel ast.SelectionSet, v int64) graphql.Marshaler { + _ = sel res := graphql.MarshalInt64(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -21815,16 +22237,16 @@ func (ec *executionContext) marshalNInt642int64(ctx context.Context, sel ast.Sel return res } -func (ec *executionContext) unmarshalNInviteMemberInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐInviteMemberInput(ctx context.Context, v interface{}) (model.InviteMemberInput, error) { - res, err := ec.unmarshalInputInviteMemberInput(ctx, v) +func (ec *executionContext) unmarshalNInviteMemberRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐInviteMemberRequest(ctx context.Context, v any) (model.InviteMemberRequest, error) { + res, err := ec.unmarshalInputInviteMemberRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNInviteMembersResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐInviteMembersResponse(ctx context.Context, sel ast.SelectionSet, v model.InviteMembersResponse) graphql.Marshaler { +func (ec *executionContext) marshalNInviteMembersResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐInviteMembersResponse(ctx context.Context, sel ast.SelectionSet, v model.InviteMembersResponse) graphql.Marshaler { return ec._InviteMembersResponse(ctx, sel, &v) } -func (ec *executionContext) marshalNInviteMembersResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐInviteMembersResponse(ctx context.Context, sel ast.SelectionSet, v *model.InviteMembersResponse) graphql.Marshaler { +func (ec *executionContext) marshalNInviteMembersResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐInviteMembersResponse(ctx context.Context, sel ast.SelectionSet, v *model.InviteMembersResponse) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -21834,21 +22256,21 @@ func (ec *executionContext) marshalNInviteMembersResponse2ᚖgithubᚗcomᚋauth return ec._InviteMembersResponse(ctx, sel, v) } -func (ec *executionContext) unmarshalNLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐLoginInput(ctx context.Context, v interface{}) (model.LoginInput, error) { - res, err := ec.unmarshalInputLoginInput(ctx, v) +func (ec *executionContext) unmarshalNLoginRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐLoginRequest(ctx context.Context, v any) (model.LoginRequest, error) { + res, err := ec.unmarshalInputLoginRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNMagicLinkLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMagicLinkLoginInput(ctx context.Context, v interface{}) (model.MagicLinkLoginInput, error) { - res, err := ec.unmarshalInputMagicLinkLoginInput(ctx, v) +func (ec *executionContext) unmarshalNMagicLinkLoginRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐMagicLinkLoginRequest(ctx context.Context, v any) (model.MagicLinkLoginRequest, error) { + res, err := ec.unmarshalInputMagicLinkLoginRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNMeta2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMeta(ctx context.Context, sel ast.SelectionSet, v model.Meta) graphql.Marshaler { +func (ec *executionContext) marshalNMeta2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐMeta(ctx context.Context, sel ast.SelectionSet, v model.Meta) graphql.Marshaler { return ec._Meta(ctx, sel, &v) } -func (ec *executionContext) marshalNMeta2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMeta(ctx context.Context, sel ast.SelectionSet, v *model.Meta) graphql.Marshaler { +func (ec *executionContext) marshalNMeta2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐMeta(ctx context.Context, sel ast.SelectionSet, v *model.Meta) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -21858,17 +22280,17 @@ func (ec *executionContext) marshalNMeta2ᚖgithubᚗcomᚋauthorizerdevᚋautho return ec._Meta(ctx, sel, v) } -func (ec *executionContext) unmarshalNMobileLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileLoginInput(ctx context.Context, v interface{}) (model.MobileLoginInput, error) { - res, err := ec.unmarshalInputMobileLoginInput(ctx, v) +func (ec *executionContext) unmarshalNMobileLoginRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐMobileLoginRequest(ctx context.Context, v any) (model.MobileLoginRequest, error) { + res, err := ec.unmarshalInputMobileLoginRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNOAuthRevokeInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐOAuthRevokeInput(ctx context.Context, v interface{}) (model.OAuthRevokeInput, error) { - res, err := ec.unmarshalInputOAuthRevokeInput(ctx, v) +func (ec *executionContext) unmarshalNOAuthRevokeRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐOAuthRevokeRequest(ctx context.Context, v any) (model.OAuthRevokeRequest, error) { + res, err := ec.unmarshalInputOAuthRevokeRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPagination(ctx context.Context, sel ast.SelectionSet, v *model.Pagination) graphql.Marshaler { +func (ec *executionContext) marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPagination(ctx context.Context, sel ast.SelectionSet, v *model.Pagination) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -21878,26 +22300,26 @@ func (ec *executionContext) marshalNPagination2ᚖgithubᚗcomᚋauthorizerdev return ec._Pagination(ctx, sel, v) } -func (ec *executionContext) unmarshalNResendOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResendOTPRequest(ctx context.Context, v interface{}) (model.ResendOTPRequest, error) { +func (ec *executionContext) unmarshalNResendOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResendOTPRequest(ctx context.Context, v any) (model.ResendOTPRequest, error) { res, err := ec.unmarshalInputResendOTPRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNResendVerifyEmailInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResendVerifyEmailInput(ctx context.Context, v interface{}) (model.ResendVerifyEmailInput, error) { - res, err := ec.unmarshalInputResendVerifyEmailInput(ctx, v) +func (ec *executionContext) unmarshalNResendVerifyEmailRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResendVerifyEmailRequest(ctx context.Context, v any) (model.ResendVerifyEmailRequest, error) { + res, err := ec.unmarshalInputResendVerifyEmailRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNResetPasswordInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResetPasswordInput(ctx context.Context, v interface{}) (model.ResetPasswordInput, error) { - res, err := ec.unmarshalInputResetPasswordInput(ctx, v) +func (ec *executionContext) unmarshalNResetPasswordRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResetPasswordRequest(ctx context.Context, v any) (model.ResetPasswordRequest, error) { + res, err := ec.unmarshalInputResetPasswordRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx context.Context, sel ast.SelectionSet, v model.Response) graphql.Marshaler { +func (ec *executionContext) marshalNResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx context.Context, sel ast.SelectionSet, v model.Response) graphql.Marshaler { return ec._Response(ctx, sel, &v) } -func (ec *executionContext) marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx context.Context, sel ast.SelectionSet, v *model.Response) graphql.Marshaler { +func (ec *executionContext) marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐResponse(ctx context.Context, sel ast.SelectionSet, v *model.Response) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -21907,17 +22329,18 @@ func (ec *executionContext) marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋa return ec._Response(ctx, sel, v) } -func (ec *executionContext) unmarshalNSignUpInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐSignUpInput(ctx context.Context, v interface{}) (model.SignUpInput, error) { - res, err := ec.unmarshalInputSignUpInput(ctx, v) +func (ec *executionContext) unmarshalNSignUpRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐSignUpRequest(ctx context.Context, v any) (model.SignUpRequest, error) { + res, err := ec.unmarshalInputSignUpRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { +func (ec *executionContext) unmarshalNString2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + _ = sel res := graphql.MarshalString(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -21927,11 +22350,9 @@ func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.S return res } -func (ec *executionContext) unmarshalNString2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } +func (ec *executionContext) unmarshalNString2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) { + var vSlice []any + vSlice = graphql.CoerceList(v) var err error res := make([]string, len(vSlice)) for i := range vSlice { @@ -21959,16 +22380,16 @@ func (ec *executionContext) marshalNString2ᚕstringᚄ(ctx context.Context, sel return ret } -func (ec *executionContext) unmarshalNTestEndpointRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐTestEndpointRequest(ctx context.Context, v interface{}) (model.TestEndpointRequest, error) { +func (ec *executionContext) unmarshalNTestEndpointRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐTestEndpointRequest(ctx context.Context, v any) (model.TestEndpointRequest, error) { res, err := ec.unmarshalInputTestEndpointRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNTestEndpointResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐTestEndpointResponse(ctx context.Context, sel ast.SelectionSet, v model.TestEndpointResponse) graphql.Marshaler { +func (ec *executionContext) marshalNTestEndpointResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐTestEndpointResponse(ctx context.Context, sel ast.SelectionSet, v model.TestEndpointResponse) graphql.Marshaler { return ec._TestEndpointResponse(ctx, sel, &v) } -func (ec *executionContext) marshalNTestEndpointResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐTestEndpointResponse(ctx context.Context, sel ast.SelectionSet, v *model.TestEndpointResponse) graphql.Marshaler { +func (ec *executionContext) marshalNTestEndpointResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐTestEndpointResponse(ctx context.Context, sel ast.SelectionSet, v *model.TestEndpointResponse) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -21978,41 +22399,41 @@ func (ec *executionContext) marshalNTestEndpointResponse2ᚖgithubᚗcomᚋautho return ec._TestEndpointResponse(ctx, sel, v) } -func (ec *executionContext) unmarshalNUpdateAccessInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateAccessInput(ctx context.Context, v interface{}) (model.UpdateAccessInput, error) { - res, err := ec.unmarshalInputUpdateAccessInput(ctx, v) +func (ec *executionContext) unmarshalNUpdateAccessRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateAccessRequest(ctx context.Context, v any) (model.UpdateAccessRequest, error) { + res, err := ec.unmarshalInputUpdateAccessRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNUpdateEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateEmailTemplateRequest(ctx context.Context, v interface{}) (model.UpdateEmailTemplateRequest, error) { +func (ec *executionContext) unmarshalNUpdateEmailTemplateRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateEmailTemplateRequest(ctx context.Context, v any) (model.UpdateEmailTemplateRequest, error) { res, err := ec.unmarshalInputUpdateEmailTemplateRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNUpdateEnvInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateEnvInput(ctx context.Context, v interface{}) (model.UpdateEnvInput, error) { - res, err := ec.unmarshalInputUpdateEnvInput(ctx, v) +func (ec *executionContext) unmarshalNUpdateEnvRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateEnvRequest(ctx context.Context, v any) (model.UpdateEnvRequest, error) { + res, err := ec.unmarshalInputUpdateEnvRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNUpdateProfileInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateProfileInput(ctx context.Context, v interface{}) (model.UpdateProfileInput, error) { - res, err := ec.unmarshalInputUpdateProfileInput(ctx, v) +func (ec *executionContext) unmarshalNUpdateProfileRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateProfileRequest(ctx context.Context, v any) (model.UpdateProfileRequest, error) { + res, err := ec.unmarshalInputUpdateProfileRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNUpdateUserInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateUserInput(ctx context.Context, v interface{}) (model.UpdateUserInput, error) { - res, err := ec.unmarshalInputUpdateUserInput(ctx, v) +func (ec *executionContext) unmarshalNUpdateUserRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateUserRequest(ctx context.Context, v any) (model.UpdateUserRequest, error) { + res, err := ec.unmarshalInputUpdateUserRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNUpdateWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateWebhookRequest(ctx context.Context, v interface{}) (model.UpdateWebhookRequest, error) { +func (ec *executionContext) unmarshalNUpdateWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUpdateWebhookRequest(ctx context.Context, v any) (model.UpdateWebhookRequest, error) { res, err := ec.unmarshalInputUpdateWebhookRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNUser2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v model.User) graphql.Marshaler { +func (ec *executionContext) marshalNUser2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v model.User) graphql.Marshaler { return ec._User(ctx, sel, &v) } -func (ec *executionContext) marshalNUser2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUserᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.User) graphql.Marshaler { +func (ec *executionContext) marshalNUser2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUserᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.User) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -22036,7 +22457,7 @@ func (ec *executionContext) marshalNUser2ᚕᚖgithubᚗcomᚋauthorizerdevᚋau if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, sel, v[i]) + ret[i] = ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUser(ctx, sel, v[i]) } if isLen1 { f(i) @@ -22056,7 +22477,7 @@ func (ec *executionContext) marshalNUser2ᚕᚖgithubᚗcomᚋauthorizerdevᚋau return ret } -func (ec *executionContext) marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v *model.User) graphql.Marshaler { +func (ec *executionContext) marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v *model.User) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -22066,11 +22487,11 @@ func (ec *executionContext) marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋautho return ec._User(ctx, sel, v) } -func (ec *executionContext) marshalNUsers2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUsers(ctx context.Context, sel ast.SelectionSet, v model.Users) graphql.Marshaler { +func (ec *executionContext) marshalNUsers2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUsers(ctx context.Context, sel ast.SelectionSet, v model.Users) graphql.Marshaler { return ec._Users(ctx, sel, &v) } -func (ec *executionContext) marshalNUsers2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUsers(ctx context.Context, sel ast.SelectionSet, v *model.Users) graphql.Marshaler { +func (ec *executionContext) marshalNUsers2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUsers(ctx context.Context, sel ast.SelectionSet, v *model.Users) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -22080,16 +22501,16 @@ func (ec *executionContext) marshalNUsers2ᚖgithubᚗcomᚋauthorizerdevᚋauth return ec._Users(ctx, sel, v) } -func (ec *executionContext) unmarshalNValidateJWTTokenInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateJWTTokenInput(ctx context.Context, v interface{}) (model.ValidateJWTTokenInput, error) { - res, err := ec.unmarshalInputValidateJWTTokenInput(ctx, v) +func (ec *executionContext) unmarshalNValidateJWTTokenRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐValidateJWTTokenRequest(ctx context.Context, v any) (model.ValidateJWTTokenRequest, error) { + res, err := ec.unmarshalInputValidateJWTTokenRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNValidateJWTTokenResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateJWTTokenResponse(ctx context.Context, sel ast.SelectionSet, v model.ValidateJWTTokenResponse) graphql.Marshaler { +func (ec *executionContext) marshalNValidateJWTTokenResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐValidateJWTTokenResponse(ctx context.Context, sel ast.SelectionSet, v model.ValidateJWTTokenResponse) graphql.Marshaler { return ec._ValidateJWTTokenResponse(ctx, sel, &v) } -func (ec *executionContext) marshalNValidateJWTTokenResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateJWTTokenResponse(ctx context.Context, sel ast.SelectionSet, v *model.ValidateJWTTokenResponse) graphql.Marshaler { +func (ec *executionContext) marshalNValidateJWTTokenResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐValidateJWTTokenResponse(ctx context.Context, sel ast.SelectionSet, v *model.ValidateJWTTokenResponse) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -22099,11 +22520,11 @@ func (ec *executionContext) marshalNValidateJWTTokenResponse2ᚖgithubᚗcomᚋa return ec._ValidateJWTTokenResponse(ctx, sel, v) } -func (ec *executionContext) marshalNValidateSessionResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateSessionResponse(ctx context.Context, sel ast.SelectionSet, v model.ValidateSessionResponse) graphql.Marshaler { +func (ec *executionContext) marshalNValidateSessionResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐValidateSessionResponse(ctx context.Context, sel ast.SelectionSet, v model.ValidateSessionResponse) graphql.Marshaler { return ec._ValidateSessionResponse(ctx, sel, &v) } -func (ec *executionContext) marshalNValidateSessionResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateSessionResponse(ctx context.Context, sel ast.SelectionSet, v *model.ValidateSessionResponse) graphql.Marshaler { +func (ec *executionContext) marshalNValidateSessionResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐValidateSessionResponse(ctx context.Context, sel ast.SelectionSet, v *model.ValidateSessionResponse) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -22113,7 +22534,7 @@ func (ec *executionContext) marshalNValidateSessionResponse2ᚖgithubᚗcomᚋau return ec._ValidateSessionResponse(ctx, sel, v) } -func (ec *executionContext) marshalNVerificationRequest2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerificationRequestᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.VerificationRequest) graphql.Marshaler { +func (ec *executionContext) marshalNVerificationRequest2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐVerificationRequestᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.VerificationRequest) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -22137,7 +22558,7 @@ func (ec *executionContext) marshalNVerificationRequest2ᚕᚖgithubᚗcomᚋaut if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNVerificationRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerificationRequest(ctx, sel, v[i]) + ret[i] = ec.marshalNVerificationRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐVerificationRequest(ctx, sel, v[i]) } if isLen1 { f(i) @@ -22157,7 +22578,7 @@ func (ec *executionContext) marshalNVerificationRequest2ᚕᚖgithubᚗcomᚋaut return ret } -func (ec *executionContext) marshalNVerificationRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerificationRequest(ctx context.Context, sel ast.SelectionSet, v *model.VerificationRequest) graphql.Marshaler { +func (ec *executionContext) marshalNVerificationRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐVerificationRequest(ctx context.Context, sel ast.SelectionSet, v *model.VerificationRequest) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -22167,11 +22588,11 @@ func (ec *executionContext) marshalNVerificationRequest2ᚖgithubᚗcomᚋauthor return ec._VerificationRequest(ctx, sel, v) } -func (ec *executionContext) marshalNVerificationRequests2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerificationRequests(ctx context.Context, sel ast.SelectionSet, v model.VerificationRequests) graphql.Marshaler { +func (ec *executionContext) marshalNVerificationRequests2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐVerificationRequests(ctx context.Context, sel ast.SelectionSet, v model.VerificationRequests) graphql.Marshaler { return ec._VerificationRequests(ctx, sel, &v) } -func (ec *executionContext) marshalNVerificationRequests2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerificationRequests(ctx context.Context, sel ast.SelectionSet, v *model.VerificationRequests) graphql.Marshaler { +func (ec *executionContext) marshalNVerificationRequests2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐVerificationRequests(ctx context.Context, sel ast.SelectionSet, v *model.VerificationRequests) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -22181,21 +22602,21 @@ func (ec *executionContext) marshalNVerificationRequests2ᚖgithubᚗcomᚋautho return ec._VerificationRequests(ctx, sel, v) } -func (ec *executionContext) unmarshalNVerifyEmailInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerifyEmailInput(ctx context.Context, v interface{}) (model.VerifyEmailInput, error) { - res, err := ec.unmarshalInputVerifyEmailInput(ctx, v) +func (ec *executionContext) unmarshalNVerifyEmailRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐVerifyEmailRequest(ctx context.Context, v any) (model.VerifyEmailRequest, error) { + res, err := ec.unmarshalInputVerifyEmailRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNVerifyOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerifyOTPRequest(ctx context.Context, v interface{}) (model.VerifyOTPRequest, error) { +func (ec *executionContext) unmarshalNVerifyOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐVerifyOTPRequest(ctx context.Context, v any) (model.VerifyOTPRequest, error) { res, err := ec.unmarshalInputVerifyOTPRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNWebhook2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhook(ctx context.Context, sel ast.SelectionSet, v model.Webhook) graphql.Marshaler { +func (ec *executionContext) marshalNWebhook2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhook(ctx context.Context, sel ast.SelectionSet, v model.Webhook) graphql.Marshaler { return ec._Webhook(ctx, sel, &v) } -func (ec *executionContext) marshalNWebhook2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Webhook) graphql.Marshaler { +func (ec *executionContext) marshalNWebhook2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Webhook) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -22219,7 +22640,7 @@ func (ec *executionContext) marshalNWebhook2ᚕᚖgithubᚗcomᚋauthorizerdev if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNWebhook2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhook(ctx, sel, v[i]) + ret[i] = ec.marshalNWebhook2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhook(ctx, sel, v[i]) } if isLen1 { f(i) @@ -22239,7 +22660,7 @@ func (ec *executionContext) marshalNWebhook2ᚕᚖgithubᚗcomᚋauthorizerdev return ret } -func (ec *executionContext) marshalNWebhook2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhook(ctx context.Context, sel ast.SelectionSet, v *model.Webhook) graphql.Marshaler { +func (ec *executionContext) marshalNWebhook2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhook(ctx context.Context, sel ast.SelectionSet, v *model.Webhook) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -22249,7 +22670,7 @@ func (ec *executionContext) marshalNWebhook2ᚖgithubᚗcomᚋauthorizerdevᚋau return ec._Webhook(ctx, sel, v) } -func (ec *executionContext) marshalNWebhookLog2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookLogᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.WebhookLog) graphql.Marshaler { +func (ec *executionContext) marshalNWebhookLog2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookLogᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.WebhookLog) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -22273,7 +22694,7 @@ func (ec *executionContext) marshalNWebhookLog2ᚕᚖgithubᚗcomᚋauthorizerde if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNWebhookLog2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookLog(ctx, sel, v[i]) + ret[i] = ec.marshalNWebhookLog2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookLog(ctx, sel, v[i]) } if isLen1 { f(i) @@ -22293,7 +22714,7 @@ func (ec *executionContext) marshalNWebhookLog2ᚕᚖgithubᚗcomᚋauthorizerde return ret } -func (ec *executionContext) marshalNWebhookLog2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookLog(ctx context.Context, sel ast.SelectionSet, v *model.WebhookLog) graphql.Marshaler { +func (ec *executionContext) marshalNWebhookLog2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookLog(ctx context.Context, sel ast.SelectionSet, v *model.WebhookLog) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -22303,11 +22724,11 @@ func (ec *executionContext) marshalNWebhookLog2ᚖgithubᚗcomᚋauthorizerdev return ec._WebhookLog(ctx, sel, v) } -func (ec *executionContext) marshalNWebhookLogs2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookLogs(ctx context.Context, sel ast.SelectionSet, v model.WebhookLogs) graphql.Marshaler { +func (ec *executionContext) marshalNWebhookLogs2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookLogs(ctx context.Context, sel ast.SelectionSet, v model.WebhookLogs) graphql.Marshaler { return ec._WebhookLogs(ctx, sel, &v) } -func (ec *executionContext) marshalNWebhookLogs2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookLogs(ctx context.Context, sel ast.SelectionSet, v *model.WebhookLogs) graphql.Marshaler { +func (ec *executionContext) marshalNWebhookLogs2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookLogs(ctx context.Context, sel ast.SelectionSet, v *model.WebhookLogs) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -22317,16 +22738,16 @@ func (ec *executionContext) marshalNWebhookLogs2ᚖgithubᚗcomᚋauthorizerdev return ec._WebhookLogs(ctx, sel, v) } -func (ec *executionContext) unmarshalNWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhookRequest(ctx context.Context, v interface{}) (model.WebhookRequest, error) { +func (ec *executionContext) unmarshalNWebhookRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhookRequest(ctx context.Context, v any) (model.WebhookRequest, error) { res, err := ec.unmarshalInputWebhookRequest(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNWebhooks2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhooks(ctx context.Context, sel ast.SelectionSet, v model.Webhooks) graphql.Marshaler { +func (ec *executionContext) marshalNWebhooks2githubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhooks(ctx context.Context, sel ast.SelectionSet, v model.Webhooks) graphql.Marshaler { return ec._Webhooks(ctx, sel, &v) } -func (ec *executionContext) marshalNWebhooks2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐWebhooks(ctx context.Context, sel ast.SelectionSet, v *model.Webhooks) graphql.Marshaler { +func (ec *executionContext) marshalNWebhooks2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐWebhooks(ctx context.Context, sel ast.SelectionSet, v *model.Webhooks) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -22384,12 +22805,13 @@ func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgq return ret } -func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) { +func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + _ = sel res := graphql.MarshalString(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -22399,11 +22821,9 @@ func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Conte return res } -func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } +func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) { + var vSlice []any + vSlice = graphql.CoerceList(v) var err error res := make([]string, len(vSlice)) for i := range vSlice { @@ -22574,12 +22994,13 @@ func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgen return ec.___Type(ctx, sel, v) } -func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) { +func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + _ = sel res := graphql.MarshalString(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -22589,17 +23010,19 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a return res } -func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { +func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v any) (bool, error) { res, err := graphql.UnmarshalBoolean(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { + _ = sel + _ = ctx res := graphql.MarshalBoolean(v) return res } -func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) { +func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v any) (*bool, error) { if v == nil { return nil, nil } @@ -22611,11 +23034,13 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast if v == nil { return graphql.Null } + _ = sel + _ = ctx res := graphql.MarshalBoolean(*v) return res } -func (ec *executionContext) unmarshalOID2ᚖstring(ctx context.Context, v interface{}) (*string, error) { +func (ec *executionContext) unmarshalOID2ᚖstring(ctx context.Context, v any) (*string, error) { if v == nil { return nil, nil } @@ -22627,11 +23052,13 @@ func (ec *executionContext) marshalOID2ᚖstring(ctx context.Context, sel ast.Se if v == nil { return graphql.Null } + _ = sel + _ = ctx res := graphql.MarshalID(*v) return res } -func (ec *executionContext) unmarshalOInt642ᚖint64(ctx context.Context, v interface{}) (*int64, error) { +func (ec *executionContext) unmarshalOInt642ᚖint64(ctx context.Context, v any) (*int64, error) { if v == nil { return nil, nil } @@ -22643,11 +23070,13 @@ func (ec *executionContext) marshalOInt642ᚖint64(ctx context.Context, sel ast. if v == nil { return graphql.Null } + _ = sel + _ = ctx res := graphql.MarshalInt64(*v) return res } -func (ec *executionContext) unmarshalOListWebhookLogRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐListWebhookLogRequest(ctx context.Context, v interface{}) (*model.ListWebhookLogRequest, error) { +func (ec *executionContext) unmarshalOListWebhookLogRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐListWebhookLogRequest(ctx context.Context, v any) (*model.ListWebhookLogRequest, error) { if v == nil { return nil, nil } @@ -22655,7 +23084,7 @@ func (ec *executionContext) unmarshalOListWebhookLogRequest2ᚖgithubᚗcomᚋau return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOMap2map(ctx context.Context, v interface{}) (map[string]interface{}, error) { +func (ec *executionContext) unmarshalOMap2map(ctx context.Context, v any) (map[string]any, error) { if v == nil { return nil, nil } @@ -22663,54 +23092,54 @@ func (ec *executionContext) unmarshalOMap2map(ctx context.Context, v interface{} return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalOMap2map(ctx context.Context, sel ast.SelectionSet, v map[string]interface{}) graphql.Marshaler { +func (ec *executionContext) marshalOMap2map(ctx context.Context, sel ast.SelectionSet, v map[string]any) graphql.Marshaler { if v == nil { return graphql.Null } + _ = sel + _ = ctx res := graphql.MarshalMap(v) return res } -func (ec *executionContext) unmarshalOMobileSignUpInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileSignUpInput(ctx context.Context, v interface{}) (*model.MobileSignUpInput, error) { +func (ec *executionContext) unmarshalOMobileSignUpRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐMobileSignUpRequest(ctx context.Context, v any) (*model.MobileSignUpRequest, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalInputMobileSignUpInput(ctx, v) + res, err := ec.unmarshalInputMobileSignUpRequest(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOPaginatedInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginatedInput(ctx context.Context, v interface{}) (*model.PaginatedInput, error) { +func (ec *executionContext) unmarshalOPaginatedRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPaginatedRequest(ctx context.Context, v any) (*model.PaginatedRequest, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalInputPaginatedInput(ctx, v) + res, err := ec.unmarshalInputPaginatedRequest(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOPaginationInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginationInput(ctx context.Context, v interface{}) (*model.PaginationInput, error) { +func (ec *executionContext) unmarshalOPaginationRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐPaginationRequest(ctx context.Context, v any) (*model.PaginationRequest, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalInputPaginationInput(ctx, v) + res, err := ec.unmarshalInputPaginationRequest(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOSessionQueryInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐSessionQueryInput(ctx context.Context, v interface{}) (*model.SessionQueryInput, error) { +func (ec *executionContext) unmarshalOSessionQueryRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐSessionQueryRequest(ctx context.Context, v any) (*model.SessionQueryRequest, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalInputSessionQueryInput(ctx, v) + res, err := ec.unmarshalInputSessionQueryRequest(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOString2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { +func (ec *executionContext) unmarshalOString2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) { if v == nil { return nil, nil } - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } + var vSlice []any + vSlice = graphql.CoerceList(v) var err error res := make([]string, len(vSlice)) for i := range vSlice { @@ -22741,14 +23170,12 @@ func (ec *executionContext) marshalOString2ᚕstringᚄ(ctx context.Context, sel return ret } -func (ec *executionContext) unmarshalOString2ᚕᚖstring(ctx context.Context, v interface{}) ([]*string, error) { +func (ec *executionContext) unmarshalOString2ᚕᚖstring(ctx context.Context, v any) ([]*string, error) { if v == nil { return nil, nil } - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } + var vSlice []any + vSlice = graphql.CoerceList(v) var err error res := make([]*string, len(vSlice)) for i := range vSlice { @@ -22773,7 +23200,7 @@ func (ec *executionContext) marshalOString2ᚕᚖstring(ctx context.Context, sel return ret } -func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { +func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v any) (*string, error) { if v == nil { return nil, nil } @@ -22785,22 +23212,24 @@ func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel as if v == nil { return graphql.Null } + _ = sel + _ = ctx res := graphql.MarshalString(*v) return res } -func (ec *executionContext) marshalOUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v *model.User) graphql.Marshaler { +func (ec *executionContext) marshalOUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v *model.User) graphql.Marshaler { if v == nil { return graphql.Null } return ec._User(ctx, sel, v) } -func (ec *executionContext) unmarshalOValidateSessionInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐValidateSessionInput(ctx context.Context, v interface{}) (*model.ValidateSessionInput, error) { +func (ec *executionContext) unmarshalOValidateSessionRequest2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋinternalᚋgraphᚋmodelᚐValidateSessionRequest(ctx context.Context, v any) (*model.ValidateSessionRequest, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalInputValidateSessionInput(ctx, v) + res, err := ec.unmarshalInputValidateSessionRequest(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } diff --git a/server/graph/model/models_gen.go b/internal/graph/model/models_gen.go similarity index 67% rename from server/graph/model/models_gen.go rename to internal/graph/model/models_gen.go index f14db1929..cb8d7bb16 100644 --- a/server/graph/model/models_gen.go +++ b/internal/graph/model/models_gen.go @@ -10,18 +10,18 @@ type AddEmailTemplateRequest struct { } type AddWebhookRequest struct { - EventName string `json:"event_name"` - EventDescription *string `json:"event_description,omitempty"` - Endpoint string `json:"endpoint"` - Enabled bool `json:"enabled"` - Headers map[string]interface{} `json:"headers,omitempty"` + EventName string `json:"event_name"` + EventDescription *string `json:"event_description,omitempty"` + Endpoint string `json:"endpoint"` + Enabled bool `json:"enabled"` + Headers map[string]any `json:"headers,omitempty"` } -type AdminLoginInput struct { +type AdminLoginRequest struct { AdminSecret string `json:"admin_secret"` } -type AdminSignupInput struct { +type AdminSignupRequest struct { AdminSecret string `json:"admin_secret"` } @@ -44,7 +44,7 @@ type DeleteEmailTemplateRequest struct { ID string `json:"id"` } -type DeleteUserInput struct { +type DeleteUserRequest struct { Email string `json:"email"` } @@ -142,7 +142,7 @@ type Error struct { Reason string `json:"reason"` } -type ForgotPasswordInput struct { +type ForgotPasswordRequest struct { Email *string `json:"email,omitempty"` PhoneNumber *string `json:"phone_number,omitempty"` State *string `json:"state,omitempty"` @@ -154,7 +154,7 @@ type ForgotPasswordResponse struct { ShouldShowMobileOtpScreen *bool `json:"should_show_mobile_otp_screen,omitempty"` } -type GenerateJWTKeysInput struct { +type GenerateJWTKeysRequest struct { Type string `json:"type"` } @@ -169,7 +169,7 @@ type GetUserRequest struct { Email *string `json:"email,omitempty"` } -type InviteMemberInput struct { +type InviteMemberRequest struct { Emails []string `json:"emails"` RedirectURI *string `json:"redirect_uri,omitempty"` } @@ -180,11 +180,11 @@ type InviteMembersResponse struct { } type ListWebhookLogRequest struct { - Pagination *PaginationInput `json:"pagination,omitempty"` - WebhookID *string `json:"webhook_id,omitempty"` + Pagination *PaginationRequest `json:"pagination,omitempty"` + WebhookID *string `json:"webhook_id,omitempty"` } -type LoginInput struct { +type LoginRequest struct { Email *string `json:"email,omitempty"` PhoneNumber *string `json:"phone_number,omitempty"` Password string `json:"password"` @@ -193,7 +193,7 @@ type LoginInput struct { State *string `json:"state,omitempty"` } -type MagicLinkLoginInput struct { +type MagicLinkLoginRequest struct { Email string `json:"email"` Roles []string `json:"roles,omitempty"` Scope []string `json:"scope,omitempty"` @@ -224,7 +224,7 @@ type Meta struct { IsPhoneVerificationEnabled bool `json:"is_phone_verification_enabled"` } -type MobileLoginInput struct { +type MobileLoginRequest struct { PhoneNumber string `json:"phone_number"` Password string `json:"password"` Roles []string `json:"roles,omitempty"` @@ -232,35 +232,35 @@ type MobileLoginInput struct { State *string `json:"state,omitempty"` } -type MobileSignUpInput struct { - Email *string `json:"email,omitempty"` - GivenName *string `json:"given_name,omitempty"` - FamilyName *string `json:"family_name,omitempty"` - MiddleName *string `json:"middle_name,omitempty"` - Nickname *string `json:"nickname,omitempty"` - Gender *string `json:"gender,omitempty"` - Birthdate *string `json:"birthdate,omitempty"` - PhoneNumber string `json:"phone_number"` - Picture *string `json:"picture,omitempty"` - Password string `json:"password"` - ConfirmPassword string `json:"confirm_password"` - Roles []string `json:"roles,omitempty"` - Scope []string `json:"scope,omitempty"` - RedirectURI *string `json:"redirect_uri,omitempty"` - IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"` - State *string `json:"state,omitempty"` - AppData map[string]interface{} `json:"app_data,omitempty"` +type MobileSignUpRequest struct { + Email *string `json:"email,omitempty"` + GivenName *string `json:"given_name,omitempty"` + FamilyName *string `json:"family_name,omitempty"` + MiddleName *string `json:"middle_name,omitempty"` + Nickname *string `json:"nickname,omitempty"` + Gender *string `json:"gender,omitempty"` + Birthdate *string `json:"birthdate,omitempty"` + PhoneNumber string `json:"phone_number"` + Picture *string `json:"picture,omitempty"` + Password string `json:"password"` + ConfirmPassword string `json:"confirm_password"` + Roles []string `json:"roles,omitempty"` + Scope []string `json:"scope,omitempty"` + RedirectURI *string `json:"redirect_uri,omitempty"` + IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"` + State *string `json:"state,omitempty"` + AppData map[string]any `json:"app_data,omitempty"` } type Mutation struct { } -type OAuthRevokeInput struct { +type OAuthRevokeRequest struct { RefreshToken string `json:"refresh_token"` } -type PaginatedInput struct { - Pagination *PaginationInput `json:"pagination,omitempty"` +type PaginatedRequest struct { + Pagination *PaginationRequest `json:"pagination,omitempty"` } type Pagination struct { @@ -270,7 +270,7 @@ type Pagination struct { Total int64 `json:"total"` } -type PaginationInput struct { +type PaginationRequest struct { Limit *int64 `json:"limit,omitempty"` Page *int64 `json:"page,omitempty"` } @@ -284,13 +284,13 @@ type ResendOTPRequest struct { State *string `json:"state,omitempty"` } -type ResendVerifyEmailInput struct { +type ResendVerifyEmailRequest struct { Email string `json:"email"` Identifier string `json:"identifier"` State *string `json:"state,omitempty"` } -type ResetPasswordInput struct { +type ResetPasswordRequest struct { Token *string `json:"token,omitempty"` Otp *string `json:"otp,omitempty"` PhoneNumber *string `json:"phone_number,omitempty"` @@ -302,45 +302,36 @@ type Response struct { Message string `json:"message"` } -type SMSVerificationRequests struct { - ID string `json:"id"` - Code string `json:"code"` - CodeExpiresAt int64 `json:"code_expires_at"` - PhoneNumber string `json:"phone_number"` - CreatedAt int64 `json:"created_at"` - UpdatedAt *int64 `json:"updated_at,omitempty"` -} - -type SessionQueryInput struct { +type SessionQueryRequest struct { Roles []string `json:"roles,omitempty"` Scope []string `json:"scope,omitempty"` } -type SignUpInput struct { - Email *string `json:"email,omitempty"` - GivenName *string `json:"given_name,omitempty"` - FamilyName *string `json:"family_name,omitempty"` - MiddleName *string `json:"middle_name,omitempty"` - Nickname *string `json:"nickname,omitempty"` - Gender *string `json:"gender,omitempty"` - Birthdate *string `json:"birthdate,omitempty"` - PhoneNumber *string `json:"phone_number,omitempty"` - Picture *string `json:"picture,omitempty"` - Password string `json:"password"` - ConfirmPassword string `json:"confirm_password"` - Roles []string `json:"roles,omitempty"` - Scope []string `json:"scope,omitempty"` - RedirectURI *string `json:"redirect_uri,omitempty"` - IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"` - State *string `json:"state,omitempty"` - AppData map[string]interface{} `json:"app_data,omitempty"` +type SignUpRequest struct { + Email *string `json:"email,omitempty"` + GivenName *string `json:"given_name,omitempty"` + FamilyName *string `json:"family_name,omitempty"` + MiddleName *string `json:"middle_name,omitempty"` + Nickname *string `json:"nickname,omitempty"` + Gender *string `json:"gender,omitempty"` + Birthdate *string `json:"birthdate,omitempty"` + PhoneNumber *string `json:"phone_number,omitempty"` + Picture *string `json:"picture,omitempty"` + Password string `json:"password"` + ConfirmPassword string `json:"confirm_password"` + Roles []string `json:"roles,omitempty"` + Scope []string `json:"scope,omitempty"` + RedirectURI *string `json:"redirect_uri,omitempty"` + IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"` + State *string `json:"state,omitempty"` + AppData map[string]any `json:"app_data,omitempty"` } type TestEndpointRequest struct { - Endpoint string `json:"endpoint"` - EventName string `json:"event_name"` - EventDescription *string `json:"event_description,omitempty"` - Headers map[string]interface{} `json:"headers,omitempty"` + Endpoint string `json:"endpoint"` + EventName string `json:"event_name"` + EventDescription *string `json:"event_description,omitempty"` + Headers map[string]any `json:"headers,omitempty"` } type TestEndpointResponse struct { @@ -348,7 +339,7 @@ type TestEndpointResponse struct { Response *string `json:"response,omitempty"` } -type UpdateAccessInput struct { +type UpdateAccessRequest struct { UserID string `json:"user_id"` } @@ -360,7 +351,7 @@ type UpdateEmailTemplateRequest struct { Design *string `json:"design,omitempty"` } -type UpdateEnvInput struct { +type UpdateEnvRequest struct { AccessTokenExpiryTime *string `json:"ACCESS_TOKEN_EXPIRY_TIME,omitempty"` AdminSecret *string `json:"ADMIN_SECRET,omitempty"` CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT,omitempty"` @@ -425,71 +416,71 @@ type UpdateEnvInput struct { DisableTotpLogin *bool `json:"DISABLE_TOTP_LOGIN,omitempty"` } -type UpdateProfileInput struct { - OldPassword *string `json:"old_password,omitempty"` - NewPassword *string `json:"new_password,omitempty"` - ConfirmNewPassword *string `json:"confirm_new_password,omitempty"` - Email *string `json:"email,omitempty"` - GivenName *string `json:"given_name,omitempty"` - FamilyName *string `json:"family_name,omitempty"` - MiddleName *string `json:"middle_name,omitempty"` - Nickname *string `json:"nickname,omitempty"` - Gender *string `json:"gender,omitempty"` - Birthdate *string `json:"birthdate,omitempty"` - PhoneNumber *string `json:"phone_number,omitempty"` - Picture *string `json:"picture,omitempty"` - IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"` - AppData map[string]interface{} `json:"app_data,omitempty"` -} - -type UpdateUserInput struct { - ID string `json:"id"` - Email *string `json:"email,omitempty"` - EmailVerified *bool `json:"email_verified,omitempty"` - GivenName *string `json:"given_name,omitempty"` - FamilyName *string `json:"family_name,omitempty"` - MiddleName *string `json:"middle_name,omitempty"` - Nickname *string `json:"nickname,omitempty"` - Gender *string `json:"gender,omitempty"` - Birthdate *string `json:"birthdate,omitempty"` - PhoneNumber *string `json:"phone_number,omitempty"` - PhoneNumberVerified *bool `json:"phone_number_verified,omitempty"` - Picture *string `json:"picture,omitempty"` - Roles []*string `json:"roles,omitempty"` - IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"` - AppData map[string]interface{} `json:"app_data,omitempty"` +type UpdateProfileRequest struct { + OldPassword *string `json:"old_password,omitempty"` + NewPassword *string `json:"new_password,omitempty"` + ConfirmNewPassword *string `json:"confirm_new_password,omitempty"` + Email *string `json:"email,omitempty"` + GivenName *string `json:"given_name,omitempty"` + FamilyName *string `json:"family_name,omitempty"` + MiddleName *string `json:"middle_name,omitempty"` + Nickname *string `json:"nickname,omitempty"` + Gender *string `json:"gender,omitempty"` + Birthdate *string `json:"birthdate,omitempty"` + PhoneNumber *string `json:"phone_number,omitempty"` + Picture *string `json:"picture,omitempty"` + IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"` + AppData map[string]any `json:"app_data,omitempty"` +} + +type UpdateUserRequest struct { + ID string `json:"id"` + Email *string `json:"email,omitempty"` + EmailVerified *bool `json:"email_verified,omitempty"` + GivenName *string `json:"given_name,omitempty"` + FamilyName *string `json:"family_name,omitempty"` + MiddleName *string `json:"middle_name,omitempty"` + Nickname *string `json:"nickname,omitempty"` + Gender *string `json:"gender,omitempty"` + Birthdate *string `json:"birthdate,omitempty"` + PhoneNumber *string `json:"phone_number,omitempty"` + PhoneNumberVerified *bool `json:"phone_number_verified,omitempty"` + Picture *string `json:"picture,omitempty"` + Roles []*string `json:"roles,omitempty"` + IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"` + AppData map[string]any `json:"app_data,omitempty"` } type UpdateWebhookRequest struct { - ID string `json:"id"` - EventName *string `json:"event_name,omitempty"` - EventDescription *string `json:"event_description,omitempty"` - Endpoint *string `json:"endpoint,omitempty"` - Enabled *bool `json:"enabled,omitempty"` - Headers map[string]interface{} `json:"headers,omitempty"` + ID string `json:"id"` + EventName *string `json:"event_name,omitempty"` + EventDescription *string `json:"event_description,omitempty"` + Endpoint *string `json:"endpoint,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Headers map[string]any `json:"headers,omitempty"` } type User struct { - ID string `json:"id"` - Email *string `json:"email,omitempty"` - EmailVerified bool `json:"email_verified"` - SignupMethods string `json:"signup_methods"` - GivenName *string `json:"given_name,omitempty"` - FamilyName *string `json:"family_name,omitempty"` - MiddleName *string `json:"middle_name,omitempty"` - Nickname *string `json:"nickname,omitempty"` - PreferredUsername *string `json:"preferred_username,omitempty"` - Gender *string `json:"gender,omitempty"` - Birthdate *string `json:"birthdate,omitempty"` - PhoneNumber *string `json:"phone_number,omitempty"` - PhoneNumberVerified *bool `json:"phone_number_verified,omitempty"` - Picture *string `json:"picture,omitempty"` - Roles []string `json:"roles"` - CreatedAt *int64 `json:"created_at,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` - RevokedTimestamp *int64 `json:"revoked_timestamp,omitempty"` - IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"` - AppData map[string]interface{} `json:"app_data,omitempty"` + ID string `json:"id"` + Email *string `json:"email,omitempty"` + EmailVerified bool `json:"email_verified"` + SignupMethods string `json:"signup_methods"` + GivenName *string `json:"given_name,omitempty"` + FamilyName *string `json:"family_name,omitempty"` + MiddleName *string `json:"middle_name,omitempty"` + Nickname *string `json:"nickname,omitempty"` + PreferredUsername *string `json:"preferred_username,omitempty"` + Gender *string `json:"gender,omitempty"` + Birthdate *string `json:"birthdate,omitempty"` + PhoneNumber *string `json:"phone_number,omitempty"` + PhoneNumberVerified bool `json:"phone_number_verified"` + Picture *string `json:"picture,omitempty"` + Roles []string `json:"roles"` + CreatedAt *int64 `json:"created_at,omitempty"` + UpdatedAt *int64 `json:"updated_at,omitempty"` + RevokedTimestamp *int64 `json:"revoked_timestamp,omitempty"` + IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"` + AppData map[string]any `json:"app_data,omitempty"` } type Users struct { @@ -497,18 +488,18 @@ type Users struct { Users []*User `json:"users"` } -type ValidateJWTTokenInput struct { +type ValidateJWTTokenRequest struct { TokenType string `json:"token_type"` Token string `json:"token"` Roles []string `json:"roles,omitempty"` } type ValidateJWTTokenResponse struct { - IsValid bool `json:"is_valid"` - Claims map[string]interface{} `json:"claims,omitempty"` + IsValid bool `json:"is_valid"` + Claims map[string]any `json:"claims,omitempty"` } -type ValidateSessionInput struct { +type ValidateSessionRequest struct { Cookie string `json:"cookie"` Roles []string `json:"roles,omitempty"` } @@ -535,7 +526,7 @@ type VerificationRequests struct { VerificationRequests []*VerificationRequest `json:"verification_requests"` } -type VerifyEmailInput struct { +type VerifyEmailRequest struct { Token string `json:"token"` State *string `json:"state,omitempty"` } @@ -549,14 +540,14 @@ type VerifyOTPRequest struct { } type Webhook struct { - ID string `json:"id"` - EventName *string `json:"event_name,omitempty"` - EventDescription *string `json:"event_description,omitempty"` - Endpoint *string `json:"endpoint,omitempty"` - Enabled *bool `json:"enabled,omitempty"` - Headers map[string]interface{} `json:"headers,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + ID string `json:"id"` + EventName *string `json:"event_name,omitempty"` + EventDescription *string `json:"event_description,omitempty"` + Endpoint *string `json:"endpoint,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Headers map[string]any `json:"headers,omitempty"` + CreatedAt *int64 `json:"created_at,omitempty"` + UpdatedAt *int64 `json:"updated_at,omitempty"` } type WebhookLog struct { diff --git a/server/graph/resolver.go b/internal/graph/resolver.go similarity index 55% rename from server/graph/resolver.go rename to internal/graph/resolver.go index a25c09c61..ce42d3205 100644 --- a/server/graph/resolver.go +++ b/internal/graph/resolver.go @@ -1,7 +1,13 @@ package graph +import ( + "github.com/authorizerdev/authorizer/internal/graphql" +) + // This file will not be regenerated automatically. // // It serves as dependency injection for your app, add any dependencies you require here. -type Resolver struct{} +type Resolver struct { + GraphQLProvider graphql.Provider +} diff --git a/server/graph/schema.graphqls b/internal/graph/schema.graphqls similarity index 84% rename from server/graph/schema.graphqls rename to internal/graph/schema.graphqls index 10202210b..ee070c17c 100644 --- a/server/graph/schema.graphqls +++ b/internal/graph/schema.graphqls @@ -50,7 +50,7 @@ type User { gender: String birthdate: String phone_number: String - phone_number_verified: Boolean + phone_number_verified: Boolean! picture: String roles: [String!]! created_at: Int64 @@ -82,15 +82,6 @@ type VerificationRequests { verification_requests: [VerificationRequest!]! } -type SMSVerificationRequests { - id: ID! - code: String! - code_expires_at: Int64! - phone_number: String! - created_at: Int64! - updated_at: Int64 -} - type Error { message: String! reason: String! @@ -270,7 +261,7 @@ type EmailTemplates { email_templates: [EmailTemplate!]! } -input UpdateEnvInput { +input UpdateEnvRequest { ACCESS_TOKEN_EXPIRY_TIME: String ADMIN_SECRET: String CUSTOM_ACCESS_TOKEN_SCRIPT: String @@ -335,16 +326,16 @@ input UpdateEnvInput { DISABLE_TOTP_LOGIN: Boolean } -input AdminLoginInput { +input AdminLoginRequest { admin_secret: String! } -input AdminSignupInput { +input AdminSignupRequest { admin_secret: String! } # Deprecated from v1.2.0 -input MobileSignUpInput { +input MobileSignUpRequest { email: String given_name: String family_name: String @@ -367,7 +358,7 @@ input MobileSignUpInput { app_data: Map } -input SignUpInput { +input SignUpRequest { email: String given_name: String family_name: String @@ -390,7 +381,7 @@ input SignUpInput { app_data: Map } -input LoginInput { +input LoginRequest { email: String phone_number: String password: String! @@ -403,7 +394,7 @@ input LoginInput { } # Deprecated from v1.2.0 -input MobileLoginInput { +input MobileLoginRequest { phone_number: String! password: String! roles: [String!] @@ -414,7 +405,7 @@ input MobileLoginInput { state: String } -input VerifyEmailInput { +input VerifyEmailRequest { token: String! # state is used for authorization code grant flow # it is used to get code for an on-going auth process during login @@ -422,7 +413,7 @@ input VerifyEmailInput { state: String } -input ResendVerifyEmailInput { +input ResendVerifyEmailRequest { email: String! identifier: String! # state is used for authorization code grant flow @@ -431,7 +422,7 @@ input ResendVerifyEmailInput { state: String } -input UpdateProfileInput { +input UpdateProfileRequest { old_password: String new_password: String confirm_new_password: String @@ -448,7 +439,7 @@ input UpdateProfileInput { app_data: Map } -input UpdateUserInput { +input UpdateUserRequest { id: ID! email: String email_verified: Boolean @@ -466,14 +457,14 @@ input UpdateUserInput { app_data: Map } -input ForgotPasswordInput { +input ForgotPasswordRequest { email: String phone_number: String state: String redirect_uri: String } -input ResetPasswordInput { +input ResetPasswordRequest { token: String otp: String phone_number: String @@ -481,11 +472,11 @@ input ResetPasswordInput { confirm_password: String! } -input DeleteUserInput { +input DeleteUserRequest { email: String! } -input MagicLinkLoginInput { +input MagicLinkLoginRequest { email: String! roles: [String!] scope: [String!] @@ -493,50 +484,50 @@ input MagicLinkLoginInput { redirect_uri: String } -input SessionQueryInput { +input SessionQueryRequest { roles: [String!] scope: [String!] } -input PaginationInput { +input PaginationRequest { limit: Int64 page: Int64 } -input PaginatedInput { - pagination: PaginationInput +input PaginatedRequest { + pagination: PaginationRequest } -input OAuthRevokeInput { +input OAuthRevokeRequest { refresh_token: String! } -input InviteMemberInput { +input InviteMemberRequest { emails: [String!]! redirect_uri: String } -input UpdateAccessInput { +input UpdateAccessRequest { user_id: String! } -input ValidateJWTTokenInput { +input ValidateJWTTokenRequest { token_type: String! token: String! roles: [String!] } -input ValidateSessionInput { +input ValidateSessionRequest { cookie: String! roles: [String!] } -input GenerateJWTKeysInput { +input GenerateJWTKeysRequest { type: String! } input ListWebhookLogRequest { - pagination: PaginationInput + pagination: PaginationRequest webhook_id: String } @@ -618,34 +609,37 @@ input GetUserRequest { } type Mutation { - signup(params: SignUpInput!): AuthResponse! + signup(params: SignUpRequest!): AuthResponse! # Deprecated from v1.2.0 - mobile_signup(params: MobileSignUpInput): AuthResponse! - login(params: LoginInput!): AuthResponse! + mobile_signup(params: MobileSignUpRequest): AuthResponse! + login(params: LoginRequest!): AuthResponse! # Deprecated from v1.2.0 - mobile_login(params: MobileLoginInput!): AuthResponse! - magic_link_login(params: MagicLinkLoginInput!): Response! + mobile_login(params: MobileLoginRequest!): AuthResponse! + magic_link_login(params: MagicLinkLoginRequest!): Response! logout: Response! - update_profile(params: UpdateProfileInput!): Response! - verify_email(params: VerifyEmailInput!): AuthResponse! - resend_verify_email(params: ResendVerifyEmailInput!): Response! - forgot_password(params: ForgotPasswordInput!): ForgotPasswordResponse! - reset_password(params: ResetPasswordInput!): Response! - revoke(params: OAuthRevokeInput!): Response! + update_profile(params: UpdateProfileRequest!): Response! + verify_email(params: VerifyEmailRequest!): AuthResponse! + resend_verify_email(params: ResendVerifyEmailRequest!): Response! + forgot_password(params: ForgotPasswordRequest!): ForgotPasswordResponse! + reset_password(params: ResetPasswordRequest!): Response! + revoke(params: OAuthRevokeRequest!): Response! verify_otp(params: VerifyOTPRequest!): AuthResponse! resend_otp(params: ResendOTPRequest!): Response! deactivate_account: Response! # admin only apis - _delete_user(params: DeleteUserInput!): Response! - _update_user(params: UpdateUserInput!): User! - _admin_signup(params: AdminSignupInput!): Response! - _admin_login(params: AdminLoginInput!): Response! + _delete_user(params: DeleteUserRequest!): Response! + _update_user(params: UpdateUserRequest!): User! + # deprecated from v2.0.0 + _admin_signup(params: AdminSignupRequest!): Response! + _admin_login(params: AdminLoginRequest!): Response! _admin_logout: Response! - _update_env(params: UpdateEnvInput!): Response! - _invite_members(params: InviteMemberInput!): InviteMembersResponse! - _revoke_access(param: UpdateAccessInput!): Response! - _enable_access(param: UpdateAccessInput!): Response! - _generate_jwt_keys(params: GenerateJWTKeysInput!): GenerateJWTKeysResponse! + # Deprecated from v2.0.0 + _update_env(params: UpdateEnvRequest!): Response! + _invite_members(params: InviteMemberRequest!): InviteMembersResponse! + _revoke_access(param: UpdateAccessRequest!): Response! + _enable_access(param: UpdateAccessRequest!): Response! + # Deprecated from v2.0.0 + _generate_jwt_keys(params: GenerateJWTKeysRequest!): GenerateJWTKeysResponse! _add_webhook(params: AddWebhookRequest!): Response! _update_webhook(params: UpdateWebhookRequest!): Response! _delete_webhook(params: WebhookRequest!): Response! @@ -657,18 +651,19 @@ type Mutation { type Query { meta: Meta! - session(params: SessionQueryInput): AuthResponse! + session(params: SessionQueryRequest): AuthResponse! profile: User! - validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse! - validate_session(params: ValidateSessionInput): ValidateSessionResponse! + validate_jwt_token(params: ValidateJWTTokenRequest!): ValidateJWTTokenResponse! + validate_session(params: ValidateSessionRequest): ValidateSessionResponse! # admin only apis - _users(params: PaginatedInput): Users! + _users(params: PaginatedRequest): Users! _user(params: GetUserRequest!): User! - _verification_requests(params: PaginatedInput): VerificationRequests! + _verification_requests(params: PaginatedRequest): VerificationRequests! _admin_session: Response! + # Deprecated from v2.0.0 _env: Env! _webhook(params: WebhookRequest!): Webhook! - _webhooks(params: PaginatedInput): Webhooks! + _webhooks(params: PaginatedRequest): Webhooks! _webhook_logs(params: ListWebhookLogRequest): WebhookLogs! - _email_templates(params: PaginatedInput): EmailTemplates! + _email_templates(params: PaginatedRequest): EmailTemplates! } diff --git a/server/graph/schema.resolvers.go b/internal/graph/schema.resolvers.go similarity index 62% rename from server/graph/schema.resolvers.go rename to internal/graph/schema.resolvers.go index e4ef95261..36892600e 100644 --- a/server/graph/schema.resolvers.go +++ b/internal/graph/schema.resolvers.go @@ -2,244 +2,244 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.45 +// Code generated by github.com/99designs/gqlgen version v0.17.73 import ( "context" + "fmt" - "github.com/authorizerdev/authorizer/server/graph/generated" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/resolvers" + "github.com/authorizerdev/authorizer/internal/graph/generated" + "github.com/authorizerdev/authorizer/internal/graph/model" ) // Signup is the resolver for the signup field. -func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) { - return resolvers.SignupResolver(ctx, params) +func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpRequest) (*model.AuthResponse, error) { + return r.GraphQLProvider.SignUp(ctx, ¶ms) } // 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) +func (r *mutationResolver) MobileSignup(ctx context.Context, params *model.MobileSignUpRequest) (*model.AuthResponse, error) { + return nil, fmt.Errorf("deprecated, use signup with mobile phone_number") } // Login is the resolver for the login field. -func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) { - return resolvers.LoginResolver(ctx, params) +func (r *mutationResolver) Login(ctx context.Context, params model.LoginRequest) (*model.AuthResponse, error) { + return r.GraphQLProvider.Login(ctx, ¶ms) } // 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) +func (r *mutationResolver) MobileLogin(ctx context.Context, params model.MobileLoginRequest) (*model.AuthResponse, error) { + return nil, fmt.Errorf("deprecated, use login with mobile phone_number") } // MagicLinkLogin is the resolver for the magic_link_login field. -func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) { - return resolvers.MagicLinkLoginResolver(ctx, params) +func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginRequest) (*model.Response, error) { + return r.GraphQLProvider.MagicLinkLogin(ctx, ¶ms) } // Logout is the resolver for the logout field. func (r *mutationResolver) Logout(ctx context.Context) (*model.Response, error) { - return resolvers.LogoutResolver(ctx) + return r.GraphQLProvider.Logout(ctx) } // UpdateProfile is the resolver for the update_profile field. -func (r *mutationResolver) UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error) { - return resolvers.UpdateProfileResolver(ctx, params) +func (r *mutationResolver) UpdateProfile(ctx context.Context, params model.UpdateProfileRequest) (*model.Response, error) { + return r.GraphQLProvider.UpdateProfile(ctx, ¶ms) } // VerifyEmail is the resolver for the verify_email field. -func (r *mutationResolver) VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error) { - return resolvers.VerifyEmailResolver(ctx, params) +func (r *mutationResolver) VerifyEmail(ctx context.Context, params model.VerifyEmailRequest) (*model.AuthResponse, error) { + return r.GraphQLProvider.VerifyEmail(ctx, ¶ms) } // ResendVerifyEmail is the resolver for the resend_verify_email field. -func (r *mutationResolver) ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) { - return resolvers.ResendVerifyEmailResolver(ctx, params) +func (r *mutationResolver) ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailRequest) (*model.Response, error) { + return r.GraphQLProvider.ResendVerifyEmail(ctx, ¶ms) } // ForgotPassword is the resolver for the forgot_password field. -func (r *mutationResolver) ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.ForgotPasswordResponse, error) { - return resolvers.ForgotPasswordResolver(ctx, params) +func (r *mutationResolver) ForgotPassword(ctx context.Context, params model.ForgotPasswordRequest) (*model.ForgotPasswordResponse, error) { + return r.GraphQLProvider.ForgotPassword(ctx, ¶ms) } // ResetPassword is the resolver for the reset_password field. -func (r *mutationResolver) ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) { - return resolvers.ResetPasswordResolver(ctx, params) +func (r *mutationResolver) ResetPassword(ctx context.Context, params model.ResetPasswordRequest) (*model.Response, error) { + return r.GraphQLProvider.ResetPassword(ctx, ¶ms) } // Revoke is the resolver for the revoke field. -func (r *mutationResolver) Revoke(ctx context.Context, params model.OAuthRevokeInput) (*model.Response, error) { - return resolvers.RevokeResolver(ctx, params) +func (r *mutationResolver) Revoke(ctx context.Context, params model.OAuthRevokeRequest) (*model.Response, error) { + return r.GraphQLProvider.Revoke(ctx, ¶ms) } // VerifyOtp is the resolver for the verify_otp field. func (r *mutationResolver) VerifyOtp(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error) { - return resolvers.VerifyOtpResolver(ctx, params) + return r.GraphQLProvider.VerifyOTP(ctx, ¶ms) } // ResendOtp is the resolver for the resend_otp field. func (r *mutationResolver) ResendOtp(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error) { - return resolvers.ResendOTPResolver(ctx, params) + return r.GraphQLProvider.ResendOTP(ctx, ¶ms) } // DeactivateAccount is the resolver for the deactivate_account field. func (r *mutationResolver) DeactivateAccount(ctx context.Context) (*model.Response, error) { - return resolvers.DeactivateAccountResolver(ctx) + return r.GraphQLProvider.DeactivateAccount(ctx) } // DeleteUser is the resolver for the _delete_user field. -func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) { - return resolvers.DeleteUserResolver(ctx, params) +func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUserRequest) (*model.Response, error) { + return r.GraphQLProvider.DeleteUser(ctx, ¶ms) } // UpdateUser is the resolver for the _update_user field. -func (r *mutationResolver) UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error) { - return resolvers.UpdateUserResolver(ctx, params) +func (r *mutationResolver) UpdateUser(ctx context.Context, params model.UpdateUserRequest) (*model.User, error) { + return r.GraphQLProvider.UpdateUser(ctx, ¶ms) } // AdminSignup is the resolver for the _admin_signup field. -func (r *mutationResolver) AdminSignup(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) { - return resolvers.AdminSignupResolver(ctx, params) +func (r *mutationResolver) AdminSignup(ctx context.Context, params model.AdminSignupRequest) (*model.Response, error) { + return nil, fmt.Errorf("deprecated. please configure admin secret via cli args") } // AdminLogin is the resolver for the _admin_login field. -func (r *mutationResolver) AdminLogin(ctx context.Context, params model.AdminLoginInput) (*model.Response, error) { - return resolvers.AdminLoginResolver(ctx, params) +func (r *mutationResolver) AdminLogin(ctx context.Context, params model.AdminLoginRequest) (*model.Response, error) { + return r.GraphQLProvider.AdminLogin(ctx, ¶ms) } // AdminLogout is the resolver for the _admin_logout field. func (r *mutationResolver) AdminLogout(ctx context.Context) (*model.Response, error) { - return resolvers.AdminLogoutResolver(ctx) + return r.GraphQLProvider.AdminLogout(ctx) } // UpdateEnv is the resolver for the _update_env field. -func (r *mutationResolver) UpdateEnv(ctx context.Context, params model.UpdateEnvInput) (*model.Response, error) { - return resolvers.UpdateEnvResolver(ctx, params) +func (r *mutationResolver) UpdateEnv(ctx context.Context, params model.UpdateEnvRequest) (*model.Response, error) { + return nil, fmt.Errorf("deprecated. please configure env via cli args") } // InviteMembers is the resolver for the _invite_members field. -func (r *mutationResolver) InviteMembers(ctx context.Context, params model.InviteMemberInput) (*model.InviteMembersResponse, error) { - return resolvers.InviteMembersResolver(ctx, params) +func (r *mutationResolver) InviteMembers(ctx context.Context, params model.InviteMemberRequest) (*model.InviteMembersResponse, error) { + return r.GraphQLProvider.InviteMembers(ctx, ¶ms) } // RevokeAccess is the resolver for the _revoke_access field. -func (r *mutationResolver) RevokeAccess(ctx context.Context, param model.UpdateAccessInput) (*model.Response, error) { - return resolvers.RevokeAccessResolver(ctx, param) +func (r *mutationResolver) RevokeAccess(ctx context.Context, param model.UpdateAccessRequest) (*model.Response, error) { + return r.GraphQLProvider.RevokeAccess(ctx, ¶m) } // EnableAccess is the resolver for the _enable_access field. -func (r *mutationResolver) EnableAccess(ctx context.Context, param model.UpdateAccessInput) (*model.Response, error) { - return resolvers.EnableAccessResolver(ctx, param) +func (r *mutationResolver) EnableAccess(ctx context.Context, param model.UpdateAccessRequest) (*model.Response, error) { + return r.GraphQLProvider.EnableAccess(ctx, ¶m) } // GenerateJwtKeys is the resolver for the _generate_jwt_keys field. -func (r *mutationResolver) GenerateJwtKeys(ctx context.Context, params model.GenerateJWTKeysInput) (*model.GenerateJWTKeysResponse, error) { - return resolvers.GenerateJWTKeysResolver(ctx, params) +func (r *mutationResolver) GenerateJwtKeys(ctx context.Context, params model.GenerateJWTKeysRequest) (*model.GenerateJWTKeysResponse, error) { + return nil, fmt.Errorf("deprecated. please configure jwt keys via cli args") } // AddWebhook is the resolver for the _add_webhook field. func (r *mutationResolver) AddWebhook(ctx context.Context, params model.AddWebhookRequest) (*model.Response, error) { - return resolvers.AddWebhookResolver(ctx, params) + return r.GraphQLProvider.AddWebhook(ctx, ¶ms) } // UpdateWebhook is the resolver for the _update_webhook field. func (r *mutationResolver) UpdateWebhook(ctx context.Context, params model.UpdateWebhookRequest) (*model.Response, error) { - return resolvers.UpdateWebhookResolver(ctx, params) + return r.GraphQLProvider.UpdateWebhook(ctx, ¶ms) } // DeleteWebhook is the resolver for the _delete_webhook field. func (r *mutationResolver) DeleteWebhook(ctx context.Context, params model.WebhookRequest) (*model.Response, error) { - return resolvers.DeleteWebhookResolver(ctx, params) + return r.GraphQLProvider.DeleteWebhook(ctx, ¶ms) } // TestEndpoint is the resolver for the _test_endpoint field. func (r *mutationResolver) TestEndpoint(ctx context.Context, params model.TestEndpointRequest) (*model.TestEndpointResponse, error) { - return resolvers.TestEndpointResolver(ctx, params) + return r.GraphQLProvider.TestEndpoint(ctx, ¶ms) } // AddEmailTemplate is the resolver for the _add_email_template field. func (r *mutationResolver) AddEmailTemplate(ctx context.Context, params model.AddEmailTemplateRequest) (*model.Response, error) { - return resolvers.AddEmailTemplateResolver(ctx, params) + return r.GraphQLProvider.AddEmailTemplate(ctx, ¶ms) } // UpdateEmailTemplate is the resolver for the _update_email_template field. func (r *mutationResolver) UpdateEmailTemplate(ctx context.Context, params model.UpdateEmailTemplateRequest) (*model.Response, error) { - return resolvers.UpdateEmailTemplateResolver(ctx, params) + return r.GraphQLProvider.UpdateEmailTemplate(ctx, ¶ms) } // DeleteEmailTemplate is the resolver for the _delete_email_template field. func (r *mutationResolver) DeleteEmailTemplate(ctx context.Context, params model.DeleteEmailTemplateRequest) (*model.Response, error) { - return resolvers.DeleteEmailTemplateResolver(ctx, params) + return r.GraphQLProvider.DeleteEmailTemplate(ctx, ¶ms) } // Meta is the resolver for the meta field. func (r *queryResolver) Meta(ctx context.Context) (*model.Meta, error) { - return resolvers.MetaResolver(ctx) + return r.GraphQLProvider.Meta(ctx) } // Session is the resolver for the session field. -func (r *queryResolver) Session(ctx context.Context, params *model.SessionQueryInput) (*model.AuthResponse, error) { - return resolvers.SessionResolver(ctx, params) +func (r *queryResolver) Session(ctx context.Context, params *model.SessionQueryRequest) (*model.AuthResponse, error) { + return r.GraphQLProvider.Session(ctx, params) } // Profile is the resolver for the profile field. func (r *queryResolver) Profile(ctx context.Context) (*model.User, error) { - return resolvers.ProfileResolver(ctx) + return r.GraphQLProvider.Profile(ctx) } // ValidateJwtToken is the resolver for the validate_jwt_token field. -func (r *queryResolver) ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) { - return resolvers.ValidateJwtTokenResolver(ctx, params) +func (r *queryResolver) ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenRequest) (*model.ValidateJWTTokenResponse, error) { + return r.GraphQLProvider.ValidateJWTToken(ctx, ¶ms) } // ValidateSession is the resolver for the validate_session field. -func (r *queryResolver) ValidateSession(ctx context.Context, params *model.ValidateSessionInput) (*model.ValidateSessionResponse, error) { - return resolvers.ValidateSessionResolver(ctx, params) +func (r *queryResolver) ValidateSession(ctx context.Context, params *model.ValidateSessionRequest) (*model.ValidateSessionResponse, error) { + return r.GraphQLProvider.ValidateSession(ctx, params) } // Users is the resolver for the _users field. -func (r *queryResolver) Users(ctx context.Context, params *model.PaginatedInput) (*model.Users, error) { - return resolvers.UsersResolver(ctx, params) +func (r *queryResolver) Users(ctx context.Context, params *model.PaginatedRequest) (*model.Users, error) { + return r.GraphQLProvider.Users(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) + return r.GraphQLProvider.User(ctx, ¶ms) } // VerificationRequests is the resolver for the _verification_requests field. -func (r *queryResolver) VerificationRequests(ctx context.Context, params *model.PaginatedInput) (*model.VerificationRequests, error) { - return resolvers.VerificationRequestsResolver(ctx, params) +func (r *queryResolver) VerificationRequests(ctx context.Context, params *model.PaginatedRequest) (*model.VerificationRequests, error) { + return r.GraphQLProvider.VerificationRequests(ctx, params) } // AdminSession is the resolver for the _admin_session field. func (r *queryResolver) AdminSession(ctx context.Context) (*model.Response, error) { - return resolvers.AdminSessionResolver(ctx) + return r.GraphQLProvider.AdminSession(ctx) } // Env is the resolver for the _env field. func (r *queryResolver) Env(ctx context.Context) (*model.Env, error) { - return resolvers.EnvResolver(ctx) + return nil, fmt.Errorf("deprecated. please configure env via cli args") } // Webhook is the resolver for the _webhook field. func (r *queryResolver) Webhook(ctx context.Context, params model.WebhookRequest) (*model.Webhook, error) { - return resolvers.WebhookResolver(ctx, params) + return r.GraphQLProvider.Webhook(ctx, ¶ms) } // Webhooks is the resolver for the _webhooks field. -func (r *queryResolver) Webhooks(ctx context.Context, params *model.PaginatedInput) (*model.Webhooks, error) { - return resolvers.WebhooksResolver(ctx, params) +func (r *queryResolver) Webhooks(ctx context.Context, params *model.PaginatedRequest) (*model.Webhooks, error) { + return r.GraphQLProvider.Webhooks(ctx, params) } // WebhookLogs is the resolver for the _webhook_logs field. func (r *queryResolver) WebhookLogs(ctx context.Context, params *model.ListWebhookLogRequest) (*model.WebhookLogs, error) { - return resolvers.WebhookLogsResolver(ctx, params) + return r.GraphQLProvider.WebhookLogs(ctx, params) } // EmailTemplates is the resolver for the _email_templates field. -func (r *queryResolver) EmailTemplates(ctx context.Context, params *model.PaginatedInput) (*model.EmailTemplates, error) { - return resolvers.EmailTemplatesResolver(ctx, params) +func (r *queryResolver) EmailTemplates(ctx context.Context, params *model.PaginatedRequest) (*model.EmailTemplates, error) { + return r.GraphQLProvider.EmailTemplates(ctx, params) } // Mutation returns generated.MutationResolver implementation. diff --git a/internal/graphql/_deprecated_admin_signup.go b/internal/graphql/_deprecated_admin_signup.go new file mode 100644 index 000000000..d7820e219 --- /dev/null +++ b/internal/graphql/_deprecated_admin_signup.go @@ -0,0 +1,83 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// AdminSignup is a resolver for admin signup +// Permissions: none, +// Deprecated and admin secret can only be set via cli args +func (g *graphqlProvider) AdminSignup(ctx context.Context, params *model.AdminSignupInput) (*model.Response, error) { + // var res *model.Response + + // gc, err := utils.GinContextFromContext(ctx) + // if err != nil { + // log.Debug("Failed to get GinContext: ", err) + // return res, err + // } + + // if strings.TrimSpace(params.AdminSecret) == "" { + // log.Debug("Admin secret is empty") + // err = fmt.Errorf("please select secure admin secret") + // return res, err + // } + + // if len(params.AdminSecret) < 6 { + // log.Debug("Admin secret is too short") + // err = fmt.Errorf("admin secret must be at least 6 characters") + // return res, err + // } + + // adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) + // if err != nil { + // log.Debug("Error getting admin secret: ", err) + // adminSecret = "" + // } + + // if adminSecret != "" { + // log.Debug("Admin secret is already set") + // err = fmt.Errorf("admin sign up already completed") + // return res, err + // } + + // memorystore.Provider.UpdateEnvVariable(constants.EnvKeyAdminSecret, params.AdminSecret) + // // consvert EnvData to JSON + // storeData, err := memorystore.Provider.GetEnvStore() + // if err != nil { + // log.Debug("Error getting env store: ", err) + // return res, err + // } + + // env, err := db.Provider.GetEnv(ctx) + // if err != nil { + // log.Debug("Failed to get env: ", err) + // return res, err + // } + + // envData, err := crypto.EncryptEnvData(storeData) + // if err != nil { + // log.Debug("Failed to encrypt envstore: ", err) + // return res, err + // } + + // env.EnvData = envData + // if _, err := db.Provider.UpdateEnv(ctx, env); err != nil { + // log.Debug("Failed to update env: ", err) + // return res, err + // } + + // hashedKey, err := crypto.EncryptPassword(params.AdminSecret) + // if err != nil { + // log.Debug("Failed to encrypt admin session key: ", err) + // return res, err + // } + // cookie.SetAdminCookie(gc, hashedKey) + + // res = &model.Response{ + // Message: "admin signed up successfully", + // } + return nil, fmt.Errorf("deprecated. please configure admin secret via cli args") +} diff --git a/internal/graphql/_deprecated_env.go b/internal/graphql/_deprecated_env.go new file mode 100644 index 000000000..40af7d84d --- /dev/null +++ b/internal/graphql/_deprecated_env.go @@ -0,0 +1,15 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// Env is a resolver for config query +// Permissions: authorizer:admin +// Deprecated: this is deprecated +func (g *graphqlProvider) Env(ctx context.Context) (*model.Env, error) { + return nil, fmt.Errorf("deprecated") +} diff --git a/internal/graphql/_deprecated_generate_jwt_keys.go b/internal/graphql/_deprecated_generate_jwt_keys.go new file mode 100644 index 000000000..8af0b5a4c --- /dev/null +++ b/internal/graphql/_deprecated_generate_jwt_keys.go @@ -0,0 +1,67 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// GenerateJWTKeysResolver mutation to generate new jwt keys +// Permissions: authorizer:admin +// Deprecated for +func (g *graphqlProvider) GenerateJWTKeysResolver(ctx context.Context, params model.GenerateJWTKeysInput) (*model.GenerateJWTKeysResponse, error) { + // gc, err := utils.GinContextFromContext(ctx) + // if err != nil { + // log.Debug("Failed to get GinContext: ", err) + // return nil, err + // } + + // if !token.IsSuperAdmin(gc) { + // log.Debug("Not logged in as super admin") + // return nil, fmt.Errorf("unauthorized") + // } + + // clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) + // if err != nil { + // log.Debug("Error getting client id: ", err) + // return nil, err + // } + // if crypto.IsHMACA(params.Type) { + // secret, _, err := crypto.NewHMACKey(params.Type, clientID) + // if err != nil { + // log.Debug("Failed to generate new HMAC key: ", err) + // return nil, err + // } + // return &model.GenerateJWTKeysResponse{ + // Secret: &secret, + // }, nil + // } + + // if crypto.IsRSA(params.Type) { + // _, privateKey, publicKey, _, err := crypto.NewRSAKey(params.Type, clientID) + // if err != nil { + // log.Debug("Failed to generate new RSA key: ", err) + // return nil, err + // } + // return &model.GenerateJWTKeysResponse{ + // PrivateKey: &privateKey, + // PublicKey: &publicKey, + // }, nil + // } + + // if crypto.IsECDSA(params.Type) { + // _, privateKey, publicKey, _, err := crypto.NewECDSAKey(params.Type, clientID) + // if err != nil { + // log.Debug("Failed to generate new ECDSA key: ", err) + // return nil, err + // } + // return &model.GenerateJWTKeysResponse{ + // PrivateKey: &privateKey, + // PublicKey: &publicKey, + // }, nil + // } + + // log.Debug("Invalid algorithm: ", params.Type) + return nil, fmt.Errorf("deprecated") +} diff --git a/internal/graphql/_deprecated_mobile_login.go b/internal/graphql/_deprecated_mobile_login.go new file mode 100644 index 000000000..fe6184cbf --- /dev/null +++ b/internal/graphql/_deprecated_mobile_login.go @@ -0,0 +1,213 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// MobileLoginResolver is a resolver for mobile login mutation +func MobileLoginResolver(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error) { + // var res *model.AuthResponse + + // gc, err := utils.GinContextFromContext(ctx) + // if err != nil { + // log.Debug("Failed to get GinContext: ", err) + // return res, err + // } + + // isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication) + // if err != nil { + // log.Debug("Error getting mobile basic auth disabled: ", err) + // isBasicAuthDisabled = true + // } + + // if isBasicAuthDisabled { + // log.Debug("Basic authentication is disabled.") + // return res, fmt.Errorf(`phone number based basic authentication is disabled for this instance`) + // } + + // log := log.WithFields(log.Fields{ + // "phone_number": params.PhoneNumber, + // }) + + // user, err := db.Provider.GetUserByPhoneNumber(ctx, params.PhoneNumber) + // if err != nil { + // log.Debug("Failed to get user by phone number: ", err) + // return res, fmt.Errorf(`bad user credentials`) + // } + + // if user.RevokedTimestamp != nil { + // log.Debug("User access is revoked") + // return res, fmt.Errorf(`user access has been revoked`) + // } + + // if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth) { + // log.Debug("User signup method is not mobile basic auth") + // return res, fmt.Errorf(`user has not signed up with phone number & password`) + // } + + // if user.PhoneNumberVerifiedAt == nil { + // log.Debug("User phone number is not verified") + // return res, fmt.Errorf(`phone number is not verified`) + // } + + // err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(params.Password)) + + // if err != nil { + // log.Debug("Failed to compare password: ", err) + // return res, fmt.Errorf(`bad user credentials`) + // } + + // defaultRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) + // roles := []string{} + // if err != nil { + // log.Debug("Error getting default roles: ", err) + // defaultRolesString = "" + // } else { + // roles = strings.Split(defaultRolesString, ",") + // } + + // currentRoles := strings.Split(user.Roles, ",") + // if len(params.Roles) > 0 { + // if !validators.IsValidRoles(params.Roles, currentRoles) { + // log.Debug("Invalid roles: ", params.Roles) + // return res, fmt.Errorf(`invalid roles`) + // } + + // roles = params.Roles + // } + + // disablePhoneVerification, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) + // if err != nil { + // log.Debug("Error getting disable phone verification: ", err) + // } + // if disablePhoneVerification { + // now := time.Now().Unix() + // user.PhoneNumberVerifiedAt = &now + // } + // isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled) + // if err != nil || !isSMSServiceEnabled { + // log.Debug("SMS service not enabled: ", err) + // } + // if disablePhoneVerification { + // now := time.Now().Unix() + // user.PhoneNumberVerifiedAt = &now + // } + // isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication) + // if err != nil || !isMFADisabled { + // log.Debug("MFA service not enabled: ", err) + // } + // if !disablePhoneVerification && isSMSServiceEnabled && !isMFADisabled { + // duration, _ := time.ParseDuration("10m") + // smsCode := utils.GenerateOTP() + + // smsBody := strings.Builder{} + // smsBody.WriteString("Your verification code is: ") + // smsBody.WriteString(smsCode) + // expires := time.Now().Add(duration).Unix() + // _, err := db.Provider.UpsertOTP(ctx, &models.OTP{ + // PhoneNumber: params.PhoneNumber, + // Otp: smsCode, + // ExpiresAt: expires, + // }) + // if err != nil { + // log.Debug("error while upserting OTP: ", err.Error()) + // return nil, err + // } + + // mfaSession := uuid.NewString() + // err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expires) + // if err != nil { + // log.Debug("Failed to add mfasession: ", err) + // return nil, err + // } + // cookie.SetMfaSession(gc, mfaSession) + + // go func() { + // utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + // smsproviders.SendSMS(params.PhoneNumber, smsBody.String()) + // }() + // return &model.AuthResponse{ + // Message: "Please check the OTP", + // ShouldShowMobileOtpScreen: refs.NewBoolRef(true), + // }, nil + // } + + // scope := []string{"openid", "email", "profile"} + // if params.Scope != nil && len(scope) > 0 { + // scope = params.Scope + // } + + // code := "" + // codeChallenge := "" + // nonce := "" + // if params.State != nil { + // // Get state from store + // authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State)) + // if authorizeState != "" { + // authorizeStateSplit := strings.Split(authorizeState, "@@") + // if len(authorizeStateSplit) > 1 { + // code = authorizeStateSplit[0] + // codeChallenge = authorizeStateSplit[1] + // } else { + // nonce = authorizeState + // } + // go memorystore.Provider.RemoveState(refs.StringValue(params.State)) + // } + // } + + // if nonce == "" { + // nonce = uuid.New().String() + // } + + // authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code) + // if err != nil { + // log.Debug("Failed to create auth token", err) + // return res, err + // } + + // // TODO add to other login options as well + // // Code challenge could be optional if PKCE flow is not used + // if code != "" { + // if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { + // log.Debug("SetState failed: ", err) + // return res, err + // } + // } + + // expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() + // if expiresIn <= 0 { + // expiresIn = 1 + // } + + // res = &model.AuthResponse{ + // Message: `Logged in successfully`, + // AccessToken: &authToken.AccessToken.Token, + // IDToken: &authToken.IDToken.Token, + // ExpiresIn: &expiresIn, + // User: user.AsAPIUser(), + // } + + // cookie.SetSession(gc, authToken.FingerPrintHash) + // sessionStoreKey := constants.AuthRecipeMethodMobileBasicAuth + ":" + user.ID + // memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) + // memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) + + // if authToken.RefreshToken != nil { + // res.RefreshToken = &authToken.RefreshToken.Token + // memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) + // } + + // go func() { + // utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + // db.Provider.AddSession(ctx, &models.Session{ + // UserID: user.ID, + // UserAgent: utils.GetUserAgent(gc.Request), + // IP: utils.GetIP(gc.Request), + // }) + // }() + + return nil, fmt.Errorf("deprecated, use login with mobile phone") +} diff --git a/internal/graphql/_deprecated_mobile_signup.go b/internal/graphql/_deprecated_mobile_signup.go new file mode 100644 index 000000000..b5fdcb020 --- /dev/null +++ b/internal/graphql/_deprecated_mobile_signup.go @@ -0,0 +1,296 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// MobileSignupResolver is a resolver for mobile_basic_auth_signup mutation +func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error) { + // var res *model.AuthResponse + + // gc, err := utils.GinContextFromContext(ctx) + // if err != nil { + // log.Debug("Failed to get GinContext: ", err) + // return res, err + // } + + // isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) + // if err != nil { + // log.Debug("Error getting signup disabled: ", err) + // isSignupDisabled = true + // } + // if isSignupDisabled { + // log.Debug("Signup is disabled") + // return res, fmt.Errorf(`signup is disabled for this instance`) + // } + + // isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication) + // if err != nil { + // log.Debug("Error getting basic auth disabled: ", err) + // isBasicAuthDisabled = true + // } + + // if isBasicAuthDisabled { + // log.Debug("Mobile based Basic authentication is disabled") + // return res, fmt.Errorf(`phone number based basic authentication is disabled for this instance`) + // } + + // if params.ConfirmPassword != params.Password { + // log.Debug("Passwords do not match") + // return res, fmt.Errorf(`password and confirm password does not match`) + // } + + // if err := validators.IsValidPassword(params.Password); err != nil { + // log.Debug("Invalid password") + // return res, err + // } + + // mobile := strings.TrimSpace(params.PhoneNumber) + // if mobile == "" || len(mobile) < 10 { + // log.Debug("Invalid phone number") + // return res, fmt.Errorf("invalid phone number") + // } + + // emailInput := strings.ToLower(strings.TrimSpace(refs.StringValue(params.Email))) + + // // if email is null set random dummy email for db constraint + + // if emailInput != "" && !validators.IsValidEmail(emailInput) { + // log.Debug("Invalid email: ", emailInput) + // return res, fmt.Errorf(`invalid email address`) + // } + + // if emailInput == "" { + // emailInput = mobile + "@authorizer.dev" + // } + + // log := log.WithFields(log.Fields{ + // "email": emailInput, + // "phone_number": mobile, + // }) + // // find user with email + // existingUser, err := db.Provider.GetUserByPhoneNumber(ctx, mobile) + // if err != nil { + // log.Debug("Failed to get user by email: ", err) + // } + // if existingUser != nil { + // if existingUser.PhoneNumberVerifiedAt != nil { + // // email is verified + // log.Debug("Phone number is already verified and signed up.") + // return res, fmt.Errorf(`%s has already signed up`, mobile) + // } else if existingUser.ID != "" && existingUser.PhoneNumberVerifiedAt == nil { + // log.Debug("Phone number is already signed up. Verification pending...") + // return res, fmt.Errorf("%s has already signed up. please complete the phone number verification process or reset the password", mobile) + // } + // } + + // inputRoles := []string{} + // if len(params.Roles) > 0 { + // // check if roles exists + // rolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRoles) + // roles := []string{} + // if err != nil { + // log.Debug("Error getting roles: ", err) + // return res, err + // } else { + // roles = strings.Split(rolesString, ",") + // } + // if !validators.IsValidRoles(params.Roles, roles) { + // log.Debug("Invalid roles: ", params.Roles) + // return res, fmt.Errorf(`invalid roles`) + // } else { + // inputRoles = params.Roles + // } + // } else { + // inputRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) + // if err != nil { + // log.Debug("Error getting default roles: ", err) + // return res, err + // } else { + // inputRoles = strings.Split(inputRolesString, ",") + // } + // } + + // user := &models.User{ + // Email: &emailInput, + // PhoneNumber: &mobile, + // } + + // user.Roles = strings.Join(inputRoles, ",") + + // password, _ := crypto.EncryptPassword(params.Password) + // user.Password = &password + + // if params.GivenName != nil { + // user.GivenName = params.GivenName + // } + + // if params.FamilyName != nil { + // user.FamilyName = params.FamilyName + // } + + // if params.MiddleName != nil { + // user.MiddleName = params.MiddleName + // } + + // if params.Nickname != nil { + // user.Nickname = params.Nickname + // } + + // if params.Gender != nil { + // user.Gender = params.Gender + // } + + // if params.Birthdate != nil { + // user.Birthdate = params.Birthdate + // } + + // if params.Picture != nil { + // user.Picture = params.Picture + // } + + // if params.IsMultiFactorAuthEnabled != nil { + // user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled + // } + + // isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication) + // if err != nil { + // log.Debug("MFA service not enabled: ", err) + // isMFAEnforced = false + // } + + // if isMFAEnforced { + // user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) + // } + + // disablePhoneVerification, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) + // if disablePhoneVerification { + // now := time.Now().Unix() + // user.PhoneNumberVerifiedAt = &now + // } + // isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled) + // if err != nil || !isSMSServiceEnabled { + // log.Debug("SMS service not enabled: ", err) + // } + + // user.SignupMethods = constants.AuthRecipeMethodMobileBasicAuth + // user, err = db.Provider.AddUser(ctx, user) + + // if err != nil { + // log.Debug("Failed to add user: ", err) + // return res, err + // } + // if !disablePhoneVerification && isSMSServiceEnabled { + // duration, _ := time.ParseDuration("10m") + // smsCode := utils.GenerateOTP() + + // smsBody := strings.Builder{} + // smsBody.WriteString("Your verification code is: ") + // smsBody.WriteString(smsCode) + + // // TODO: For those who enabled the webhook to call their sms vendor separately - sending the otp to their api + // if err != nil { + // log.Debug("error while upserting user: ", err.Error()) + // return nil, err + // } + // _, err = db.Provider.UpsertOTP(ctx, &models.OTP{ + // PhoneNumber: mobile, + // Otp: smsCode, + // ExpiresAt: time.Now().Add(duration).Unix(), + // }) + // if err != nil { + // log.Debug("error while upserting OTP: ", err.Error()) + // return nil, err + // } + // go func() { + // smsproviders.SendSMS(mobile, smsBody.String()) + // utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) + // }() + // return &model.AuthResponse{ + // Message: "Please check the OTP in your inbox", + // ShouldShowMobileOtpScreen: refs.NewBoolRef(true), + // }, nil + // } + + // roles := strings.Split(user.Roles, ",") + // userToReturn := user.AsAPIUser() + + // scope := []string{"openid", "email", "profile"} + // if params.Scope != nil && len(scope) > 0 { + // scope = params.Scope + // } + + // code := "" + // codeChallenge := "" + // nonce := "" + // if params.State != nil { + // // Get state from store + // authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State)) + // if authorizeState != "" { + // authorizeStateSplit := strings.Split(authorizeState, "@@") + // if len(authorizeStateSplit) > 1 { + // code = authorizeStateSplit[0] + // codeChallenge = authorizeStateSplit[1] + // } else { + // nonce = authorizeState + // } + // go memorystore.Provider.RemoveState(refs.StringValue(params.State)) + // } + // } + + // if nonce == "" { + // nonce = uuid.New().String() + // } + + // authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code) + // if err != nil { + // log.Debug("Failed to create auth token: ", err) + // return res, err + // } + + // // Code challenge could be optional if PKCE flow is not used + // if code != "" { + // if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { + // log.Debug("SetState failed: ", err) + // return res, err + // } + // } + + // expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() + // if expiresIn <= 0 { + // expiresIn = 1 + // } + + // res = &model.AuthResponse{ + // Message: `Signed up successfully.`, + // AccessToken: &authToken.AccessToken.Token, + // ExpiresIn: &expiresIn, + // User: userToReturn, + // } + + // sessionKey := constants.AuthRecipeMethodMobileBasicAuth + ":" + user.ID + // cookie.SetSession(gc, 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, authToken.AccessToken.ExpiresAt) + + // if authToken.RefreshToken != nil { + // res.RefreshToken = &authToken.RefreshToken.Token + // memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) + // } + + // go func() { + // utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + // // User is also logged in with signup + // utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + // db.Provider.AddSession(ctx, &models.Session{ + // UserID: user.ID, + // UserAgent: utils.GetUserAgent(gc.Request), + // IP: utils.GetIP(gc.Request), + // }) + // }() + + return nil, fmt.Errorf("deprecated, use signup with mobile phone") +} diff --git a/internal/graphql/_deprecated_update_env.go b/internal/graphql/_deprecated_update_env.go new file mode 100644 index 000000000..9e4a0f729 --- /dev/null +++ b/internal/graphql/_deprecated_update_env.go @@ -0,0 +1,429 @@ +package graphql + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/db" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/memorystore" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// check if login methods have been disabled +// remove the session tokens for those methods +// TODO: run on start up of service +func clearSessionIfRequired(currentData, updatedData map[string]interface{}) { + isCurrentBasicAuthEnabled := !currentData[constants.EnvKeyDisableBasicAuthentication].(bool) + isCurrentMobileBasicAuthEnabled := !currentData[constants.EnvKeyDisableMobileBasicAuthentication].(bool) + isCurrentMagicLinkLoginEnabled := !currentData[constants.EnvKeyDisableMagicLinkLogin].(bool) + isCurrentAppleLoginEnabled := currentData[constants.EnvKeyAppleClientID] != nil && currentData[constants.EnvKeyAppleClientSecret] != nil && currentData[constants.EnvKeyAppleClientID].(string) != "" && currentData[constants.EnvKeyAppleClientSecret].(string) != "" + isCurrentFacebookLoginEnabled := currentData[constants.EnvKeyFacebookClientID] != nil && currentData[constants.EnvKeyFacebookClientSecret] != nil && currentData[constants.EnvKeyFacebookClientID].(string) != "" && currentData[constants.EnvKeyFacebookClientSecret].(string) != "" + isCurrentGoogleLoginEnabled := currentData[constants.EnvKeyGoogleClientID] != nil && currentData[constants.EnvKeyGoogleClientSecret] != nil && currentData[constants.EnvKeyGoogleClientID].(string) != "" && currentData[constants.EnvKeyGoogleClientSecret].(string) != "" + isCurrentGithubLoginEnabled := currentData[constants.EnvKeyGithubClientID] != nil && currentData[constants.EnvKeyGithubClientSecret] != nil && currentData[constants.EnvKeyGithubClientID].(string) != "" && currentData[constants.EnvKeyGithubClientSecret].(string) != "" + isCurrentLinkedInLoginEnabled := currentData[constants.EnvKeyLinkedInClientID] != nil && currentData[constants.EnvKeyLinkedInClientSecret] != nil && currentData[constants.EnvKeyLinkedInClientID].(string) != "" && currentData[constants.EnvKeyLinkedInClientSecret].(string) != "" + isCurrentTwitterLoginEnabled := currentData[constants.EnvKeyTwitterClientID] != nil && currentData[constants.EnvKeyTwitterClientSecret] != nil && currentData[constants.EnvKeyTwitterClientID].(string) != "" && currentData[constants.EnvKeyTwitterClientSecret].(string) != "" + isCurrentMicrosoftLoginEnabled := currentData[constants.EnvKeyMicrosoftClientID] != nil && currentData[constants.EnvKeyMicrosoftClientSecret] != nil && currentData[constants.EnvKeyMicrosoftClientID].(string) != "" && currentData[constants.EnvKeyMicrosoftClientSecret].(string) != "" + isCurrentTwitchLoginEnabled := currentData[constants.EnvKeyTwitchClientID] != nil && currentData[constants.EnvKeyTwitchClientSecret] != nil && currentData[constants.EnvKeyTwitchClientID].(string) != "" && currentData[constants.EnvKeyTwitchClientSecret].(string) != "" + + isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool) + isUpdatedMobileBasicAuthEnabled := !updatedData[constants.EnvKeyDisableMobileBasicAuthentication].(bool) + isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool) + isUpdatedAppleLoginEnabled := updatedData[constants.EnvKeyAppleClientID] != nil && updatedData[constants.EnvKeyAppleClientSecret] != nil && updatedData[constants.EnvKeyAppleClientID].(string) != "" && updatedData[constants.EnvKeyAppleClientSecret].(string) != "" + isUpdatedFacebookLoginEnabled := updatedData[constants.EnvKeyFacebookClientID] != nil && updatedData[constants.EnvKeyFacebookClientSecret] != nil && updatedData[constants.EnvKeyFacebookClientID].(string) != "" && updatedData[constants.EnvKeyFacebookClientSecret].(string) != "" + isUpdatedGoogleLoginEnabled := updatedData[constants.EnvKeyGoogleClientID] != nil && updatedData[constants.EnvKeyGoogleClientSecret] != nil && updatedData[constants.EnvKeyGoogleClientID].(string) != "" && updatedData[constants.EnvKeyGoogleClientSecret].(string) != "" + isUpdatedGithubLoginEnabled := updatedData[constants.EnvKeyGithubClientID] != nil && updatedData[constants.EnvKeyGithubClientSecret] != nil && updatedData[constants.EnvKeyGithubClientID].(string) != "" && updatedData[constants.EnvKeyGithubClientSecret].(string) != "" + isUpdatedLinkedInLoginEnabled := updatedData[constants.EnvKeyLinkedInClientID] != nil && updatedData[constants.EnvKeyLinkedInClientSecret] != nil && updatedData[constants.EnvKeyLinkedInClientID].(string) != "" && updatedData[constants.EnvKeyLinkedInClientSecret].(string) != "" + isUpdatedTwitterLoginEnabled := updatedData[constants.EnvKeyTwitterClientID] != nil && updatedData[constants.EnvKeyTwitterClientSecret] != nil && updatedData[constants.EnvKeyTwitterClientID].(string) != "" && updatedData[constants.EnvKeyTwitterClientSecret].(string) != "" + isUpdatedMicrosoftLoginEnabled := updatedData[constants.EnvKeyMicrosoftClientID] != nil && updatedData[constants.EnvKeyMicrosoftClientSecret] != nil && updatedData[constants.EnvKeyMicrosoftClientID].(string) != "" && updatedData[constants.EnvKeyMicrosoftClientSecret].(string) != "" + isUpdatedTwitchLoginEnabled := updatedData[constants.EnvKeyTwitchClientID] != nil && updatedData[constants.EnvKeyTwitchClientSecret] != nil && updatedData[constants.EnvKeyTwitchClientID].(string) != "" && updatedData[constants.EnvKeyTwitchClientSecret].(string) != "" + + if isCurrentBasicAuthEnabled && !isUpdatedBasicAuthEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth) + } + + if isCurrentMobileBasicAuthEnabled && !isUpdatedMobileBasicAuthEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMobileBasicAuth) + } + + if isCurrentMagicLinkLoginEnabled && !isUpdatedMagicLinkLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMagicLinkLogin) + } + + if isCurrentAppleLoginEnabled && !isUpdatedAppleLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodApple) + } + + if isCurrentFacebookLoginEnabled && !isUpdatedFacebookLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodFacebook) + } + + if isCurrentGoogleLoginEnabled && !isUpdatedGoogleLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodGoogle) + } + + if isCurrentGithubLoginEnabled && !isUpdatedGithubLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodGithub) + } + + if isCurrentLinkedInLoginEnabled && !isUpdatedLinkedInLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodLinkedIn) + } + + if isCurrentTwitterLoginEnabled && !isUpdatedTwitterLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodTwitter) + } + + if isCurrentMicrosoftLoginEnabled && !isUpdatedMicrosoftLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMicrosoft) + } + + if isCurrentTwitchLoginEnabled && !isUpdatedTwitchLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodTwitch) + } +} + +// updateRoles will update DB for user roles, if a role is deleted by admin +// then this function will those roles from user roles if exists +// TODO: run on start up of service +func updateRoles(ctx context.Context, deletedRoles []string) error { + data, err := db.Provider.ListUsers(ctx, &model.Pagination{ + Limit: 1, + Offset: 1, + }) + if err != nil { + return err + } + + allData, err := db.Provider.ListUsers(ctx, &model.Pagination{ + Limit: data.Pagination.Total, + }) + if err != nil { + return err + } + + chunkSize := 1000 + totalUsers := len(allData.Users) + + for start := 0; start < totalUsers; start += chunkSize { + end := start + chunkSize + if end > totalUsers { + end = totalUsers + } + + chunkUsers := allData.Users[start:end] + + for i := range chunkUsers { + roles := utils.DeleteFromArray(chunkUsers[i].Roles, deletedRoles) + if len(chunkUsers[i].Roles) != len(roles) { + updatedValues := map[string]interface{}{ + "roles": strings.Join(roles, ","), + "updated_at": time.Now().Unix(), + } + id := []string{chunkUsers[i].ID} + err = db.Provider.UpdateUsers(ctx, updatedValues, id) + if err != nil { + return err + } + } + } + } + return nil +} + +// UpdateEnvResolver is a resolver for update config mutation +// This is admin only mutation +func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model.Response, error) { + // var res *model.Response + + // gc, err := utils.GinContextFromContext(ctx) + // if err != nil { + // log.Debug("Failed to get GinContext: ", err) + // return res, err + // } + + // if !token.IsSuperAdmin(gc) { + // log.Debug("Not logged in as super admin") + // return res, fmt.Errorf("unauthorized") + // } + + // currentData, err := memorystore.Provider.GetEnvStore() + // if err != nil { + // log.Debug("Failed to get env store: ", err) + // return res, err + // } + + // // clone currentData in new var + // // that will be updated based on the req + // updatedData := make(map[string]interface{}) + // for key, val := range currentData { + // updatedData[key] = val + // } + + // isJWTUpdated := false + // algo := updatedData[constants.EnvKeyJwtType].(string) + // if params.JwtType != nil { + // algo = *params.JwtType + // if !crypto.IsHMACA(algo) && !crypto.IsECDSA(algo) && !crypto.IsRSA(algo) { + // log.Debug("Invalid JWT type: ", algo) + // return res, fmt.Errorf("invalid jwt type") + // } + + // updatedData[constants.EnvKeyJwtType] = algo + // isJWTUpdated = true + // } + + // if params.JwtSecret != nil || params.JwtPublicKey != nil || params.JwtPrivateKey != nil { + // isJWTUpdated = true + // } + + // if isJWTUpdated { + // // use to reset when type is changed from rsa, edsa -> hmac or vice a versa + // defaultSecret := "" + // defaultPublicKey := "" + // defaultPrivateKey := "" + // // check if jwt secret is provided + // if crypto.IsHMACA(algo) { + // if params.JwtSecret == nil { + // log.Debug("JWT secret is required for HMAC") + // return res, fmt.Errorf("jwt secret is required for HMAC algorithm") + // } + + // // reset public key and private key + // params.JwtPrivateKey = &defaultPrivateKey + // params.JwtPublicKey = &defaultPublicKey + // } + + // if crypto.IsRSA(algo) { + // if params.JwtPrivateKey == nil || params.JwtPublicKey == nil { + // log.Debug("JWT private key and public key are required for RSA: ", *params.JwtPrivateKey, *params.JwtPublicKey) + // return res, fmt.Errorf("jwt private and public key is required for RSA (PKCS1) / ECDSA algorithm") + // } + + // // reset the jwt secret + // params.JwtSecret = &defaultSecret + // _, err = crypto.ParseRsaPrivateKeyFromPemStr(*params.JwtPrivateKey) + // if err != nil { + // log.Debug("Invalid JWT private key: ", err) + // return res, err + // } + + // _, err := crypto.ParseRsaPublicKeyFromPemStr(*params.JwtPublicKey) + // if err != nil { + // log.Debug("Invalid JWT public key: ", err) + // return res, err + // } + // } + + // if crypto.IsECDSA(algo) { + // if params.JwtPrivateKey == nil || params.JwtPublicKey == nil { + // log.Debug("JWT private key and public key are required for ECDSA: ", *params.JwtPrivateKey, *params.JwtPublicKey) + // return res, fmt.Errorf("jwt private and public key is required for RSA (PKCS1) / ECDSA algorithm") + // } + + // // reset the jwt secret + // params.JwtSecret = &defaultSecret + // _, err = crypto.ParseEcdsaPrivateKeyFromPemStr(*params.JwtPrivateKey) + // if err != nil { + // log.Debug("Invalid JWT private key: ", err) + // return res, err + // } + + // _, err := crypto.ParseEcdsaPublicKeyFromPemStr(*params.JwtPublicKey) + // if err != nil { + // log.Debug("Invalid JWT public key: ", err) + // return res, err + // } + // } + + // } + + // var data map[string]interface{} + // byteData, err := json.Marshal(params) + // if err != nil { + // log.Debug("Failed to marshal update env input: ", err) + // return res, fmt.Errorf("error marshalling params: %t", err) + // } + + // err = json.Unmarshal(byteData, &data) + // if err != nil { + // log.Debug("Failed to unmarshal update env input: ", err) + // return res, fmt.Errorf("error un-marshalling params: %t", err) + // } + + // // in case of admin secret change update the cookie with new hash + // if params.AdminSecret != nil { + // if params.OldAdminSecret == nil { + // log.Debug("Old admin secret is required for admin secret update") + // return res, errors.New("admin secret and old admin secret are required for secret change") + // } + // oldAdminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) + // if err != nil { + // log.Debug("Failed to get old admin secret: ", err) + // return res, err + // } + // if *params.OldAdminSecret != oldAdminSecret { + // log.Debug("Old admin secret is invalid") + // return res, errors.New("old admin secret is not correct") + // } + + // if len(*params.AdminSecret) < 6 { + // log.Debug("Admin secret is too short") + // err = fmt.Errorf("admin secret must be at least 6 characters") + // return res, err + // } + + // } + + // for key, value := range data { + // if value != nil { + // fieldType := reflect.TypeOf(value).String() + + // if fieldType == "string" { + // updatedData[key] = value.(string) + // } + + // if fieldType == "bool" { + // updatedData[key] = value.(bool) + // } + // if fieldType == "[]interface {}" { + // stringArr := utils.ConvertInterfaceToStringSlice(value) + // updatedData[key] = strings.Join(stringArr, ",") + // } + // } + // } + + // // handle derivative cases like disabling email verification & magic login + // // in case SMTP is off but env is set to true + // if updatedData[constants.EnvKeySmtpHost] == "" || updatedData[constants.EnvKeySmtpUsername] == "" || updatedData[constants.EnvKeySmtpPassword] == "" || updatedData[constants.EnvKeySenderEmail] == "" && updatedData[constants.EnvKeySmtpPort] == "" { + // updatedData[constants.EnvKeyIsEmailServiceEnabled] = false + // if !updatedData[constants.EnvKeyDisableEmailVerification].(bool) { + // updatedData[constants.EnvKeyDisableEmailVerification] = true + // } + // if !updatedData[constants.EnvKeyDisableMailOTPLogin].(bool) { + // updatedData[constants.EnvKeyDisableMailOTPLogin] = true + // } + // if !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool) { + // updatedData[constants.EnvKeyDisableMailOTPLogin] = true + // } + // } + + // if updatedData[constants.EnvKeySmtpHost] != "" || updatedData[constants.EnvKeySmtpUsername] != "" || updatedData[constants.EnvKeySmtpPassword] != "" || updatedData[constants.EnvKeySenderEmail] != "" && updatedData[constants.EnvKeySmtpPort] != "" { + // updatedData[constants.EnvKeyIsEmailServiceEnabled] = true + // } + + // if updatedData[constants.EnvKeyTwilioAPIKey] == "" || updatedData[constants.EnvKeyTwilioAPISecret] == "" || updatedData[constants.EnvKeyTwilioAccountSID] == "" || updatedData[constants.EnvKeyTwilioSender] == "" { + // updatedData[constants.EnvKeyIsSMSServiceEnabled] = false + // if !updatedData[constants.EnvKeyIsSMSServiceEnabled].(bool) { + // updatedData[constants.EnvKeyDisablePhoneVerification] = true + // } + // } + + // if updatedData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) && updatedData[constants.EnvKeyIsEmailServiceEnabled].(bool) { + // updatedData[constants.EnvKeyDisableMailOTPLogin] = true + // } + + // if !currentData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && updatedData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && !updatedData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) { + // go db.Provider.UpdateUsers(ctx, map[string]interface{}{ + // "is_multi_factor_auth_enabled": true, + // }, nil) + // } + + // previousRoles := strings.Split(currentData[constants.EnvKeyRoles].(string), ",") + // previousProtectedRoles := strings.Split(currentData[constants.EnvKeyProtectedRoles].(string), ",") + // updatedRoles := strings.Split(updatedData[constants.EnvKeyRoles].(string), ",") + // updatedDefaultRoles := strings.Split(updatedData[constants.EnvKeyDefaultRoles].(string), ",") + // updatedProtectedRoles := strings.Split(updatedData[constants.EnvKeyProtectedRoles].(string), ",") + // // check the roles change + // if len(updatedRoles) > 0 && len(updatedDefaultRoles) > 0 { + // // should be subset of roles + // for _, role := range updatedDefaultRoles { + // if !utils.StringSliceContains(updatedRoles, role) { + // log.Debug("Default roles should be subset of roles") + // return res, fmt.Errorf("default role %s is not in roles", role) + // } + // } + // } + + // if len(updatedProtectedRoles) > 0 { + // for _, role := range updatedProtectedRoles { + // if utils.StringSliceContains(updatedRoles, role) || utils.StringSliceContains(updatedDefaultRoles, role) { + // log.Debug("Protected roles should not be in roles or default roles") + // return res, fmt.Errorf("protected role %s found roles or default roles", role) + // } + // } + // } + + // deletedRoles := utils.FindDeletedValues(previousRoles, updatedRoles) + // if len(deletedRoles) > 0 { + // go updateRoles(ctx, deletedRoles) + // } + + // deletedProtectedRoles := utils.FindDeletedValues(previousProtectedRoles, updatedProtectedRoles) + // if len(deletedProtectedRoles) > 0 { + // go updateRoles(ctx, deletedProtectedRoles) + // } + + // // Update local store + // memorystore.Provider.UpdateEnvStore(updatedData) + // jwk, err := crypto.GenerateJWKBasedOnEnv() + // if err != nil { + // log.Debug("Failed to generate JWK: ", err) + // return res, err + // } + // // updating jwk + // err = memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJWK, jwk) + // if err != nil { + // log.Debug("Failed to update JWK: ", err) + // return res, err + // } + + // err = oauth.InitOAuth() + // if err != nil { + // return res, err + // } + + // // Fetch the current db store and update it + // env, err := db.Provider.GetEnv(ctx) + // if err != nil { + // log.Debug("Failed to get env: ", err) + // return res, err + // } + + // if params.AdminSecret != nil { + // adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) + // if err != nil { + // log.Debug("Failed to get admin secret: ", err) + // return res, err + // } + // hashedKey, err := crypto.EncryptPassword(adminSecret) + // if err != nil { + // log.Debug("Failed to encrypt admin secret: ", err) + // return res, err + // } + // cookie.SetAdminCookie(gc, hashedKey) + // } + + // encryptedConfig, err := crypto.EncryptEnvData(updatedData) + // if err != nil { + // log.Debug("Failed to encrypt env data: ", err) + // return res, err + // } + + // env.EnvData = encryptedConfig + // _, err = db.Provider.UpdateEnv(ctx, env) + // if err != nil { + // log.Debug("Failed to update env: ", err) + // return res, err + // } + + // go clearSessionIfRequired(currentData, updatedData) + + // res = &model.Response{ + // Message: "configurations updated successfully", + // } + return nil, fmt.Errorf("deprecated") +} diff --git a/internal/graphql/add_email_template.go b/internal/graphql/add_email_template.go new file mode 100644 index 000000000..e487a007f --- /dev/null +++ b/internal/graphql/add_email_template.go @@ -0,0 +1,64 @@ +package graphql + +import ( + "context" + "fmt" + "strings" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" +) + +// AddEmailTemplate is the method to add email template. +// Permissions: authorizer:admin +func (g *graphqlProvider) AddEmailTemplate(ctx context.Context, params *model.AddEmailTemplateRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "AddEmailTemplate").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + if !validators.IsValidEmailTemplateEventName(params.EventName) { + log.Debug().Str("EventName", params.EventName).Msg("Invalid Event Name") + return nil, fmt.Errorf("invalid event name %s", params.EventName) + } + + if strings.TrimSpace(params.Subject) == "" { + log.Debug().Msg("subject is missing") + return nil, fmt.Errorf("empty subject not allowed") + } + + if strings.TrimSpace(params.Template) == "" { + log.Debug().Msg("template is missing") + return nil, fmt.Errorf("empty template not allowed") + } + + var design string + + if params.Design == nil || strings.TrimSpace(refs.StringValue(params.Design)) == "" { + design = "" + } + + _, err = g.StorageProvider.AddEmailTemplate(ctx, &schemas.EmailTemplate{ + EventName: params.EventName, + Template: params.Template, + Subject: params.Subject, + Design: design, + }) + if err != nil { + log.Debug().Err(err).Msg("Failed to add email template in db") + return nil, err + } + + return &model.Response{ + Message: `Email template added successfully`, + }, nil +} diff --git a/server/resolvers/add_webhook.go b/internal/graphql/add_webhook.go similarity index 51% rename from server/resolvers/add_webhook.go rename to internal/graphql/add_webhook.go index 3380779e9..a92af1f15 100644 --- a/server/resolvers/add_webhook.go +++ b/internal/graphql/add_webhook.go @@ -1,4 +1,4 @@ -package resolvers +package graphql import ( "context" @@ -6,33 +6,32 @@ import ( "fmt" "strings" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" - log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" ) -// AddWebhookResolver resolver for add webhook mutation -func AddWebhookResolver(ctx context.Context, params model.AddWebhookRequest) (*model.Response, error) { +// AddWebhook is the method to add webhook. +// Permissions: authorizer:admin +func (g *graphqlProvider) AddWebhook(ctx context.Context, params *model.AddWebhookRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "AddWebhook").Logger() gc, err := utils.GinContextFromContext(ctx) if err != nil { - log.Debug("Failed to get GinContext: ", err) + log.Debug().Err(err).Msg("Failed to get GinContext") return nil, err } - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") return nil, fmt.Errorf("unauthorized") } if !validators.IsValidWebhookEventName(params.EventName) { - log.Debug("Invalid Event Name: ", params.EventName) + log.Debug().Str("EventName", params.EventName).Msg("Invalid Event Name") return nil, fmt.Errorf("invalid event name %s", params.EventName) } if strings.TrimSpace(params.Endpoint) == "" { - log.Debug("empty endpoint not allowed") + log.Debug().Msg("endpoint is missing") return nil, fmt.Errorf("empty endpoint not allowed") } headerBytes, err := json.Marshal(params.Headers) @@ -43,7 +42,7 @@ func AddWebhookResolver(ctx context.Context, params model.AddWebhookRequest) (*m if params.EventDescription == nil { params.EventDescription = refs.NewStringRef(strings.Join(strings.Split(params.EventName, "."), " ")) } - _, err = db.Provider.AddWebhook(ctx, &models.Webhook{ + _, err = g.StorageProvider.AddWebhook(ctx, &schemas.Webhook{ EventDescription: refs.StringValue(params.EventDescription), EventName: params.EventName, EndPoint: params.Endpoint, @@ -51,7 +50,7 @@ func AddWebhookResolver(ctx context.Context, params model.AddWebhookRequest) (*m Headers: string(headerBytes), }) if err != nil { - log.Debug("Failed to add webhook: ", err) + log.Debug().Err(err).Msg("Failed to add webhook in db") return nil, err } diff --git a/internal/graphql/admin_login.go b/internal/graphql/admin_login.go new file mode 100644 index 000000000..e35e0ab40 --- /dev/null +++ b/internal/graphql/admin_login.go @@ -0,0 +1,38 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// AdminLogin is the method to login as admin. +// Permissions: none +func (g *graphqlProvider) AdminLogin(ctx context.Context, params *model.AdminLoginRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "AdminLogin").Logger() + var res *model.Response + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return res, fmt.Errorf("internal server error") + } + if params.AdminSecret != g.Config.AdminSecret { + log.Debug().Msg("Invalid admin secret") + return res, fmt.Errorf(`invalid admin secret`) + } + + hashedKey, err := crypto.EncryptPassword(g.Config.AdminSecret) + if err != nil { + return res, err + } + cookie.SetAdminCookie(gc, hashedKey, g.Config.AdminCookieSecure) + + res = &model.Response{ + Message: "admin logged in successfully", + } + return res, nil +} diff --git a/internal/graphql/admin_logout.go b/internal/graphql/admin_logout.go new file mode 100644 index 000000000..fc7f127bc --- /dev/null +++ b/internal/graphql/admin_logout.go @@ -0,0 +1,32 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// AdminLogout is the method to logout as admin. +// Permissions: authorizer:admin +func (g *graphqlProvider) AdminLogout(ctx context.Context) (*model.Response, error) { + log := g.Log.With().Str("func", "AdminLogout").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + cookie.DeleteAdminCookie(gc, g.Config.AdminCookieSecure) + + res := &model.Response{ + Message: "admin logged out successfully", + } + return res, nil +} diff --git a/internal/graphql/admin_session.go b/internal/graphql/admin_session.go new file mode 100644 index 000000000..db00fecfe --- /dev/null +++ b/internal/graphql/admin_session.go @@ -0,0 +1,37 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// AdminSession is the method to get admin session. +// Permissions: authorizer:admin +func (g *graphqlProvider) AdminSession(ctx context.Context) (*model.Response, error) { + log := g.Log.With().Str("func", "AdminLogout").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + hashedKey, err := crypto.EncryptPassword(g.Config.AdminSecret) + if err != nil { + log.Debug().Err(err).Msg("Failed to encrypt admin secret") + return nil, err + } + cookie.SetAdminCookie(gc, hashedKey, g.Config.AdminCookieSecure) + + res := &model.Response{ + Message: "admin session refreshed successfully", + } + return res, nil +} diff --git a/internal/graphql/deactivate_account.go b/internal/graphql/deactivate_account.go new file mode 100644 index 000000000..9e7aa5f46 --- /dev/null +++ b/internal/graphql/deactivate_account.go @@ -0,0 +1,49 @@ +package graphql + +import ( + "context" + "time" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// DeactivateAccount is the method for the deactivate_account field. +// Permissions: authorized user +func (g *graphqlProvider) DeactivateAccount(ctx context.Context) (*model.Response, error) { + log := g.Log.With().Str("func", "DeactivateAccount").Logger() + var res *model.Response + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return res, err + } + + tokenData, err := g.TokenProvider.GetUserIDFromSessionOrAccessToken(gc) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user id from session or access token") + return res, err + } + log = log.With().Str("userID", tokenData.UserID).Logger() + user, err := g.StorageProvider.GetUserByID(ctx, tokenData.UserID) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by id") + return res, err + } + now := time.Now().Unix() + user.RevokedTimestamp = &now + user, err = g.StorageProvider.UpdateUser(ctx, user) + if err != nil { + log.Debug().Err(err).Msg("Failed to update user") + return res, err + } + go func() { + g.MemoryStoreProvider.DeleteAllUserSessions(user.ID) + g.EventsProvider.RegisterEvent(ctx, constants.UserDeactivatedWebhookEvent, "", user) + }() + res = &model.Response{ + Message: `user account deactivated successfully`, + } + return res, nil +} diff --git a/internal/graphql/delete_email_template.go b/internal/graphql/delete_email_template.go new file mode 100644 index 000000000..cdc3c1bbc --- /dev/null +++ b/internal/graphql/delete_email_template.go @@ -0,0 +1,48 @@ +package graphql + +import ( + "context" + "fmt" + "strings" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// DeleteEmailTemplate is the method to delete an email template. +// Permissions: authorizer:admin +func (g *graphqlProvider) DeleteEmailTemplate(ctx context.Context, params *model.DeleteEmailTemplateRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "DeleteEmailTemplate").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + if strings.TrimSpace(params.ID) == "" { + return nil, fmt.Errorf("email template ID required") + } + + log = log.With().Str("emailTemplateID", params.ID).Logger() + + emailTemplate, err := g.StorageProvider.GetEmailTemplateByID(ctx, params.ID) + if err != nil { + log.Debug().Err(err).Msg("Failed to get email template by id") + return nil, err + } + + err = g.StorageProvider.DeleteEmailTemplate(ctx, emailTemplate) + if err != nil { + log.Debug().Err(err).Msg("Failed to delete email template") + return nil, err + } + + return &model.Response{ + Message: "Email templated deleted successfully", + }, nil +} diff --git a/internal/graphql/delete_user.go b/internal/graphql/delete_user.go new file mode 100644 index 000000000..0d6742a6c --- /dev/null +++ b/internal/graphql/delete_user.go @@ -0,0 +1,94 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// DeleteUser is the method to delete a user. +// Permissions: authorizer:admin +func (g *graphqlProvider) DeleteUser(ctx context.Context, params *model.DeleteUserRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "DeleteUser").Logger() + + var res *model.Response + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return res, err + } + + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + log = log.With().Str("email", params.Email).Logger() + user, err := g.StorageProvider.GetUserByEmail(ctx, params.Email) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by email") + return res, err + } + + err = g.StorageProvider.DeleteUser(ctx, user) + if err != nil { + log.Debug().Err(err).Msg("Failed to delete user") + return res, err + } + + res = &model.Response{ + Message: `user deleted successfully`, + } + + go func() { + // delete otp for given email + otp, err := g.StorageProvider.GetOTPByEmail(ctx, refs.StringValue(user.Email)) + if err != nil { + log.Debug().Err(err).Msg("No OTP found for email") + // continue + } else { + err := g.StorageProvider.DeleteOTP(ctx, otp) + if err != nil { + log.Debug().Err(err).Msg("Failed to delete otp for given email") + // continue + } + } + + // delete otp for given phone number + otp, err = g.StorageProvider.GetOTPByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)) + if err != nil { + log.Debug().Err(err).Msg("No OTP found for phone number") + // continue + } else { + err := g.StorageProvider.DeleteOTP(ctx, otp) + if err != nil { + log.Debug().Err(err).Msg("Failed to delete otp for given phone number") + // continue + } + } + + // delete verification requests for given email + for _, vt := range constants.VerificationTypes { + verificationRequest, err := g.StorageProvider.GetVerificationRequestByEmail(ctx, refs.StringValue(user.Email), vt) + if err != nil { + log.Debug().Err(err).Msg("No verification request found for email") + // continue + } else { + err := g.StorageProvider.DeleteVerificationRequest(ctx, verificationRequest) + if err != nil { + log.Debug().Err(err).Msg("Failed to delete verification request for given email") + // continue + } + } + } + + g.MemoryStoreProvider.DeleteAllUserSessions(user.ID) + g.EventsProvider.RegisterEvent(ctx, constants.UserDeletedWebhookEvent, "", user) + }() + + return res, nil +} diff --git a/internal/graphql/delete_webhook.go b/internal/graphql/delete_webhook.go new file mode 100644 index 000000000..0df0e9f9c --- /dev/null +++ b/internal/graphql/delete_webhook.go @@ -0,0 +1,48 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// DeleteWebhook is the method to delete a webhook. +// Permissions: authorizer:admin +func (g *graphqlProvider) DeleteWebhook(ctx context.Context, params *model.WebhookRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "DeleteWebhook").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + if params.ID == "" { + log.Debug().Msg("Webhook ID required") + return nil, fmt.Errorf("webhook ID required") + } + + log = log.With().Str("webhookID", params.ID).Logger() + + webhook, err := g.StorageProvider.GetWebhookByID(ctx, params.ID) + if err != nil { + log.Debug().Err(err).Msg("Failed to get webhook by ID") + return nil, err + } + + err = g.StorageProvider.DeleteWebhook(ctx, webhook) + if err != nil { + log.Debug().Err(err).Msg("Failed to delete webhook") + return nil, err + } + + return &model.Response{ + Message: "Webhook deleted successfully", + }, nil +} diff --git a/internal/graphql/email_templates.go b/internal/graphql/email_templates.go new file mode 100644 index 000000000..eac83a127 --- /dev/null +++ b/internal/graphql/email_templates.go @@ -0,0 +1,41 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// EmailTemplates is the method to get all email templates. +// Permissions: authorizer:admin +func (g *graphqlProvider) EmailTemplates(ctx context.Context, params *model.PaginatedRequest) (*model.EmailTemplates, error) { + log := g.Log.With().Str("func", "EmailTemplates").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + pagination := utils.GetPagination(params) + emailTemplates, pagination, err := g.StorageProvider.ListEmailTemplate(ctx, pagination) + if err != nil { + log.Debug().Err(err).Msg("Failed to get email templates") + return nil, err + } + resItems := make([]*model.EmailTemplate, len(emailTemplates)) + for _, emailTemplate := range emailTemplates { + resItems = append(resItems, emailTemplate.AsAPIEmailTemplate()) + } + + return &model.EmailTemplates{ + Pagination: pagination, + EmailTemplates: resItems, + }, nil +} diff --git a/internal/graphql/enable_access.go b/internal/graphql/enable_access.go new file mode 100644 index 000000000..f4f516dd6 --- /dev/null +++ b/internal/graphql/enable_access.go @@ -0,0 +1,52 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// EnableAccess is the method to enable access for a user. +// Permissions: authorizer:admin +func (g *graphqlProvider) EnableAccess(ctx context.Context, params *model.UpdateAccessRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "EnableAccess").Logger() + + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + if params.UserID == "" { + return nil, fmt.Errorf("user ID is missing") + } + + log = log.With().Str("user_id", params.UserID).Logger() + + user, err := g.StorageProvider.GetUserByID(ctx, params.UserID) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by ID") + return nil, err + } + + user.RevokedTimestamp = nil + + user, err = g.StorageProvider.UpdateUser(ctx, user) + if err != nil { + log.Debug().Err(err).Msg("Failed to update user") + return nil, err + } + go g.EventsProvider.RegisterEvent(ctx, constants.UserAccessEnabledWebhookEvent, "", user) + + return &model.Response{ + Message: `user access enabled successfully`, + }, nil +} diff --git a/internal/graphql/forgot_password.go b/internal/graphql/forgot_password.go new file mode 100644 index 000000000..5e1d0ef4b --- /dev/null +++ b/internal/graphql/forgot_password.go @@ -0,0 +1,151 @@ +package graphql + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// ForgotPassword is a for forgot password mutation +// It sends an email or sms with a verification token +// Permissions: none +func (g *graphqlProvider) ForgotPassword(ctx context.Context, params *model.ForgotPasswordRequest) (*model.ForgotPasswordResponse, error) { + log := g.Log.With().Str("func", "ForgotPassword").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + isBasicAuthEnabled := g.Config.EnableBasicAuthentication + isEmailVerificationEnabled := g.Config.EnableEmailVerification + isMobileBasicAuthEnabled := g.Config.EnableMobileBasicAuthentication + isMobileVerificationEnabled := g.Config.EnablePhoneVerification + email := refs.StringValue(params.Email) + phoneNumber := refs.StringValue(params.PhoneNumber) + if email == "" && phoneNumber == "" { + log.Debug().Msg("Email or phone number is required") + return nil, fmt.Errorf(`email or phone number is required`) + } + log = log.With().Str("email", email).Str("phoneNumber", phoneNumber).Logger() + isEmailLogin := email != "" + isMobileLogin := phoneNumber != "" + if !isBasicAuthEnabled && isEmailLogin && isEmailVerificationEnabled { + log.Debug().Msgf("Basic authentication is disabled.") + return nil, fmt.Errorf(`basic authentication is disabled for this instance`) + } + if !isMobileBasicAuthEnabled && isMobileLogin && isMobileVerificationEnabled { + log.Debug().Msgf("Mobile basic authentication is disabled.") + return nil, fmt.Errorf(`mobile basic authentication is disabled for this instance`) + } + var user *schemas.User + if isEmailLogin { + user, err = g.StorageProvider.GetUserByEmail(ctx, email) + log.Debug().Err(err).Msg("Failed to get user by email") + } else { + user, err = g.StorageProvider.GetUserByPhoneNumber(ctx, phoneNumber) + log.Debug().Err(err).Msg("Failed to get user by phone number") + } + if err != nil { + return nil, fmt.Errorf(`bad user credentials`) + } + hostname := parsers.GetHost(gc) + _, nonceHash, err := utils.GenerateNonce() + if err != nil { + log.Debug().Err(err).Msg("Failed to generate nonce") + return nil, err + } + if user.RevokedTimestamp != nil { + log.Debug().Msg("User access has been revoked") + return nil, fmt.Errorf(`user access has been revoked`) + } + if isEmailLogin { + redirectURI := "" + // give higher preference to params redirect uri + if strings.TrimSpace(refs.StringValue(params.RedirectURI)) != "" { + redirectURI = refs.StringValue(params.RedirectURI) + } else { + redirectURI = g.Config.ResetPasswordURL + if redirectURI == "" { + log.Debug().Err(err).Msg("Failed to get reset password url") + redirectURI = hostname + "/app/reset-password" + } + } + + verificationToken, err := g.TokenProvider.CreateVerificationToken(&token.AuthTokenConfig{ + LoginMethod: constants.AuthRecipeMethodBasicAuth, + Nonce: nonceHash, + User: user, + HostName: hostname, + }, redirectURI, constants.VerificationTypeForgotPassword) + if err != nil { + log.Debug().Err(err).Msg("Failed to create verification token") + return nil, err + } + _, err = g.StorageProvider.AddVerificationRequest(ctx, &schemas.VerificationRequest{ + Token: verificationToken, + Identifier: constants.VerificationTypeForgotPassword, + ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), + Email: email, + Nonce: nonceHash, + RedirectURI: redirectURI, + }) + if err != nil { + log.Debug().Err(err).Msg("Failed to add verification request") + return nil, err + } + // execute it as go routine so that we can reduce the api latency + go g.EmailProvider.SendEmail([]string{email}, constants.VerificationTypeForgotPassword, map[string]interface{}{ + "user": user.ToMap(), + "organization": utils.GetOrganization(g.Config), + "verification_url": utils.GetForgotPasswordURL(verificationToken, redirectURI), + }) + return &model.ForgotPasswordResponse{ + Message: `Please check your inbox! We have sent a password reset link.`, + }, nil + } + if isMobileLogin { + expiresAt := time.Now().Add(1 * time.Minute).Unix() + otp := utils.GenerateOTP() + otpData, err := g.StorageProvider.UpsertOTP(ctx, &schemas.OTP{ + Email: refs.StringValue(user.Email), + PhoneNumber: refs.StringValue(user.PhoneNumber), + Otp: otp, + ExpiresAt: expiresAt, + }) + if err != nil { + log.Debug().Err(err).Msg("Failed to upsert otp") + return nil, err + } + mfaSession := uuid.NewString() + err = g.MemoryStoreProvider.SetMfaSession(user.ID, mfaSession, expiresAt) + if err != nil { + log.Debug().Err(err).Msg("Failed to set mfa session") + return nil, err + } + cookie.SetMfaSession(gc, mfaSession, g.Config.AppCookieSecure) + smsBody := strings.Builder{} + smsBody.WriteString("Your verification code is: ") + smsBody.WriteString(otpData.Otp) + if err := g.SMSProvider.SendSMS(phoneNumber, smsBody.String()); err != nil { + log.Debug().Err(err).Msg("Failed to send sms") + // continue + } + return &model.ForgotPasswordResponse{ + Message: "Please enter the OTP sent to your phone number and change your password.", + ShouldShowMobileOtpScreen: refs.NewBoolRef(true), + }, nil + } + return nil, fmt.Errorf(`email or phone number verification needs to be enabled`) +} diff --git a/internal/graphql/invite_members.go b/internal/graphql/invite_members.go new file mode 100644 index 000000000..e8368998c --- /dev/null +++ b/internal/graphql/invite_members.go @@ -0,0 +1,173 @@ +package graphql + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" +) + +// InviteMembers is the method to invite members to the organization. +// Permissions: authorizer:admin +func (g *graphqlProvider) InviteMembers(ctx context.Context, params *model.InviteMemberRequest) (*model.InviteMembersResponse, error) { + log := g.Log.With().Str("func", "InviteMembers").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + // this feature is only allowed if email server is configured + if !g.Config.IsEmailServiceEnabled { + log.Debug().Msg("Email sending is disabled") + return nil, errors.New("email sending is disabled") + } + + isBasicAuthEnabled := g.Config.EnableBasicAuthentication + isMagicLinkLoginEnabled := g.Config.EnableMagicLinkLogin + if !isBasicAuthEnabled && !isMagicLinkLoginEnabled { + log.Debug().Msg("Either basic authentication or magic link login is required") + return nil, errors.New("either basic authentication or magic link login is required") + } + + // filter valid emails + emails := []string{} + for _, email := range params.Emails { + if validators.IsValidEmail(email) { + emails = append(emails, email) + } + } + + if len(emails) == 0 { + log.Debug().Msg("No valid emails found") + return nil, errors.New("no valid emails found") + } + + // TODO: optimise to use like query instead of looping through emails and getting user individually + // for each emails check if emails exists in db + newEmails := []string{} + for _, email := range emails { + _, err := g.StorageProvider.GetUserByEmail(ctx, email) + if err != nil { + log.Debug().Msgf("User with %s email does not exist", email) + newEmails = append(newEmails, email) + } else { + log.Debug().Msgf("User with %s email already exists", email) + } + } + + if len(newEmails) == 0 { + log.Debug().Msg("All emails already exist") + return nil, errors.New("all emails already exist") + } + + // invite new emails + for _, email := range newEmails { + user := &schemas.User{ + Email: refs.NewStringRef(email), + Roles: strings.Join(g.Config.DefaultRoles, ","), + } + hostname := parsers.GetHost(gc) + verifyEmailURL := hostname + "/verify_email" + appURL := parsers.GetAppURL(gc) + + redirectURL := appURL + if params.RedirectURI != nil { + redirectURL = *params.RedirectURI + } + + _, nonceHash, err := utils.GenerateNonce() + if err != nil { + return nil, err + } + // email, constants.VerificationTypeInviteMember, hostname, nonceHash, redirectURL + + verificationToken, err := g.TokenProvider.CreateVerificationToken(&token.AuthTokenConfig{ + LoginMethod: constants.AuthRecipeMethodBasicAuth, + Nonce: nonceHash, + HostName: hostname, + User: user, + }, redirectURL, constants.VerificationTypeInviteMember) + if err != nil { + log.Debug().Err(err).Msg("Failed to create verification token") + // continue to next email + } + + verificationRequest := &schemas.VerificationRequest{ + Token: verificationToken, + ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), + Email: email, + Nonce: nonceHash, + RedirectURI: redirectURL, + } + + // use magic link login if that option is on + if isMagicLinkLoginEnabled { + user.SignupMethods = constants.AuthRecipeMethodMagicLinkLogin + verificationRequest.Identifier = constants.VerificationTypeMagicLinkLogin + } else { + // use basic authentication if that option is on + user.SignupMethods = constants.AuthRecipeMethodBasicAuth + verificationRequest.Identifier = constants.VerificationTypeInviteMember + + isMFAEnforced := g.Config.EnforceMFA + if isMFAEnforced { + user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) + } + verifyEmailURL = appURL + "/setup-password" + } + + user, err = g.StorageProvider.AddUser(ctx, user) + if err != nil { + log.Debug().Err(err).Msg("Failed to add user") + return nil, err + } + + _, err = g.StorageProvider.AddVerificationRequest(ctx, verificationRequest) + if err != nil { + log.Debug().Err(err).Msg("Failed to add verification request") + return nil, err + } + + // exec it as go routine so that we can reduce the api latency + go g.EmailProvider.SendEmail([]string{refs.StringValue(user.Email)}, constants.VerificationTypeInviteMember, map[string]interface{}{ + "user": user.ToMap(), + "organization": utils.GetOrganization(g.Config), + "verification_url": utils.GetInviteVerificationURL(verifyEmailURL, verificationToken, redirectURL), + }) + } + + InvitedUsers := []*model.User{} + + for _, email := range newEmails { + user, err := g.StorageProvider.GetUserByEmail(ctx, email) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by email") + return nil, err + } + InvitedUsers = append(InvitedUsers, &model.User{ + Email: user.Email, + ID: user.ID, + }) + } + + return &model.InviteMembersResponse{ + Message: fmt.Sprintf("%d user(s) invited successfully.", len(newEmails)), + Users: InvitedUsers, + }, nil +} diff --git a/internal/graphql/login.go b/internal/graphql/login.go new file mode 100644 index 000000000..b9fd20e77 --- /dev/null +++ b/internal/graphql/login.go @@ -0,0 +1,388 @@ +package graphql + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/google/uuid" + "golang.org/x/crypto/bcrypt" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" +) + +// Login is the method to login a user. +// User can login with email or phone number, but not both +// Permissions: none +func (g *graphqlProvider) Login(ctx context.Context, params *model.LoginRequest) (*model.AuthResponse, error) { + log := g.Log.With().Str("func", "Login").Logger() + + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + isBasicAuthEnabled := g.Config.EnableBasicAuthentication + isMobileBasicAuthEnabled := g.Config.EnableMobileBasicAuthentication + email := refs.StringValue(params.Email) + phoneNumber := refs.StringValue(params.PhoneNumber) + if email == "" && phoneNumber == "" { + log.Debug().Msg("Email or phone number is required") + return nil, fmt.Errorf(`email or phone number is required`) + } + log = log.With().Str("email", email).Str("phone_number", phoneNumber).Logger() + isEmailLogin := email != "" + isMobileLogin := phoneNumber != "" + if !isBasicAuthEnabled && isEmailLogin { + log.Debug().Msg("Basic authentication is disabled") + return nil, fmt.Errorf(`basic authentication is disabled for this instance`) + } + if !isMobileBasicAuthEnabled && isMobileLogin { + log.Debug().Msg("Mobile basic authentication is disabled") + return nil, fmt.Errorf(`mobile basic authentication is disabled for this instance`) + } + var user *schemas.User + if isEmailLogin { + user, err = g.StorageProvider.GetUserByEmail(ctx, email) + log.Debug().Str("email", email).Msg("User found by email") + } else { + user, err = g.StorageProvider.GetUserByPhoneNumber(ctx, phoneNumber) + log.Debug().Str("phone_number", phoneNumber).Msg("User found by phone number") + } + if err != nil { + return nil, fmt.Errorf(`user not found`) + } + if user.RevokedTimestamp != nil { + log.Debug().Msg("User access has been revoked") + return nil, fmt.Errorf(`user access has been revoked`) + } + isEmailServiceEnabled := g.Config.IsEmailServiceEnabled + isSMSServiceEnabled := g.Config.IsSMSServiceEnabled + // If multi factor authentication is enabled and we need to generate OTP for mail / sms based MFA + generateOTP := func(expiresAt int64) (*schemas.OTP, error) { + otp := utils.GenerateOTP() + otpData, err := g.StorageProvider.UpsertOTP(ctx, &schemas.OTP{ + Email: refs.StringValue(user.Email), + PhoneNumber: refs.StringValue(user.PhoneNumber), + Otp: otp, + ExpiresAt: expiresAt, + }) + if err != nil { + log.Debug().Msg("Failed to upsert otp") + return nil, err + } + return otpData, nil + } + setOTPMFaSession := func(expiresAt int64) error { + mfaSession := uuid.NewString() + err = g.MemoryStoreProvider.SetMfaSession(user.ID, mfaSession, expiresAt) + if err != nil { + log.Debug().Msg("Failed to set mfa session") + return err + } + cookie.SetMfaSession(gc, mfaSession, g.Config.AppCookieSecure) + return nil + } + if isEmailLogin { + if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodBasicAuth) { + log.Debug().Msg("User signup method is not email basic auth") + return nil, fmt.Errorf(`user has not signed up email & password`) + } + + if user.EmailVerifiedAt == nil { + // Check if email service is enabled + // Send email verification via otp + if !isEmailServiceEnabled { + log.Debug().Msg("Email service is not enabled") + return nil, fmt.Errorf(`email not verified`) + } else { + if vreq, err := g.StorageProvider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup); err == nil && vreq != nil { + // if verification request exists and not expired then return + // if verification request exists and expired then delete it and proceed + if vreq.ExpiresAt > time.Now().Unix() { + if err := g.StorageProvider.DeleteVerificationRequest(ctx, vreq); err != nil { + log.Debug().Msg("Failed to delete verification request") + // continue with the flow + } + } else { + log.Debug().Msg("Email verification pending") + return nil, fmt.Errorf(`email verification pending`) + } + } + expiresAt := time.Now().Add(1 * time.Minute).Unix() + otpData, err := generateOTP(expiresAt) + if err != nil { + log.Debug().Msg("Failed to generate otp") + return nil, err + } + if err := setOTPMFaSession(expiresAt); err != nil { + log.Debug().Msg("Failed to set mfa session") + return nil, err + } + go func() { + // exec it as go routine so that we can reduce the api latency + if err := g.EmailProvider.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{ + "user": user.ToMap(), + "organization": utils.GetOrganization(g.Config), + "otp": otpData.Otp, + }); err != nil { + log.Debug().Msg("Failed to send otp email") + } + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) + }() + return &model.AuthResponse{ + Message: "Please check email inbox for the OTP", + ShouldShowEmailOtpScreen: refs.NewBoolRef(isEmailLogin), + }, nil + } + } + } else { + if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth) { + log.Debug().Msg("User signup method is not phone number basic auth") + return nil, fmt.Errorf(`user has not signed up with phone number & password`) + } + + if user.PhoneNumberVerifiedAt == nil { + if !isSMSServiceEnabled { + log.Debug().Msg("SMS service is not enabled") + return nil, fmt.Errorf(`phone number is not verified and sms service is not enabled`) + } else { + expiresAt := time.Now().Add(1 * time.Minute).Unix() + otpData, err := generateOTP(expiresAt) + if err != nil { + log.Debug().Msg("Failed to generate otp") + return nil, err + } + if err := setOTPMFaSession(expiresAt); err != nil { + log.Debug().Msg("Failed to set mfa session") + return nil, err + } + go func() { + smsBody := strings.Builder{} + smsBody.WriteString("Your verification code is: ") + smsBody.WriteString(otpData.Otp) + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + if err := g.SMSProvider.SendSMS(phoneNumber, smsBody.String()); err != nil { + log.Debug().Msg("Failed to send sms") + } + }() + return &model.AuthResponse{ + Message: "Please check text message for the OTP", + ShouldShowMobileOtpScreen: refs.NewBoolRef(isMobileLogin), + }, nil + } + } + } + err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(params.Password)) + if err != nil { + log.Debug().Msg("Bad user credentials") + return nil, fmt.Errorf(`bad user credentials`) + } + roles := g.Config.DefaultRoles + currentRoles := strings.Split(user.Roles, ",") + if len(params.Roles) > 0 { + if !validators.IsValidRoles(params.Roles, currentRoles) { + log.Debug().Msg("Invalid roles") + return nil, fmt.Errorf(`invalid roles`) + } + roles = params.Roles + } + scope := []string{"openid", "email", "profile"} + if params.Scope != nil && len(scope) > 0 { + scope = params.Scope + } + + isMFAEnabled := g.Config.EnableMFA + isTOTPLoginEnabled := g.Config.EnableTOTPLogin + isMailOTPEnabled := g.Config.EnableEmailOTP + isSMSOTPEnabled := g.Config.EnableSMSOTP + + // If multi factor authentication is enabled and is email based login and email otp is enabled + if refs.BoolValue(user.IsMultiFactorAuthEnabled) && isMFAEnabled && isMailOTPEnabled && isEmailServiceEnabled && isEmailLogin { + expiresAt := time.Now().Add(1 * time.Minute).Unix() + otpData, err := generateOTP(expiresAt) + if err != nil { + log.Debug().Msg("Failed to generate otp") + return nil, err + } + if err := setOTPMFaSession(expiresAt); err != nil { + log.Debug().Msg("Failed to set mfa session") + return nil, err + } + go func() { + // exec it as go routine so that we can reduce the api latency + if err := g.EmailProvider.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{ + "user": user.ToMap(), + "organization": utils.GetOrganization(g.Config), + "otp": otpData.Otp, + }); err != nil { + log.Debug().Msg("Failed to send otp email") + } + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) + }() + return &model.AuthResponse{ + Message: "Please check email inbox for the OTP", + ShouldShowEmailOtpScreen: refs.NewBoolRef(isMobileLogin), + }, nil + } + // If multi factor authentication is enabled and is sms based login and sms otp is enabled + if refs.BoolValue(user.IsMultiFactorAuthEnabled) && isMFAEnabled && isSMSOTPEnabled && isSMSServiceEnabled && isMobileLogin { + expiresAt := time.Now().Add(1 * time.Minute).Unix() + otpData, err := generateOTP(expiresAt) + if err != nil { + log.Debug().Msg("Failed to generate otp") + return nil, err + } + if err := setOTPMFaSession(expiresAt); err != nil { + log.Debug().Msg("Failed to set mfa session") + return nil, err + } + go func() { + smsBody := strings.Builder{} + smsBody.WriteString("Your verification code is: ") + smsBody.WriteString(otpData.Otp) + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + if err := g.SMSProvider.SendSMS(phoneNumber, smsBody.String()); err != nil { + log.Debug().Msg("Failed to send sms") + } + }() + return &model.AuthResponse{ + Message: "Please check text message for the OTP", + ShouldShowMobileOtpScreen: refs.NewBoolRef(isMobileLogin), + }, nil + } + // If mfa enabled and also totp enabled + if refs.BoolValue(user.IsMultiFactorAuthEnabled) && isMFAEnabled && isTOTPLoginEnabled { + expiresAt := time.Now().Add(3 * time.Minute).Unix() + if err := setOTPMFaSession(expiresAt); err != nil { + log.Debug().Msg("Failed to set mfa session") + return nil, err + } + authenticator, err := g.StorageProvider.GetAuthenticatorDetailsByUserId(ctx, user.ID, constants.EnvKeyTOTPAuthenticator) + if err != nil || authenticator == nil || authenticator.VerifiedAt == nil { + // generate totp + // Generate a base64 URL and initiate the registration for TOTP + authConfig, err := g.AuthenticatorProvider.Generate(ctx, user.ID) + if err != nil { + log.Debug().Msg("Failed to generate totp") + return nil, err + } + recoveryCodes := []*string{} + for _, code := range authConfig.RecoveryCodes { + recoveryCodes = append(recoveryCodes, refs.NewStringRef(code)) + } + // when user is first time registering for totp + res := &model.AuthResponse{ + Message: `Proceed to totp verification screen`, + ShouldShowTotpScreen: refs.NewBoolRef(true), + AuthenticatorScannerImage: refs.NewStringRef(authConfig.ScannerImage), + AuthenticatorSecret: refs.NewStringRef(authConfig.Secret), + AuthenticatorRecoveryCodes: recoveryCodes, + } + return res, nil + } else { + //when user is already register for totp + res := &model.AuthResponse{ + Message: `Proceed to totp screen`, + ShouldShowTotpScreen: refs.NewBoolRef(true), + } + return res, nil + } + } + + code := "" + codeChallenge := "" + nonce := "" + if params.State != nil { + // Get state from store + authorizeState, _ := g.MemoryStoreProvider.GetState(refs.StringValue(params.State)) + if authorizeState != "" { + authorizeStateSplit := strings.Split(authorizeState, "@@") + if len(authorizeStateSplit) > 1 { + code = authorizeStateSplit[0] + codeChallenge = authorizeStateSplit[1] + } else { + nonce = authorizeState + } + go g.MemoryStoreProvider.RemoveState(refs.StringValue(params.State)) + } + } + + if nonce == "" { + nonce = uuid.New().String() + } + hostname := parsers.GetHost(gc) + // gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth, nonce, code + authToken, err := g.TokenProvider.CreateAuthToken(gc, &token.AuthTokenConfig{ + User: user, + Roles: roles, + Scope: scope, + Nonce: nonce, + Code: code, + LoginMethod: constants.AuthRecipeMethodBasicAuth, + HostName: hostname, + }) + if err != nil { + log.Debug().Msg("Failed to create auth token") + return nil, err + } + + // TODO add to other login options as well + // Code challenge could be optional if PKCE flow is not used + if code != "" { + if err := g.MemoryStoreProvider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { + log.Debug().Msg("Failed to set state") + return nil, err + } + } + + expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() + if expiresIn <= 0 { + expiresIn = 1 + } + + res := &model.AuthResponse{ + Message: `Logged in successfully`, + AccessToken: &authToken.AccessToken.Token, + IDToken: &authToken.IDToken.Token, + ExpiresIn: &expiresIn, + User: user.AsAPIUser(), + } + + cookie.SetSession(gc, authToken.FingerPrintHash, g.Config.AppCookieSecure) + sessionStoreKey := constants.AuthRecipeMethodBasicAuth + ":" + user.ID + g.MemoryStoreProvider.SetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) + g.MemoryStoreProvider.SetUserSession(sessionStoreKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) + + if authToken.RefreshToken != nil { + res.RefreshToken = &authToken.RefreshToken.Token + g.MemoryStoreProvider.SetUserSession(sessionStoreKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) + } + + go func() { + // Register event + if isEmailLogin { + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) + } else { + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + } + // Record session + g.StorageProvider.AddSession(ctx, &schemas.Session{ + UserID: user.ID, + UserAgent: utils.GetUserAgent(gc.Request), + IP: utils.GetIP(gc.Request), + }) + }() + + return res, nil +} diff --git a/internal/graphql/logout.go b/internal/graphql/logout.go new file mode 100644 index 000000000..31408550a --- /dev/null +++ b/internal/graphql/logout.go @@ -0,0 +1,43 @@ +package graphql + +import ( + "context" + + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// Logout is the method to logout a user. +// Permissions: authenticated:* +func (g *graphqlProvider) Logout(ctx context.Context) (*model.Response, error) { + log := g.Log.With().Str("func", "Logout").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + tokenData, err := g.TokenProvider.GetUserIDFromSessionOrAccessToken(gc) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user id from session or access token") + return nil, err + } + + sessionKey := tokenData.UserID + if tokenData.LoginMethod != "" { + sessionKey = tokenData.LoginMethod + ":" + tokenData.UserID + } + + if err = g.MemoryStoreProvider.DeleteUserSession(sessionKey, tokenData.Nonce); err != nil { + log.Debug().Err(err).Msg("Failed to delete user session") + return nil, err + } + cookie.DeleteSession(gc, g.Config.AppCookieSecure) + + res := &model.Response{ + Message: "Logged out successfully", + } + + return res, nil +} diff --git a/internal/graphql/magic_link_login.go b/internal/graphql/magic_link_login.go new file mode 100644 index 000000000..71b3989ce --- /dev/null +++ b/internal/graphql/magic_link_login.go @@ -0,0 +1,196 @@ +package graphql + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" +) + +// MagicLinkLogin is the method to login a user using magic link. +// Permissions: none +func (g *graphqlProvider) MagicLinkLogin(ctx context.Context, params *model.MagicLinkLoginRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "MagicLinkLogin").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + isMagicLinkLoginEnabled := g.Config.EnableMagicLinkLogin + if !isMagicLinkLoginEnabled { + log.Debug().Msg("Magic link login is disabled") + return nil, fmt.Errorf(`magic link login is disabled for this instance`) + } + + params.Email = strings.ToLower(params.Email) + log = log.With().Str("email", params.Email).Logger() + + if !validators.IsValidEmail(params.Email) { + log.Debug().Msg("Invalid email address") + return nil, fmt.Errorf(`invalid email address`) + } + + inputRoles := []string{} + user := &schemas.User{ + Email: refs.NewStringRef(params.Email), + } + + // find user with email + existingUser, err := g.StorageProvider.GetUserByEmail(ctx, params.Email) + if err != nil { + isSignupEnabled := g.Config.EnableSignup + if !isSignupEnabled { + log.Debug().Msg("Signup is disabled") + return nil, fmt.Errorf(`signup is disabled for this instance`) + } + + user.SignupMethods = constants.AuthRecipeMethodMagicLinkLogin + // define roles for new user + if len(params.Roles) > 0 { + // check if roles exists + roles := g.Config.Roles + if !validators.IsValidRoles(params.Roles, roles) { + log.Debug().Msg("Invalid roles") + return nil, fmt.Errorf(`invalid roles`) + } else { + inputRoles = params.Roles + } + } else { + inputRoles = g.Config.DefaultRoles + } + + user.Roles = strings.Join(inputRoles, ",") + user, _ = g.StorageProvider.AddUser(ctx, user) + go g.EventsProvider.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodMagicLinkLogin, user) + } else { + user = existingUser + // There multiple scenarios with roles here in magic link login + // 1. user has access to protected roles + roles and trying to login + // 2. user has not signed up for one of the available role but trying to signup. + // Need to modify roles in this case + + if user.RevokedTimestamp != nil { + log.Debug().Msg("User access has been revoked") + return nil, fmt.Errorf(`user access has been revoked`) + } + + // find the unassigned roles + if len(params.Roles) <= 0 { + inputRolesString := g.Config.DefaultRoles + inputRoles = inputRolesString + } + existingRoles := strings.Split(existingUser.Roles, ",") + unasignedRoles := []string{} + for _, ir := range inputRoles { + if !utils.StringSliceContains(existingRoles, ir) { + unasignedRoles = append(unasignedRoles, ir) + } + } + + if len(unasignedRoles) > 0 { + // check if it contains protected unassigned role + hasProtectedRole := false + protectedRoles := g.Config.ProtectedRoles + for _, ur := range unasignedRoles { + if utils.StringSliceContains(protectedRoles, ur) { + hasProtectedRole = true + } + } + + if hasProtectedRole { + log.Debug().Msg("Protected roles cannot be assigned") + return nil, fmt.Errorf(`invalid roles`) + } else { + user.Roles = existingUser.Roles + "," + strings.Join(unasignedRoles, ",") + } + } else { + user.Roles = existingUser.Roles + } + + signupMethod := existingUser.SignupMethods + if !strings.Contains(signupMethod, constants.AuthRecipeMethodMagicLinkLogin) { + signupMethod = signupMethod + "," + constants.AuthRecipeMethodMagicLinkLogin + } + + user.SignupMethods = signupMethod + user, err = g.StorageProvider.UpdateUser(ctx, user) + if err != nil { + log.Debug().Msg("Failed to update user") + return nil, fmt.Errorf(`failed to update user`) + } + } + + hostname := parsers.GetHost(gc) + isEmailVerificationEnabled := g.Config.EnableEmailVerification + if isEmailVerificationEnabled { + // insert verification request + _, nonceHash, err := utils.GenerateNonce() + if err != nil { + log.Debug().Msg("Failed to generate nonce") + return nil, err + } + redirectURLParams := "&roles=" + strings.Join(inputRoles, ",") + if params.State != nil { + redirectURLParams = redirectURLParams + "&state=" + refs.StringValue(params.State) + } + if len(params.Scope) > 0 { + redirectURLParams = redirectURLParams + "&scope=" + strings.Join(params.Scope, " ") + } + redirectURL := parsers.GetAppURL(gc) + if params.RedirectURI != nil { + redirectURL = *params.RedirectURI + } + + if strings.Contains(redirectURL, "?") { + redirectURL = redirectURL + "&" + redirectURLParams + } else { + redirectURL = redirectURL + "?" + strings.TrimPrefix(redirectURLParams, "&") + } + + verificationType := constants.VerificationTypeMagicLinkLogin + // params.Email, verificationType, hostname, nonceHash, redirectURL + verificationToken, err := g.TokenProvider.CreateVerificationToken(&token.AuthTokenConfig{ + User: user, + HostName: hostname, + Nonce: nonceHash, + LoginMethod: constants.AuthRecipeMethodMagicLinkLogin, + }, redirectURL, verificationType) + if err != nil { + log.Debug().Msg("Failed to create verification token") + return nil, err + } + _, err = g.StorageProvider.AddVerificationRequest(ctx, &schemas.VerificationRequest{ + Token: verificationToken, + Identifier: verificationType, + ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), + Email: params.Email, + Nonce: nonceHash, + RedirectURI: redirectURL, + }) + if err != nil { + log.Debug().Msg("Failed to add verification request") + return nil, err + } + + // exec it as go routine so that we can reduce the api latency + go g.EmailProvider.SendEmail([]string{params.Email}, constants.VerificationTypeMagicLinkLogin, map[string]interface{}{ + "user": user.ToMap(), + "organization": utils.GetOrganization(g.Config), + "verification_url": utils.GetEmailVerificationURL(verificationToken, hostname, redirectURL), + }) + } + + return &model.Response{ + Message: `Magic Link has been sent to your email. Please check your inbox!`, + }, nil +} diff --git a/internal/graphql/meta.go b/internal/graphql/meta.go new file mode 100644 index 000000000..17d60eda8 --- /dev/null +++ b/internal/graphql/meta.go @@ -0,0 +1,75 @@ +package graphql + +import ( + "context" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// Meta returns the meta information about the server. +// Permissions: none +func (g *graphqlProvider) Meta(ctx context.Context) (*model.Meta, error) { + clientID := g.Config.ClientID + + googleClientID := g.Config.GoogleClientID + googleClientSecret := g.Config.GoogleClientSecret + + facebookClientID := g.Config.FacebookClientID + facebookClientSecret := g.Config.FacebookClientSecret + + linkedClientID := g.Config.LinkedinClientID + linkedInClientSecret := g.Config.LinkedinClientSecret + + appleClientID := g.Config.AppleClientID + appleClientSecret := g.Config.AppleClientSecret + + githubClientID := g.Config.GithubClientID + githubClientSecret := g.Config.GithubClientSecret + + twitterClientID := g.Config.TwitterClientID + twitterClientSecret := g.Config.TwitterClientSecret + + microsoftClientID := g.Config.MicrosoftClientID + microsoftClientSecret := g.Config.MicrosoftClientSecret + + twitchClientID := g.Config.TwitchClientID + twitchClientSecret := g.Config.TwitchClientSecret + + robloxClientID := g.Config.RobloxClientID + robloxClientSecret := g.Config.RobloxClientSecret + + g.Log.Info().Interface("config", g.Config).Msg("Config") + + isBasicAuthEnabled := g.Config.EnableBasicAuthentication + isMobileBasicAuthEnabled := g.Config.EnableMobileBasicAuthentication + isMobileVerificationEnabled := g.Config.EnablePhoneVerification + isMagicLinkLoginEnabled := g.Config.EnableMagicLinkLogin + isEmailVerificationEnabled := g.Config.EnableEmailVerification + isMultiFactorAuthenticationEnabled := g.Config.EnableMFA + isStrongPasswordEnabled := g.Config.EnableStrongPassword + isSignUpEnabled := g.Config.EnableSignup + + metaInfo := model.Meta{ + Version: constants.VERSION, + ClientID: clientID, + IsGoogleLoginEnabled: googleClientID != "" && googleClientSecret != "", + IsGithubLoginEnabled: githubClientID != "" && githubClientSecret != "", + IsFacebookLoginEnabled: facebookClientID != "" && facebookClientSecret != "", + IsLinkedinLoginEnabled: linkedClientID != "" && linkedInClientSecret != "", + IsAppleLoginEnabled: appleClientID != "" && appleClientSecret != "", + IsTwitterLoginEnabled: twitterClientID != "" && twitterClientSecret != "", + IsMicrosoftLoginEnabled: microsoftClientID != "" && microsoftClientSecret != "", + IsBasicAuthenticationEnabled: isBasicAuthEnabled, + IsEmailVerificationEnabled: isEmailVerificationEnabled, + IsMagicLinkLoginEnabled: isMagicLinkLoginEnabled, + IsSignUpEnabled: isSignUpEnabled, + IsStrongPasswordEnabled: isStrongPasswordEnabled, + IsMultiFactorAuthEnabled: isMultiFactorAuthenticationEnabled, + IsMobileBasicAuthenticationEnabled: isMobileBasicAuthEnabled, + IsPhoneVerificationEnabled: isMobileVerificationEnabled, + IsTwitchLoginEnabled: twitchClientID != "" && twitchClientSecret != "", + IsRobloxLoginEnabled: robloxClientID != "" && robloxClientSecret != "", + } + return &metaInfo, nil +} diff --git a/internal/graphql/profile.go b/internal/graphql/profile.go new file mode 100644 index 000000000..ebcb4926f --- /dev/null +++ b/internal/graphql/profile.go @@ -0,0 +1,32 @@ +package graphql + +import ( + "context" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// Profile is the method to get the profile of a user. +func (g *graphqlProvider) Profile(ctx context.Context) (*model.User, error) { + log := g.Log.With().Str("func", "Profile").Logger() + + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + tokenData, err := g.TokenProvider.GetUserIDFromSessionOrAccessToken(gc) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user id from session or access token") + return nil, err + } + log = log.With().Str("user_id", tokenData.UserID).Logger() + user, err := g.StorageProvider.GetUserByID(ctx, tokenData.UserID) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by id") + return nil, err + } + + return user.AsAPIUser(), nil +} diff --git a/internal/graphql/provider.go b/internal/graphql/provider.go new file mode 100644 index 000000000..c537437e9 --- /dev/null +++ b/internal/graphql/provider.go @@ -0,0 +1,181 @@ +package graphql + +import ( + "context" + + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/authenticators" + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/email" + "github.com/authorizerdev/authorizer/internal/events" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/memory_store" + "github.com/authorizerdev/authorizer/internal/sms" + "github.com/authorizerdev/authorizer/internal/storage" + "github.com/authorizerdev/authorizer/internal/token" +) + +// Dependencies for a graphql provider +type Dependencies struct { + Log *zerolog.Logger + + // Providers for various services + // AuthenticatorProvider is used to register authenticators like totp (Google Authenticator) + AuthenticatorProvider authenticators.Provider + // EmailProvider is used to send emails + EmailProvider email.Provider + // EventsProvider is used to register events + EventsProvider events.Provider + // MemoryStoreProvider is used to store data in memory + MemoryStoreProvider memory_store.Provider + // SMSProvider is used to send SMS + SMSProvider sms.Provider + // StorageProvider is used to register storage like database + StorageProvider storage.Provider + // TokenProvider is used to generate tokens + TokenProvider token.Provider +} + +// New constructs a new graphql provider with given arguments +func New(cfg *config.Config, deps *Dependencies) (Provider, error) { + // TODO - Add any validation here for config and dependencies + g := &graphqlProvider{ + Config: cfg, + Dependencies: *deps, + } + return g, nil +} + +// graphqlProvider is the struct that provides resolver functions. +type graphqlProvider struct { + *config.Config + Dependencies +} + +// Ensure that graphqlProvider implements the Provider interface +var _ Provider = &graphqlProvider{} + +// Provider is the interface that provides the methods to interact with the graphql mutations and queries. +type Provider interface { + // AddEmailTemplate is the method to add email template. + // Permissions: authorizer:admin + AddEmailTemplate(ctx context.Context, params *model.AddEmailTemplateRequest) (*model.Response, error) + // AddWebhook is the method to add webhook. + // Permissions: authorizer:admin + AddWebhook(ctx context.Context, params *model.AddWebhookRequest) (*model.Response, error) + // AdminLogin is the method to login as admin. + // Permissions: none + AdminLogin(ctx context.Context, params *model.AdminLoginRequest) (*model.Response, error) + // AdminLogout is the method to logout as admin. + // Permissions: authorizer:admin + AdminLogout(ctx context.Context) (*model.Response, error) + // AdminSession is the method to get admin session. + // Permissions: authorizer:admin + AdminSession(ctx context.Context) (*model.Response, error) + // DeactivateAccount is the method to deactivate account. + // Permissions: authorized user + DeactivateAccount(ctx context.Context) (*model.Response, error) + // DeleteEmailTemplate is the method to delete email template. + // Permissions: authorizer:admin + DeleteEmailTemplate(ctx context.Context, params *model.DeleteEmailTemplateRequest) (*model.Response, error) + // DeleteUser is the method to delete user. + // Permissions: authorizer:admin + DeleteUser(ctx context.Context, params *model.DeleteUserRequest) (*model.Response, error) + // DeleteWebhook is the method to delete webhook. + // Permissions: authorizer:admin + DeleteWebhook(ctx context.Context, params *model.WebhookRequest) (*model.Response, error) + // EmailTemplates is the method to list email templates. + // Permissions: authorizer:admin + EmailTemplates(ctx context.Context, in *model.PaginatedRequest) (*model.EmailTemplates, error) + // EnableAccess is the method to enable access. + // Permissions: authorizer:admin + EnableAccess(ctx context.Context, params *model.UpdateAccessRequest) (*model.Response, error) + // ForgotPassword is the method to forgot password. + // Permissions: none + ForgotPassword(ctx context.Context, params *model.ForgotPasswordRequest) (*model.ForgotPasswordResponse, error) + // InviteMembers is the method to invite members. + // Permissions: authorizer:admin + InviteMembers(ctx context.Context, params *model.InviteMemberRequest) (*model.InviteMembersResponse, error) + // Login is the method to login. + // Permissions: none + Login(ctx context.Context, params *model.LoginRequest) (*model.AuthResponse, error) + // Logout is the method to logout. + // Permissions: authorized user + Logout(ctx context.Context) (*model.Response, error) + // MagicLinkLogin is the method to login using magic link. + // Permissions: none + MagicLinkLogin(ctx context.Context, params *model.MagicLinkLoginRequest) (*model.Response, error) + // Meta is the method to get meta. + // Permissions: none + Meta(ctx context.Context) (*model.Meta, error) + // Profile is the method to get profile. + // Permissions: authorized user + Profile(ctx context.Context) (*model.User, error) + // ResendOTP is the method to resend OTP. + // Permissions: none + ResendOTP(ctx context.Context, params *model.ResendOTPRequest) (*model.Response, error) + // ResendVerifyEmail is the method to resend verification email. + // Permissions: none + ResendVerifyEmail(ctx context.Context, params *model.ResendVerifyEmailRequest) (*model.Response, error) + // ResetPassword is the method to reset password. + // Permissions: none + ResetPassword(ctx context.Context, params *model.ResetPasswordRequest) (*model.Response, error) + // RevokeAccess is the method to revoke access. + // Permissions: authorizer:admin + RevokeAccess(ctx context.Context, params *model.UpdateAccessRequest) (*model.Response, error) + // Revoke is the method to revoke refresh token. + // Permissions: none + Revoke(ctx context.Context, params *model.OAuthRevokeRequest) (*model.Response, error) + // Session is the method to get session. + // Permissions: authorized user + Session(ctx context.Context, params *model.SessionQueryRequest) (*model.AuthResponse, error) + // SignUp is the method to SignUp. + // Permissions: none + SignUp(ctx context.Context, params *model.SignUpRequest) (*model.AuthResponse, error) + // TestEndpoint is the method to test endpoint. + // Permissions: authorizer:admin + TestEndpoint(ctx context.Context, params *model.TestEndpointRequest) (*model.TestEndpointResponse, error) + // UpdateEmailTemplate is the method to update email template. + // Permissions: authorizer:admin + UpdateEmailTemplate(ctx context.Context, params *model.UpdateEmailTemplateRequest) (*model.Response, error) + // UpdateProfile is the method to update profile. + // Permissions: authorized user + UpdateProfile(ctx context.Context, params *model.UpdateProfileRequest) (*model.Response, error) + // UpdateUser is the method to update user. + // Permissions: authorizer:admin + UpdateUser(ctx context.Context, params *model.UpdateUserRequest) (*model.User, error) + // UpdateWebhook is the method to update webhook. + // Permissions: authorizer:admin + UpdateWebhook(ctx context.Context, params *model.UpdateWebhookRequest) (*model.Response, error) + // User is the method to get user. + // Permissions: authorizer:admin + User(ctx context.Context, params *model.GetUserRequest) (*model.User, error) + // Users is the method to list users. + // Permissions: authorizer:admin + Users(ctx context.Context, in *model.PaginatedRequest) (*model.Users, error) + // ValidateJWTToken is the method to validate JWT token. + // Permissions: none + ValidateJWTToken(ctx context.Context, params *model.ValidateJWTTokenRequest) (*model.ValidateJWTTokenResponse, error) + // ValidateSession is the method to validate browser session. + // Permissions: authorized user + ValidateSession(ctx context.Context, params *model.ValidateSessionRequest) (*model.ValidateSessionResponse, error) + // VerificationRequests is the method to list verification requests. + // Permissions: authorizer:admin + VerificationRequests(ctx context.Context, in *model.PaginatedRequest) (*model.VerificationRequests, error) + // VerifyEmail is the method to verify email. + // Permissions: none + VerifyEmail(ctx context.Context, params *model.VerifyEmailRequest) (*model.AuthResponse, error) + // VerifyOTP is the method to verify OTP. + // Permissions: authorized otp request + VerifyOTP(ctx context.Context, params *model.VerifyOTPRequest) (*model.AuthResponse, error) + // WebhookLogs is the method to list webhook logs. + // Permissions: authorizer:admin + WebhookLogs(ctx context.Context, in *model.ListWebhookLogRequest) (*model.WebhookLogs, error) + // Webhook is the method to get webhook. + // Permissions: authorizer:admin + Webhook(ctx context.Context, params *model.WebhookRequest) (*model.Webhook, error) + // Webhooks is the method to list webhooks. + // Permissions: authorizer:admin + Webhooks(ctx context.Context, in *model.PaginatedRequest) (*model.Webhooks, error) +} diff --git a/internal/graphql/resend_otp.go b/internal/graphql/resend_otp.go new file mode 100644 index 000000000..4a7f962b4 --- /dev/null +++ b/internal/graphql/resend_otp.go @@ -0,0 +1,156 @@ +package graphql + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// ResendOTP is the method to resend OTP. +// Permissions: none +func (g *graphqlProvider) ResendOTP(ctx context.Context, params *model.ResendOTPRequest) (*model.Response, error) { + email := strings.ToLower(strings.Trim(refs.StringValue(params.Email), " ")) + phoneNumber := strings.Trim(refs.StringValue(params.PhoneNumber), " ") + log := g.Log.With().Str("func", "ResendOTP").Str("email", email).Str("phone_number", phoneNumber).Logger() + if email == "" && phoneNumber == "" { + log.Debug().Msg("Email or phone number is required") + return nil, errors.New("email or phone number is required") + } + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + var user *schemas.User + var isEmailServiceEnabled, isSMSServiceEnabled bool + if email != "" { + isEmailServiceEnabled = g.Config.IsEmailServiceEnabled + if !isEmailServiceEnabled { + log.Debug().Msg("Email service not enabled") + return nil, errors.New("email service not enabled") + } + user, err = g.StorageProvider.GetUserByEmail(ctx, email) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by email") + return nil, fmt.Errorf(`user with this email/phone not found`) + } + } else { + isSMSServiceEnabled = g.Config.IsSMSServiceEnabled + if !isSMSServiceEnabled { + log.Debug().Msg("SMS service not enabled") + return nil, errors.New("email service not enabled") + } + user, err = g.StorageProvider.GetUserByPhoneNumber(ctx, phoneNumber) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by phone number") + return nil, fmt.Errorf(`user with this email/phone not found`) + } + } + if user.RevokedTimestamp != nil { + log.Debug().Msg("User access has been revoked") + return nil, fmt.Errorf(`user access has been revoked`) + } + + if !refs.BoolValue(user.IsMultiFactorAuthEnabled) && user.EmailVerifiedAt != nil && user.PhoneNumberVerifiedAt != nil { + log.Debug().Msg("Multi factor authentication not enabled") + return nil, fmt.Errorf(`multi factor authentication not enabled`) + } + + isMFAEnabled := g.Config.EnableMFA + if !isMFAEnabled { + log.Debug().Msg("Multi factor authentication is disabled for this instance") + return nil, errors.New("multi factor authentication is disabled for this instance") + } + + // get otp by email or phone number + var otpData *schemas.OTP + if email != "" { + otpData, err = g.StorageProvider.GetOTPByEmail(ctx, refs.StringValue(params.Email)) + log.Debug().Msg("Failed to get otp for given email") + } else { + otpData, err = g.StorageProvider.GetOTPByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber)) + log.Debug().Msg("Failed to get otp for given phone number") + } + if err != nil { + return nil, err + } + if otpData == nil { + log.Debug().Msg("Failed to get otp for given email") + return &model.Response{ + Message: "Failed to get for given email", + }, errors.New("failed to get otp for given email") + } + // If multi factor authentication is enabled and we need to generate OTP for mail / sms based MFA + generateOTP := func(expiresAt int64) (*schemas.OTP, error) { + otp := utils.GenerateOTP() + otpData, err := g.StorageProvider.UpsertOTP(ctx, &schemas.OTP{ + Email: refs.StringValue(user.Email), + PhoneNumber: refs.StringValue(user.PhoneNumber), + Otp: otp, + ExpiresAt: expiresAt, + }) + if err != nil { + log.Debug().Msg("Failed to upsert otp") + return nil, err + } + return otpData, nil + } + setOTPMFaSession := func(expiresAt int64) error { + mfaSession := uuid.NewString() + err = g.MemoryStoreProvider.SetMfaSession(user.ID, mfaSession, expiresAt) + if err != nil { + log.Debug().Msg("Failed to set mfa session") + return err + } + cookie.SetMfaSession(gc, mfaSession, g.Config.AppCookieSecure) + return nil + } + expiresAt := time.Now().Add(1 * time.Minute).Unix() + otpData, err = generateOTP(expiresAt) + if err != nil { + log.Debug().Msg("Failed to generate otp") + return nil, err + } + if err := setOTPMFaSession(expiresAt); err != nil { + log.Debug().Err(err).Msg("Failed to set mfa session") + return nil, err + } + if email != "" { + go func() { + // exec it as go routine so that we can reduce the api latency + if err := g.EmailProvider.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{ + "user": user.ToMap(), + "organization": utils.GetOrganization(g.Config), + "otp": otpData.Otp, + }); err != nil { + log.Debug().Err(err).Msg("Failed to send email") + } + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) + }() + } else { + go func() { + smsBody := strings.Builder{} + smsBody.WriteString("Your verification code is: ") + smsBody.WriteString(otpData.Otp) + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + if err := g.SMSProvider.SendSMS(phoneNumber, smsBody.String()); err != nil { + log.Debug().Err(err).Msg("Failed to send sms") + } + }() + } + log.Info().Msg("OTP has been sent") + return &model.Response{ + Message: `OTP has been sent. Please check your inbox`, + }, nil +} diff --git a/internal/graphql/resend_verify_email.go b/internal/graphql/resend_verify_email.go new file mode 100644 index 000000000..1ea0a8ba9 --- /dev/null +++ b/internal/graphql/resend_verify_email.go @@ -0,0 +1,97 @@ +package graphql + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" +) + +// ResendVerifyEmail is the method to resend verification email. +// Permissions: none +func (g *graphqlProvider) ResendVerifyEmail(ctx context.Context, params *model.ResendVerifyEmailRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "ResendVerifyEmail").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + params.Email = strings.ToLower(params.Email) + + log = log.With().Str("email", params.Email).Str("identifier", params.Identifier).Logger() + if !validators.IsValidEmail(params.Email) { + log.Debug().Msg("Invalid email") + return nil, fmt.Errorf("invalid email") + } + + if !validators.IsValidVerificationIdentifier(params.Identifier) { + log.Debug().Msg("Invalid verification identifier") + return nil, fmt.Errorf("invalid identifier") + } + + user, err := g.StorageProvider.GetUserByEmail(ctx, params.Email) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by email") + return nil, fmt.Errorf("invalid user") + } + + verificationRequest, err := g.StorageProvider.GetVerificationRequestByEmail(ctx, params.Email, params.Identifier) + if err != nil { + log.Debug().Err(err).Msg("Failed to get verification request") + return nil, fmt.Errorf(`verification request not found`) + } + + // delete current verification and create new one + err = g.StorageProvider.DeleteVerificationRequest(ctx, verificationRequest) + if err != nil { + log.Debug().Err(err).Msg("Failed to delete verification request") + } + + hostname := parsers.GetHost(gc) + _, nonceHash, err := utils.GenerateNonce() + if err != nil { + log.Debug().Msg("Failed to generate nonce") + return nil, err + } + // params.Email, params.Identifier, hostname, nonceHash, verificationRequest.RedirectURI + verificationToken, err := g.TokenProvider.CreateVerificationToken(&token.AuthTokenConfig{ + User: user, + Nonce: nonceHash, + HostName: hostname, + LoginMethod: constants.AuthRecipeMethodBasicAuth, + }, verificationRequest.RedirectURI, params.Identifier) + if err != nil { + log.Debug().Err(err).Msg("Failed to create verification token") + } + _, err = g.StorageProvider.AddVerificationRequest(ctx, &schemas.VerificationRequest{ + Token: verificationToken, + Identifier: params.Identifier, + ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), + Email: params.Email, + Nonce: nonceHash, + RedirectURI: verificationRequest.RedirectURI, + }) + if err != nil { + log.Debug().Err(err).Msg("Failed to add verification request") + } + + // exec it as go routine so that we can reduce the api latency + go g.EmailProvider.SendEmail([]string{params.Email}, params.Identifier, map[string]interface{}{ + "user": user.ToMap(), + "organization": utils.GetOrganization(g.Config), + "verification_url": utils.GetEmailVerificationURL(verificationToken, hostname, verificationRequest.RedirectURI), + }) + + return &model.Response{ + Message: `Verification email has been sent. Please check your inbox`, + }, nil +} diff --git a/internal/graphql/reset_password.go b/internal/graphql/reset_password.go new file mode 100644 index 000000000..1047b5a2e --- /dev/null +++ b/internal/graphql/reset_password.go @@ -0,0 +1,173 @@ +package graphql + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" +) + +// ResetPassword is the method to reset password. +// Permissions: none +func (g *graphqlProvider) ResetPassword(ctx context.Context, params *model.ResetPasswordRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "ResetPassword").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + verifyingToken := refs.StringValue(params.Token) + otp := refs.StringValue(params.Otp) + if verifyingToken == "" && otp == "" { + log.Debug().Msg("Token or otp is required") + return nil, fmt.Errorf(`token or otp is required`) + } + isTokenVerification := verifyingToken != "" + isOtpVerification := otp != "" + if isOtpVerification && refs.StringValue(params.PhoneNumber) == "" { + log.Debug().Msg("Phone number is required") + return nil, fmt.Errorf(`phone number is required`) + } + isBasicAuthEnabled := g.Config.EnableBasicAuthentication + isMobileBasicAuthEnabled := g.Config.EnableMobileBasicAuthentication + if isTokenVerification && !isBasicAuthEnabled { + log.Debug().Msg("Basic authentication is disabled") + return nil, fmt.Errorf(`basic authentication is disabled for this instance`) + } + if isOtpVerification && !isMobileBasicAuthEnabled { + log.Debug().Msg("Mobile basic authentication is disabled") + return nil, fmt.Errorf(`mobile basic authentication is disabled for this instance`) + } + email := "" + phoneNumber := refs.StringValue(params.PhoneNumber) + var user *schemas.User + var verificationRequest *schemas.VerificationRequest + var otpRequest *schemas.OTP + if isTokenVerification { + verificationRequest, err = g.StorageProvider.GetVerificationRequestByToken(ctx, verifyingToken) + if err != nil { + log.Debug().Err(err).Msg("Failed to get verification request") + return nil, fmt.Errorf(`invalid token`) + } + // verify if token exists in db + hostname := parsers.GetHost(gc) + claim, err := g.TokenProvider.ParseJWTToken(verifyingToken) + if err != nil { + log.Debug().Err(err).Msg("Failed to parse token") + return nil, fmt.Errorf(`invalid token`) + } + + if ok, err := g.TokenProvider.ValidateJWTClaims(claim, &token.AuthTokenConfig{ + HostName: hostname, + Nonce: verificationRequest.Nonce, + User: &schemas.User{ + ID: "", + Email: refs.NewStringRef(verificationRequest.Email), + }, + }); !ok || err != nil { + log.Debug().Err(err).Msg("Failed to validate jwt claims") + return nil, fmt.Errorf(`invalid token`) + } + email = claim["sub"].(string) + user, err = g.StorageProvider.GetUserByEmail(ctx, email) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user") + return nil, err + } + } + if isOtpVerification { + mfaSession, err := cookie.GetMfaSession(gc) + if err != nil { + log.Debug().Err(err).Msg("Failed to get otp request by email") + return nil, fmt.Errorf(`invalid session: %s`, err.Error()) + } + // Get user by phone number + user, err = g.StorageProvider.GetUserByPhoneNumber(ctx, phoneNumber) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by phone number") + return nil, fmt.Errorf(`user not found`) + } + if _, err := g.MemoryStoreProvider.GetMfaSession(user.ID, mfaSession); err != nil { + log.Debug().Err(err).Msg("Failed to get mfa session") + return nil, fmt.Errorf(`invalid session: %s`, err.Error()) + } + otpRequest, err = g.StorageProvider.GetOTPByPhoneNumber(ctx, phoneNumber) + if err != nil { + log.Debug().Err(err).Msg("Failed to get otp request by phone number") + return nil, fmt.Errorf(`invalid otp`) + } + if otpRequest.Otp != otp { + log.Debug().Msg("Failed to verify otp request: Incorrect value") + return nil, fmt.Errorf(`invalid otp`) + } + } + if params.Password != params.ConfirmPassword { + log.Debug().Msg("Passwords do not match") + return nil, fmt.Errorf(`passwords don't match`) + } + if err := validators.IsValidPassword(params.Password, !g.Config.EnableStrongPassword); err != nil { + log.Debug().Msg("Invalid password") + return nil, err + } + log = log.With().Str("email", email).Str("phone_number", phoneNumber).Logger() + password, _ := crypto.EncryptPassword(params.Password) + user.Password = &password + signupMethod := user.SignupMethods + if !strings.Contains(signupMethod, constants.AuthRecipeMethodBasicAuth) && isTokenVerification { + signupMethod = signupMethod + "," + constants.AuthRecipeMethodBasicAuth + // helpful if user has not signed up with basic auth + if user.EmailVerifiedAt == nil { + now := time.Now().Unix() + user.EmailVerifiedAt = &now + } + } + if !strings.Contains(signupMethod, constants.AuthRecipeMethodMobileOTP) && isOtpVerification { + signupMethod = signupMethod + "," + constants.AuthRecipeMethodMobileOTP + // helpful if user has not signed up with basic auth + if user.PhoneNumberVerifiedAt == nil { + now := time.Now().Unix() + user.PhoneNumberVerifiedAt = &now + } + } + user.SignupMethods = signupMethod + isMFAEnforced := g.Config.EnforceMFA + if isMFAEnforced { + user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) + } + _, err = g.StorageProvider.UpdateUser(ctx, user) + if err != nil { + log.Debug().Err(err).Msg("Failed to update user") + return nil, err + } + if isTokenVerification { + // delete from verification table + err = g.StorageProvider.DeleteVerificationRequest(ctx, verificationRequest) + if err != nil { + log.Debug().Err(err).Msg("Failed to delete verification request") + return nil, err + } + } + if isOtpVerification { + // delete from otp table + err = g.StorageProvider.DeleteOTP(ctx, otpRequest) + if err != nil { + log.Debug().Err(err).Msg("Failed to delete otp request") + return nil, err + } + } + return &model.Response{ + Message: `Password updated successfully.`, + }, nil +} diff --git a/internal/graphql/revoke.go b/internal/graphql/revoke.go new file mode 100644 index 000000000..616cb2813 --- /dev/null +++ b/internal/graphql/revoke.go @@ -0,0 +1,57 @@ +package graphql + +import ( + "context" + "errors" + "strings" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// Revoke is the method to revoke refresh token +func (g *graphqlProvider) Revoke(ctx context.Context, params *model.OAuthRevokeRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "Revoke").Logger() + token := strings.TrimSpace(params.RefreshToken) + if token == "" { + log.Error().Msg("Refresh token is empty") + return nil, errors.New("missing refresh token") + } + claims, err := g.TokenProvider.ParseJWTToken(token) + if err != nil { + log.Debug().Err(err).Msg("failed to parse jwt") + return nil, err + } + + userID := claims["sub"].(string) + loginMethod := claims["login_method"] + sessionToken := userID + if loginMethod != nil && loginMethod != "" { + sessionToken = loginMethod.(string) + ":" + userID + } + + existingToken, err := g.MemoryStoreProvider.GetUserSession(sessionToken, constants.TokenTypeRefreshToken+"_"+claims["nonce"].(string)) + if err != nil { + log.Debug().Err(err).Msg("Failed to get refresh token") + return nil, err + } + + if existingToken == "" { + log.Debug().Msg("Token not found") + return nil, errors.New("token not found") + } + + if existingToken != token { + log.Debug().Msg("Token does not match") + return nil, errors.New("token does not match") + } + + // Remove the token from the memory store + if err := g.MemoryStoreProvider.DeleteUserSession(sessionToken, claims["nonce"].(string)); err != nil { + log.Debug().Err(err).Msg("failed to delete user session") + return nil, err + } + return &model.Response{ + Message: "Token revoked", + }, nil +} diff --git a/internal/graphql/revoke_access.go b/internal/graphql/revoke_access.go new file mode 100644 index 000000000..9dafc0ed8 --- /dev/null +++ b/internal/graphql/revoke_access.go @@ -0,0 +1,50 @@ +package graphql + +import ( + "context" + "fmt" + "time" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// RevokeAccess is the method to revoke access of a user. +// Permission: authorizer:admin +func (g *graphqlProvider) RevokeAccess(ctx context.Context, params *model.UpdateAccessRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "RevokeAccess").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + log = log.With().Str("user_id", params.UserID).Logger() + user, err := g.StorageProvider.GetUserByID(ctx, params.UserID) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by id") + return nil, err + } + + now := time.Now().Unix() + user.RevokedTimestamp = &now + + user, err = g.StorageProvider.UpdateUser(ctx, user) + if err != nil { + log.Debug().Err(err).Msg("Failed to update user") + return nil, err + } + + go func() { + g.MemoryStoreProvider.DeleteAllUserSessions(user.ID) + g.EventsProvider.RegisterEvent(ctx, constants.UserAccessRevokedWebhookEvent, "", user) + }() + + return &model.Response{ + Message: `user access revoked successfully`, + }, nil +} diff --git a/internal/graphql/session.go b/internal/graphql/session.go new file mode 100644 index 000000000..61ee6baab --- /dev/null +++ b/internal/graphql/session.go @@ -0,0 +1,114 @@ +package graphql + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// Session is the method to get session. +// It also refreshes the session token. +// TODO allow validating with code and code verifier instead of cookie (PKCE flow) +func (g *graphqlProvider) Session(ctx context.Context, params *model.SessionQueryRequest) (*model.AuthResponse, error) { + log := g.Log.With().Str("func", "Session").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + sessionToken, err := cookie.GetSession(gc) + if err != nil { + log.Debug().Err(err).Msg("Failed to get session token") + return nil, errors.New("unauthorized") + } + + // get session from cookie + claims, err := g.TokenProvider.ValidateBrowserSession(gc, sessionToken) + if err != nil { + log.Debug().Err(err).Msg("Failed to validate session token") + return nil, errors.New("unauthorized") + } + userID := claims.Subject + log = log.With().Str("user_id", userID).Logger() + user, err := g.StorageProvider.GetUserByID(ctx, userID) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user") + return nil, err + } + + // refresh token has "roles" as claim + claimRoleInterface := claims.Roles + claimRoles := []string{} + claimRoles = append(claimRoles, claimRoleInterface...) + + if params != nil && params.Roles != nil && len(params.Roles) > 0 { + for _, v := range params.Roles { + if !utils.StringSliceContains(claimRoles, v) { + log.Debug().Msg("User does not have required role") + return nil, fmt.Errorf(`unauthorized`) + } + } + } + + scope := []string{"openid", "email", "profile"} + if params != nil && params.Scope != nil && len(scope) > 0 { + scope = params.Scope + } + + nonce := uuid.New().String() + hostname := parsers.GetHost(gc) + // user, claimRoles, scope, claimg.LoginMethod, nonce, "" + authToken, err := g.TokenProvider.CreateAuthToken(gc, &token.AuthTokenConfig{ + User: user, + Nonce: nonce, + Roles: claimRoles, + Scope: scope, + LoginMethod: claims.LoginMethod, + HostName: hostname, + }) + if err != nil { + log.Debug().Err(err).Msg("Failed to CreateAuthToken") + return nil, err + } + + // rollover the session for security + sessionKey := userID + if claims.LoginMethod != "" { + sessionKey = claims.LoginMethod + ":" + userID + } + go g.MemoryStoreProvider.DeleteUserSession(sessionKey, claims.Nonce) + + expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() + if expiresIn <= 0 { + expiresIn = 1 + } + + res := &model.AuthResponse{ + Message: `Session token refreshed`, + AccessToken: &authToken.AccessToken.Token, + ExpiresIn: &expiresIn, + IDToken: &authToken.IDToken.Token, + User: user.AsAPIUser(), + } + + cookie.SetSession(gc, authToken.FingerPrintHash, g.Config.AppCookieSecure) + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) + + if authToken.RefreshToken != nil { + res.RefreshToken = &authToken.RefreshToken.Token + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) + } + return res, nil +} diff --git a/internal/graphql/signup.go b/internal/graphql/signup.go new file mode 100644 index 000000000..0453ae30c --- /dev/null +++ b/internal/graphql/signup.go @@ -0,0 +1,372 @@ +package graphql + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strings" + "time" + + "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" +) + +// SignUp is the method to singup user +// Permission: none +func (g *graphqlProvider) SignUp(ctx context.Context, params *model.SignUpRequest) (*model.AuthResponse, error) { + log := g.Log.With().Str("func", "SignUp").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + email := strings.TrimSpace(refs.StringValue(params.Email)) + phoneNumber := strings.TrimSpace(refs.StringValue(params.PhoneNumber)) + if email == "" && phoneNumber == "" { + log.Debug().Msg("Email or phone number is required") + return nil, fmt.Errorf(`email or phone number is required`) + } + + isSignupEnabled := g.Config.EnableSignup + if !isSignupEnabled { + log.Debug().Msg("Signup is disabled") + return nil, fmt.Errorf(`signup is disabled for this instance`) + } + + isBasicAuthEnabled := g.Config.EnableBasicAuthentication + isMobileBasicAuthEnabled := g.Config.EnableMobileBasicAuthentication + if params.ConfirmPassword != params.Password { + log.Debug().Msg("Passwords do not match") + return nil, fmt.Errorf(`password and confirm password does not match`) + } + if err := validators.IsValidPassword(params.Password, !g.Config.EnableStrongPassword); err != nil { + log.Debug().Msg("Invalid password") + return nil, err + } + + log = log.With().Str("email", email).Str("phone_number", phoneNumber).Logger() + isEmailSignup := email != "" + isMobileSignup := phoneNumber != "" + if !isBasicAuthEnabled && isEmailSignup { + log.Debug().Msg("Basic authentication is disabled") + return nil, fmt.Errorf(`basic authentication is disabled for this instance`) + } + if !isMobileBasicAuthEnabled && isMobileSignup { + log.Debug().Msg("Mobile basic authentication is disabled") + return nil, fmt.Errorf(`mobile basic authentication is disabled for this instance`) + } + if isEmailSignup && !validators.IsValidEmail(email) { + log.Debug().Msg("Invalid email") + return nil, fmt.Errorf(`invalid email address`) + } + if isMobileSignup && (phoneNumber == "" || len(phoneNumber) < 10) { + log.Debug().Msg("Invalid phone number") + return nil, fmt.Errorf(`invalid phone number`) + } + // find user with email / phone number + if isEmailSignup { + existingUser, err := g.StorageProvider.GetUserByEmail(ctx, email) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by email") + } + if existingUser != nil { + if existingUser.EmailVerifiedAt != nil { + // email is verified + log.Debug().Msg("Email is already verified and signed up.") + return nil, fmt.Errorf(`%s has already signed up`, email) + } else if existingUser.ID != "" && existingUser.EmailVerifiedAt == nil { + log.Debug().Msg("Email is already signed up. Verification pending...") + return nil, fmt.Errorf("%s has already signed up. please complete the email verification process or reset the password", email) + } + } + } else { + existingUser, err := g.StorageProvider.GetUserByPhoneNumber(ctx, phoneNumber) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by phone number") + } + if existingUser != nil { + if existingUser.PhoneNumberVerifiedAt != nil { + // email is verified + log.Debug().Msg("Phone number is already verified and signed up.") + return nil, fmt.Errorf(`%s has already signed up`, phoneNumber) + } else if existingUser.ID != "" && existingUser.PhoneNumberVerifiedAt == nil { + log.Debug().Msg("Phone number is already signed up. Verification pending...") + return nil, fmt.Errorf("%s has already signed up. please complete the phone number verification process or reset the password", phoneNumber) + } + } + } + + inputRoles := params.Roles + if len(inputRoles) > 0 { + // check if roles exists + roles := g.Config.Roles + if !validators.IsValidRoles(inputRoles, roles) { + log.Debug().Err(err).Strs("roles", params.Roles).Msg("Invalid roles") + return nil, fmt.Errorf(`invalid roles`) + } + } else { + inputRoles = g.Config.DefaultRoles + } + user := &schemas.User{} + user.Roles = strings.Join(inputRoles, ",") + password, _ := crypto.EncryptPassword(params.Password) + user.Password = &password + if email != "" { + user.SignupMethods = constants.AuthRecipeMethodBasicAuth + user.Email = &email + } + if params.GivenName != nil { + user.GivenName = params.GivenName + } + + if params.FamilyName != nil { + user.FamilyName = params.FamilyName + } + + if params.MiddleName != nil { + user.MiddleName = params.MiddleName + } + + if params.Nickname != nil { + user.Nickname = params.Nickname + } + + if params.Gender != nil { + user.Gender = params.Gender + } + + if params.Birthdate != nil { + user.Birthdate = params.Birthdate + } + + if phoneNumber != "" { + user.SignupMethods = constants.AuthRecipeMethodMobileBasicAuth + user.PhoneNumber = refs.NewStringRef(phoneNumber) + } + + if params.Picture != nil { + user.Picture = params.Picture + } + + if params.IsMultiFactorAuthEnabled != nil { + user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled + } + + isMFAEnforced := g.Config.EnforceMFA + if isMFAEnforced { + user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) + } + + if params.AppData != nil { + appDataString := "" + appDataBytes, err := json.Marshal(params.AppData) + if err != nil { + log.Debug().Msg("failed to marshall source app_data") + return nil, errors.New("malformed app_data") + } + appDataString = string(appDataBytes) + user.AppData = &appDataString + } + isEmailServiceEnabled := g.Config.IsEmailServiceEnabled + isEmailVerificationEnabled := g.Config.EnableEmailVerification && isEmailServiceEnabled + if !isEmailVerificationEnabled && isEmailSignup { + now := time.Now().Unix() + user.EmailVerifiedAt = &now + } + isSMSServiceEnabled := g.Config.IsSMSServiceEnabled + isPhoneVerificationEnabled := g.Config.EnablePhoneVerification && isSMSServiceEnabled + if !isPhoneVerificationEnabled && isMobileSignup { + now := time.Now().Unix() + user.PhoneNumberVerifiedAt = &now + } + user, err = g.StorageProvider.AddUser(ctx, user) + if err != nil { + log.Debug().Err(err).Msg("failed to add user") + return nil, err + } + roles := strings.Split(user.Roles, ",") + userToReturn := user.AsAPIUser() + hostname := parsers.GetHost(gc) + if isEmailVerificationEnabled && isEmailSignup { + // insert verification request + _, nonceHash, err := utils.GenerateNonce() + if err != nil { + log.Debug().Err(err).Msg("Failed to generate nonce") + return nil, err + } + verificationType := constants.VerificationTypeBasicAuthSignup + redirectURL := parsers.GetAppURL(gc) + if params.RedirectURI != nil { + redirectURL = *params.RedirectURI + } + verificationToken, err := g.TokenProvider.CreateVerificationToken(&token.AuthTokenConfig{ + Nonce: nonceHash, + HostName: hostname, + User: user, + LoginMethod: constants.AuthRecipeMethodBasicAuth, + }, redirectURL, verificationType) + if err != nil { + log.Debug().Err(err).Msg("Failed to create verification token") + return nil, err + } + _, err = g.StorageProvider.AddVerificationRequest(ctx, &schemas.VerificationRequest{ + Token: verificationToken, + Identifier: verificationType, + ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), + Email: email, + Nonce: nonceHash, + RedirectURI: redirectURL, + }) + if err != nil { + log.Debug().Err(err).Msg("Failed to add verification request") + return nil, err + } + // exec it as go routine so that we can reduce the api latency + go func() { + // exec it as go routine so that we can reduce the api latency + g.EmailProvider.SendEmail([]string{email}, constants.VerificationTypeBasicAuthSignup, map[string]interface{}{ + "user": user.ToMap(), + "organization": utils.GetOrganization(g.Config), + "verification_url": utils.GetEmailVerificationURL(verificationToken, hostname, redirectURL), + }) + g.EventsProvider.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) + }() + + return &model.AuthResponse{ + Message: `Verification email has been sent. Please check your inbox`, + }, nil + } else if isPhoneVerificationEnabled && isMobileSignup { + duration, _ := time.ParseDuration("10m") + smsCode := utils.GenerateOTP() + smsBody := strings.Builder{} + smsBody.WriteString("Your verification code is: ") + smsBody.WriteString(smsCode) + expiresAt := time.Now().Add(duration).Unix() + _, err = g.StorageProvider.UpsertOTP(ctx, &schemas.OTP{ + PhoneNumber: phoneNumber, + Otp: smsCode, + ExpiresAt: expiresAt, + }) + if err != nil { + log.Debug().Err(err).Msg("error while upserting OTP") + return nil, err + } + mfaSession := uuid.NewString() + err = g.MemoryStoreProvider.SetMfaSession(user.ID, mfaSession, expiresAt) + if err != nil { + log.Debug().Err(err).Msg("Failed to add mfasession") + return nil, err + } + cookie.SetMfaSession(gc, mfaSession, g.Config.AppCookieSecure) + go func() { + g.SMSProvider.SendSMS(phoneNumber, smsBody.String()) + g.EventsProvider.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + }() + return &model.AuthResponse{ + Message: "Please check the OTP in your inbox", + ShouldShowMobileOtpScreen: refs.NewBoolRef(true), + }, nil + } + scope := []string{"openid", "email", "profile"} + if params.Scope != nil && len(scope) > 0 { + scope = params.Scope + } + + code := "" + codeChallenge := "" + nonce := "" + if params.State != nil { + // Get state from store + authorizeState, _ := g.MemoryStoreProvider.GetState(refs.StringValue(params.State)) + if authorizeState != "" { + authorizeStateSplit := strings.Split(authorizeState, "@@") + if len(authorizeStateSplit) > 1 { + code = authorizeStateSplit[0] + codeChallenge = authorizeStateSplit[1] + } else { + nonce = authorizeState + } + go g.MemoryStoreProvider.RemoveState(refs.StringValue(params.State)) + } + } + + if nonce == "" { + nonce = uuid.New().String() + } + authToken, err := g.TokenProvider.CreateAuthToken(gc, &token.AuthTokenConfig{ + User: user, + Roles: roles, + Scope: scope, + Nonce: nonce, + Code: code, + LoginMethod: constants.AuthRecipeMethodBasicAuth, + HostName: hostname, + }) + if err != nil { + log.Debug().Err(err).Msg("Failed to create auth token") + return nil, err + } + + // Code challenge could be optional if PKCE flow is not used + if code != "" { + if err := g.MemoryStoreProvider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { + log.Debug().Err(err).Msg("SetState failed") + return nil, err + } + } + + expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() + if expiresIn <= 0 { + expiresIn = 1 + } + + res := &model.AuthResponse{ + Message: `Signed up successfully.`, + AccessToken: &authToken.AccessToken.Token, + ExpiresIn: &expiresIn, + User: userToReturn, + } + + sessionKey := constants.AuthRecipeMethodBasicAuth + ":" + user.ID + cookie.SetSession(gc, authToken.FingerPrintHash, g.Config.AppCookieSecure) + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) + + if authToken.RefreshToken != nil { + res.RefreshToken = &authToken.RefreshToken.Token + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) + } + + go func() { + g.EventsProvider.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) + if isEmailSignup { + g.EventsProvider.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) + } else { + g.EventsProvider.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) + } + + if err := g.StorageProvider.AddSession(ctx, &schemas.Session{ + UserID: user.ID, + UserAgent: utils.GetUserAgent(gc.Request), + IP: utils.GetIP(gc.Request), + }); err != nil { + log.Debug().Err(err).Msg("Failed to add session") + } + }() + + return res, nil +} diff --git a/server/resolvers/test_endpoint.go b/internal/graphql/test_endpoint.go similarity index 61% rename from server/resolvers/test_endpoint.go rename to internal/graphql/test_endpoint.go index c0cdb230a..d9c10b8e5 100644 --- a/server/resolvers/test_endpoint.go +++ b/internal/graphql/test_endpoint.go @@ -1,4 +1,4 @@ -package resolvers +package graphql import ( "bytes" @@ -9,31 +9,30 @@ import ( "net/http" "time" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" "github.com/google/uuid" - log "github.com/sirupsen/logrus" ) -// TestEndpointResolver resolver to test webhook endpoints -func TestEndpointResolver(ctx context.Context, params model.TestEndpointRequest) (*model.TestEndpointResponse, error) { +// TestEndpoint is a service to test a webhook endpoint +// Permission: authorizer:admin +func (g *graphqlProvider) TestEndpoint(ctx context.Context, params *model.TestEndpointRequest) (*model.TestEndpointResponse, error) { + log := g.Log.With().Str("func", "TestEndpoint").Logger() gc, err := utils.GinContextFromContext(ctx) if err != nil { - log.Debug("Failed to get GinContext: ", err) + log.Debug().Err(err).Msg("Failed to get GinContext") return nil, err } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") return nil, fmt.Errorf("unauthorized") } if !validators.IsValidWebhookEventName(params.EventName) { - log.Debug("Invalid event name: ", params.EventName) + log.Debug().Str("event_name", params.EventName).Msg("Invalid event name") return nil, fmt.Errorf("invalid event_name %s", params.EventName) } @@ -48,13 +47,13 @@ func TestEndpointResolver(ctx context.Context, params model.TestEndpointRequest) userBytes, err := json.Marshal(user) if err != nil { - log.Debug("error marshalling user obj: ", err) + log.Debug().Err(err).Msg("error marshalling user obj") return nil, err } userMap := map[string]interface{}{} err = json.Unmarshal(userBytes, &userMap) if err != nil { - log.Debug("error un-marshalling user obj: ", err) + log.Debug().Err(err).Msg("error un-marshalling user obj") return nil, err } @@ -69,13 +68,13 @@ func TestEndpointResolver(ctx context.Context, params model.TestEndpointRequest) requestBody, err := json.Marshal(reqBody) if err != nil { - log.Debug("error marshalling requestBody obj: ", err) + log.Debug().Err(err).Msg("error marshalling requestBody obj") return nil, err } req, err := http.NewRequest("POST", params.Endpoint, bytes.NewBuffer(requestBody)) if err != nil { - log.Debug("error creating post request: ", err) + log.Debug().Err(err).Msg("error creating post request") return nil, err } req.Header.Set("Content-Type", "application/json") @@ -85,14 +84,14 @@ func TestEndpointResolver(ctx context.Context, params model.TestEndpointRequest) client := &http.Client{Timeout: time.Second * 30} resp, err := client.Do(req) if err != nil { - log.Debug("error making request: ", err) + log.Debug().Err(err).Msg("error making request") return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { - log.Debug("error reading response: ", err) + log.Debug().Err(err).Msg("error reading response") return nil, err } diff --git a/server/resolvers/update_email_template.go b/internal/graphql/update_email_template.go similarity index 55% rename from server/resolvers/update_email_template.go rename to internal/graphql/update_email_template.go index c08a49f6d..e9e18e430 100644 --- a/server/resolvers/update_email_template.go +++ b/internal/graphql/update_email_template.go @@ -1,49 +1,47 @@ -package resolvers +package graphql import ( "context" "fmt" "strings" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" - log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" ) -// UpdateEmailTemplateResolver resolver for update email template mutation -func UpdateEmailTemplateResolver(ctx context.Context, params model.UpdateEmailTemplateRequest) (*model.Response, error) { +// UpdateEmailTemplate for update email template mutation +// Permission: authorizer:admin +func (g *graphqlProvider) UpdateEmailTemplate(ctx context.Context, params *model.UpdateEmailTemplateRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "UpdateEmailTemplate").Logger() gc, err := utils.GinContextFromContext(ctx) if err != nil { - log.Debug("Failed to get GinContext: ", err) + log.Debug().Err(err).Msg("Failed to get GinContext") return nil, err } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") return nil, fmt.Errorf("unauthorized") } - emailTemplate, err := db.Provider.GetEmailTemplateByID(ctx, params.ID) + emailTemplate, err := g.StorageProvider.GetEmailTemplateByID(ctx, params.ID) if err != nil { - log.Debug("failed to get email template: ", err) + log.Debug().Err(err).Msg("failed GetEmailTemplateByID") return nil, err } - emailTemplateDetails := &models.EmailTemplate{ + emailTemplateDetails := &schemas.EmailTemplate{ ID: emailTemplate.ID, Key: emailTemplate.ID, EventName: emailTemplate.EventName, - CreatedAt: refs.Int64Value(emailTemplate.CreatedAt), + CreatedAt: emailTemplate.CreatedAt, } if params.EventName != nil && emailTemplateDetails.EventName != refs.StringValue(params.EventName) { if isValid := validators.IsValidEmailTemplateEventName(refs.StringValue(params.EventName)); !isValid { - log.Debug("invalid event name: ", refs.StringValue(params.EventName)) + log.Debug().Str("event_name", refs.StringValue(params.EventName)).Msg("invalid event name") return nil, fmt.Errorf("invalid event name %s", refs.StringValue(params.EventName)) } emailTemplateDetails.EventName = refs.StringValue(params.EventName) @@ -51,7 +49,7 @@ func UpdateEmailTemplateResolver(ctx context.Context, params model.UpdateEmailTe if params.Subject != nil && emailTemplateDetails.Subject != refs.StringValue(params.Subject) { if strings.TrimSpace(refs.StringValue(params.Subject)) == "" { - log.Debug("empty subject not allowed") + log.Debug().Msg("empty subject not allowed") return nil, fmt.Errorf("empty subject not allowed") } emailTemplateDetails.Subject = refs.StringValue(params.Subject) @@ -59,7 +57,7 @@ func UpdateEmailTemplateResolver(ctx context.Context, params model.UpdateEmailTe if params.Template != nil && emailTemplateDetails.Template != refs.StringValue(params.Template) { if strings.TrimSpace(refs.StringValue(params.Template)) == "" { - log.Debug("empty template not allowed") + log.Debug().Msg("empty template not allowed") return nil, fmt.Errorf("empty template not allowed") } emailTemplateDetails.Template = refs.StringValue(params.Template) @@ -67,14 +65,15 @@ func UpdateEmailTemplateResolver(ctx context.Context, params model.UpdateEmailTe if params.Design != nil && emailTemplateDetails.Design != refs.StringValue(params.Design) { if strings.TrimSpace(refs.StringValue(params.Design)) == "" { - log.Debug("empty design not allowed") + log.Debug().Msg("empty design not allowed") return nil, fmt.Errorf("empty design not allowed") } emailTemplateDetails.Design = refs.StringValue(params.Design) } - _, err = db.Provider.UpdateEmailTemplate(ctx, emailTemplateDetails) + _, err = g.StorageProvider.UpdateEmailTemplate(ctx, emailTemplateDetails) if err != nil { + log.Debug().Err(err).Msg("failed UpdateEmailTemplate") return nil, err } diff --git a/server/resolvers/update_profile.go b/internal/graphql/update_profile.go similarity index 50% rename from server/resolvers/update_profile.go rename to internal/graphql/update_profile.go index 3b9af37dd..6a7a89d61 100644 --- a/server/resolvers/update_profile.go +++ b/internal/graphql/update_profile.go @@ -1,4 +1,4 @@ -package resolvers +package graphql import ( "context" @@ -10,50 +10,44 @@ import ( "golang.org/x/crypto/bcrypt" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/email" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" ) -// UpdateProfileResolver is resolver for update profile mutation -func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error) { - var res *model.Response - +// UpdateProfile is the method to update profile +// Permissions: authenticated:user +func (g *graphqlProvider) UpdateProfile(ctx context.Context, params *model.UpdateProfileRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "UpdateProfile").Logger() gc, err := utils.GinContextFromContext(ctx) if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err } - tokenData, err := token.GetUserIDFromSessionOrAccessToken(gc) + + tokenData, err := g.TokenProvider.GetUserIDFromSessionOrAccessToken(gc) if err != nil { - log.Debug("Failed GetUserIDFromSessionOrAccessToken: ", err) - return res, err + log.Debug().Err(err).Msg("Failed GetUserIDFromSessionOrAccessToken") + return nil, err } // validate if all params are not empty if params.GivenName == nil && params.FamilyName == nil && params.Picture == nil && params.MiddleName == nil && params.Nickname == nil && params.OldPassword == nil && params.Email == nil && params.Birthdate == nil && params.Gender == nil && params.PhoneNumber == nil && params.NewPassword == nil && params.ConfirmNewPassword == nil && params.IsMultiFactorAuthEnabled == nil && params.AppData == nil { - log.Debug("All params are empty") - return res, fmt.Errorf("please enter at least one param to update") + log.Debug().Msg("All params are empty") + return nil, fmt.Errorf("please enter at least one param to update") } - log := log.WithFields(log.Fields{ - "user_id": tokenData.UserID, - }) - user, err := db.Provider.GetUserByID(ctx, tokenData.UserID) + log = log.With().Str("user_id", tokenData.UserID).Logger() + user, err := g.StorageProvider.GetUserByID(ctx, tokenData.UserID) if err != nil { - log.Debug("Failed to get user by id: ", err) - return res, err + log.Debug().Err(err).Msg("Failed to get user by id") + return nil, err } if params.GivenName != nil && refs.StringValue(user.GivenName) != refs.StringValue(params.GivenName) { @@ -82,8 +76,8 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) { // verify if phone number is unique - if _, err := db.Provider.GetUserByPhoneNumber(ctx, strings.TrimSpace(refs.StringValue(params.PhoneNumber))); err == nil { - log.Debug("user with given phone number already exists") + if _, err := g.StorageProvider.GetUserByPhoneNumber(ctx, strings.TrimSpace(refs.StringValue(params.PhoneNumber))); err == nil { + log.Debug().Msg("user with given phone number already exists") return nil, errors.New("user with given phone number already exists") } user.PhoneNumber = params.PhoneNumber @@ -96,7 +90,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) appDataString := "" appDataBytes, err := json.Marshal(params.AppData) if err != nil { - log.Debug("failed to marshall source app_data: ", err) + log.Debug().Err(err).Msg("failed to marshall source app_data") return nil, errors.New("malformed app_data") } appDataString = string(appDataBytes) @@ -105,35 +99,18 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) // Check if the user is trying to enable or disable multi-factor authentication (MFA) if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) { // Check if totp, email or sms is enabled - isMailOTPEnvServiceDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMailOTPLogin) - if err != nil { - log.Debug("Error getting mail otp disabled: ", err) - isMailOTPEnvServiceDisabled = false - } - isTOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin) - if err != nil { - log.Debug("Error getting totp disabled: ", err) - isTOTPEnvServiceDisabled = false - } - isSMSOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) - if err != nil { - log.Debug("Error getting sms otp disabled: ", err) - isSMSOTPEnvServiceDisabled = false - } + isMailOTPEnvServiceEnabled := g.Config.EnableEmailOTP + isTOTPEnvServiceEnabled := g.Config.EnableTOTPLogin + isSMSOTPEnvServiceEnabled := g.Config.EnableSMSOTP // Initialize a flag to check if enabling Mail OTP is required - if isMailOTPEnvServiceDisabled && isTOTPEnvServiceDisabled && isSMSOTPEnvServiceDisabled { - log.Debug("Cannot enable mfa service as all mfa services are disabled") + if !isMailOTPEnvServiceEnabled && !isTOTPEnvServiceEnabled && !isSMSOTPEnvServiceEnabled { + log.Debug().Msg("Cannot enable mfa service as all mfa services are disabled") return nil, errors.New("cannot enable multi factor authentication as all mfa services are disabled") } - isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication) - if err != nil { - log.Debug("MFA service not enabled: ", err) - isMFAEnforced = false - } - + isMFAEnforced := g.Config.EnforceMFA if isMFAEnforced && !refs.BoolValue(params.IsMultiFactorAuthEnabled) { - log.Debug("Cannot disable mfa service as it is enforced:") + log.Debug().Msg("Cannot disable mfa service as it is enforced.") return nil, errors.New("cannot disable multi factor authentication as it is enforced by organization") } @@ -143,14 +120,14 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) isPasswordChanging := false if params.NewPassword != nil && params.ConfirmNewPassword == nil { isPasswordChanging = true - log.Debug("confirm password is empty") - return res, fmt.Errorf("confirm password is required") + log.Debug().Msg("confirm password is empty") + return nil, fmt.Errorf("confirm password is required") } if params.ConfirmNewPassword != nil && params.NewPassword == nil { isPasswordChanging = true - log.Debug("new password is empty") - return res, fmt.Errorf("new password is required") + log.Debug().Msg("new password is empty") + return nil, fmt.Errorf("new password is required") } if params.NewPassword != nil && params.ConfirmNewPassword != nil { @@ -158,48 +135,39 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) } if isPasswordChanging && user.Password != nil && params.OldPassword == nil { - log.Debug("old password is empty") - return res, fmt.Errorf("old password is required") + log.Debug().Msg("old password is empty") + return nil, fmt.Errorf("old password is required") } if isPasswordChanging && user.Password != nil && params.OldPassword != nil { if err = bcrypt.CompareHashAndPassword([]byte(refs.StringValue(user.Password)), []byte(refs.StringValue(params.OldPassword))); err != nil { - log.Debug("Failed to compare hash and old password: ", err) - return res, fmt.Errorf("incorrect old password") + log.Debug().Err(err).Msg("Failed to compare hash and old password") + return nil, fmt.Errorf("incorrect old password") } } shouldAddBasicSignUpMethod := false - isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) - if err != nil { - log.Debug("Error getting basic auth disabled: ", err) - isBasicAuthDisabled = true - } - - isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication) - if err != nil { - log.Debug("Error getting mobile basic auth disabled: ", err) - isBasicAuthDisabled = true - } + isBasicAuthEnabled := g.Config.EnableBasicAuthentication + isMobileBasicAuthEnabled := g.Config.EnableMobileBasicAuthentication if params.NewPassword != nil && params.ConfirmNewPassword != nil { - if isBasicAuthDisabled || isMobileBasicAuthDisabled { - log.Debug("Cannot update password as basic authentication is disabled") - return res, fmt.Errorf(`basic authentication is disabled for this instance`) + if !isBasicAuthEnabled || !isMobileBasicAuthEnabled { + log.Debug().Msg("Cannot update password as basic authentication is disabled") + return nil, fmt.Errorf(`basic authentication is disabled for this instance`) } if refs.StringValue(params.ConfirmNewPassword) != refs.StringValue(params.NewPassword) { - log.Debug("Failed to compare new password and confirm new password") - return res, fmt.Errorf(`password and confirm password does not match`) + log.Debug().Msg("Failed to compare new password and confirm new password") + return nil, fmt.Errorf(`password and confirm password does not match`) } if user.Password == nil || refs.StringValue(user.Password) == "" { shouldAddBasicSignUpMethod = true } - if err := validators.IsValidPassword(refs.StringValue(params.NewPassword)); err != nil { - log.Debug("Invalid password") - return res, err + if err := validators.IsValidPassword(refs.StringValue(params.NewPassword), !g.Config.EnableStrongPassword); err != nil { + log.Debug().Msg("Invalid password") + return nil, err } password, _ := crypto.EncryptPassword(refs.StringValue(params.NewPassword)) @@ -215,51 +183,53 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) if params.Email != nil && refs.StringValue(user.Email) != refs.StringValue(params.Email) { // check if valid email if !validators.IsValidEmail(*params.Email) { - log.Debug("Failed to validate email: ", refs.StringValue(params.Email)) - return res, fmt.Errorf("invalid email address") + log.Debug().Str("email", refs.StringValue(params.Email)).Msg("Failed to validate email") + return nil, fmt.Errorf("invalid email address") } newEmail := strings.ToLower(*params.Email) // check if valid email if !validators.IsValidEmail(newEmail) { - log.Debug("Failed to validate new email: ", newEmail) - return res, fmt.Errorf("invalid new email address") + log.Debug().Str("new_email", newEmail).Msg("Failed to validate new email: ") + return nil, fmt.Errorf("invalid new email address") } // check if user with new email exists - _, err := db.Provider.GetUserByEmail(ctx, newEmail) + _, err := g.StorageProvider.GetUserByEmail(ctx, newEmail) // err = nil means user exists if err == nil { - log.Debug("Failed to get user by email: ", newEmail) - return res, fmt.Errorf("user with this email address already exists") + log.Debug().Str("new_email", newEmail).Msg("User with new email already exists") + return nil, fmt.Errorf("user with this email address already exists") } - go memorystore.Provider.DeleteAllUserSessions(user.ID) - go cookie.DeleteSession(gc) + go g.MemoryStoreProvider.DeleteAllUserSessions(user.ID) + go cookie.DeleteSession(gc, g.Config.AppCookieSecure) user.Email = &newEmail - isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) - if err != nil { - log.Debug("Failed to get disable email verification env variable: ", err) - return res, err - } - if !isEmailVerificationDisabled { + isEmailVerificationEnabled := g.Config.EnableEmailVerification + if isEmailVerificationEnabled { hostname := parsers.GetHost(gc) user.EmailVerifiedAt = nil hasEmailChanged = true // insert verification request _, nonceHash, err := utils.GenerateNonce() if err != nil { - log.Debug("Failed to generate nonce: ", err) - return res, err + log.Debug().Err(err).Msg("Failed to generate nonce") + return nil, err } verificationType := constants.VerificationTypeUpdateEmail redirectURL := parsers.GetAppURL(gc) - verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname, nonceHash, redirectURL) + + verificationToken, err := g.TokenProvider.CreateVerificationToken(&token.AuthTokenConfig{ + User: user, + HostName: hostname, + Nonce: nonceHash, + LoginMethod: constants.AuthRecipeMethodBasicAuth, + }, redirectURL, verificationType) if err != nil { - log.Debug("Failed to create verification token: ", err) - return res, err + log.Debug().Err(err).Msg("Failed to create verification token") + return nil, err } - _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ + _, err = g.StorageProvider.AddVerificationRequest(ctx, &schemas.VerificationRequest{ Token: verificationToken, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), @@ -268,31 +238,30 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) RedirectURI: redirectURL, }) if err != nil { - log.Debug("Failed to add verification request: ", err) - return res, err + log.Debug().Err(err).Msg("Failed to add verification request") + return nil, err } // exec it as go routine so that we can reduce the api latency - go email.SendEmail([]string{refs.StringValue(user.Email)}, verificationType, map[string]interface{}{ + go g.EmailProvider.SendEmail([]string{refs.StringValue(user.Email)}, verificationType, map[string]interface{}{ "user": user.ToMap(), - "organization": utils.GetOrganization(), + "organization": utils.GetOrganization(g.Config), "verification_url": utils.GetEmailVerificationURL(verificationToken, hostname, redirectURL), }) } } - _, err = db.Provider.UpdateUser(ctx, user) + _, err = g.StorageProvider.UpdateUser(ctx, user) if err != nil { - log.Debug("Failed to update user: ", err) - return res, err + log.Debug().Err(err).Msg("Failed to update user") + return nil, err } message := `Profile details updated successfully.` if hasEmailChanged { message += `For the email change we have sent new verification email, please verify and continue` } - res = &model.Response{ - Message: message, - } - return res, nil + return &model.Response{ + Message: message, + }, nil } diff --git a/internal/graphql/update_user.go b/internal/graphql/update_user.go new file mode 100644 index 000000000..f47ba757b --- /dev/null +++ b/internal/graphql/update_user.go @@ -0,0 +1,257 @@ +package graphql + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strings" + "time" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" +) + +// UpdateUser is the method to update user details +// Permission: authorizer:admin +func (g *graphqlProvider) UpdateUser(ctx context.Context, params *model.UpdateUserRequest) (*model.User, error) { + log := g.Log.With().Str("func", "UpdateUser").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + if params.ID == "" { + log.Debug().Msg("user id is missing") + return nil, fmt.Errorf("user_id is missing") + } + + log = log.With().Str("user_id", params.ID).Logger() + + if params.GivenName == nil && + params.FamilyName == nil && + params.Picture == nil && + params.MiddleName == nil && + params.Nickname == nil && + params.Email == nil && + params.Birthdate == nil && + params.Gender == nil && + params.PhoneNumber == nil && + params.Roles == nil && + params.IsMultiFactorAuthEnabled == nil && + params.AppData == nil { + log.Debug().Msg("please enter atleast one param to update") + return nil, fmt.Errorf("please enter atleast one param to update") + } + + user, err := g.StorageProvider.GetUserByID(ctx, params.ID) + if err != nil { + log.Debug().Err(err).Msg("failed GetUserByID") + return nil, fmt.Errorf(`User not found`) + } + + if params.GivenName != nil && refs.StringValue(user.GivenName) != refs.StringValue(params.GivenName) { + user.GivenName = params.GivenName + } + + if params.FamilyName != nil && refs.StringValue(user.FamilyName) != refs.StringValue(params.FamilyName) { + user.FamilyName = params.FamilyName + } + + if params.MiddleName != nil && refs.StringValue(user.MiddleName) != refs.StringValue(params.MiddleName) { + user.MiddleName = params.MiddleName + } + + if params.Nickname != nil && refs.StringValue(user.Nickname) != refs.StringValue(params.Nickname) { + user.Nickname = params.Nickname + } + + if params.Birthdate != nil && refs.StringValue(user.Birthdate) != refs.StringValue(params.Birthdate) { + user.Birthdate = params.Birthdate + } + + if params.Gender != nil && refs.StringValue(user.Gender) != refs.StringValue(params.Gender) { + user.Gender = params.Gender + } + // TODO + // if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) { + // // verify if phone number is unique + // if _, err := g.StorageProvider.GetUserByPhoneNumber(ctx, strings.TrimSpace(refs.StringValue(params.PhoneNumber))); err == nil { + // log.Debug().Msg("user with given phone number already exists") + // return nil, errors.New("user with given phone number already exists") + // } + // user.PhoneNumber = params.PhoneNumber + // } + + if params.Picture != nil && refs.StringValue(user.Picture) != refs.StringValue(params.Picture) { + user.Picture = params.Picture + } + + if params.AppData != nil { + appDataString := "" + appDataBytes, err := json.Marshal(params.AppData) + if err != nil { + log.Debug().Err(err).Msg("failed to marshal app_data") + return nil, errors.New("malformed app_data") + } + appDataString = string(appDataBytes) + user.AppData = &appDataString + } + + if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) { + user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled + if refs.BoolValue(params.IsMultiFactorAuthEnabled) { + // Check if totp, email or sms is enabled + isMailOTPEnvServiceEnabled := g.Config.EnableEmailOTP + isTOTPEnvServiceEnabled := g.Config.EnableTOTPLogin + isSMSOTPEnvServiceEnabled := g.Config.EnableSMSOTP + // Initialize a flag to check if enabling Mail OTP is required + if !isMailOTPEnvServiceEnabled && !isTOTPEnvServiceEnabled && !isSMSOTPEnvServiceEnabled { + log.Debug().Msg("cannot enable multi factor authentication as all mfa services are disabled") + return nil, errors.New("cannot enable multi factor authentication as all mfa services are disabled") + } + } + } + + if params.EmailVerified != nil { + if *params.EmailVerified { + now := time.Now().Unix() + user.EmailVerifiedAt = &now + } else { + user.EmailVerifiedAt = nil + } + } + if params.PhoneNumberVerified != nil { + if *params.PhoneNumberVerified { + now := time.Now().Unix() + user.PhoneNumberVerifiedAt = &now + } else { + user.PhoneNumberVerifiedAt = nil + } + + } + + if params.Email != nil && refs.StringValue(user.Email) != refs.StringValue(params.Email) { + // check if valid email + if !validators.IsValidEmail(*params.Email) { + log.Debug().Str("email", *params.Email).Msg("Invalid email address") + return nil, fmt.Errorf("invalid email address") + } + newEmail := strings.ToLower(*params.Email) + // check if user with new email exists + _, err = g.StorageProvider.GetUserByEmail(ctx, newEmail) + // err = nil means user exists + if err == nil { + log.Debug().Str("email", newEmail).Msg("User with email already exists") + return nil, fmt.Errorf("user with this email address already exists") + } + + go g.MemoryStoreProvider.DeleteAllUserSessions(user.ID) + + hostname := parsers.GetHost(gc) + user.Email = &newEmail + user.EmailVerifiedAt = nil + // insert verification request + _, nonceHash, err := utils.GenerateNonce() + if err != nil { + log.Debug().Err(err).Msg("Failed to generate nonce") + return nil, err + } + verificationType := constants.VerificationTypeUpdateEmail + redirectURL := parsers.GetAppURL(gc) + // newEmail, verificationType, hostname, nonceHash, redirectURL + verificationToken, err := g.TokenProvider.CreateVerificationToken(&token.AuthTokenConfig{ + User: user, + Nonce: nonceHash, + HostName: hostname, + LoginMethod: constants.AuthRecipeMethodBasicAuth, + }, redirectURL, verificationType) + if err != nil { + log.Debug().Err(err).Msg("Failed to create verification token") + return nil, err + } + _, err = g.StorageProvider.AddVerificationRequest(ctx, &schemas.VerificationRequest{ + Token: verificationToken, + Identifier: verificationType, + ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), + Email: newEmail, + Nonce: nonceHash, + RedirectURI: redirectURL, + }) + if err != nil { + log.Debug().Err(err).Msg("Failed to add verification request") + return nil, err + } + + // exec it as go routine so that we can reduce the api latency + go g.EmailProvider.SendEmail([]string{refs.StringValue(user.Email)}, constants.VerificationTypeBasicAuthSignup, map[string]interface{}{ + "user": user.ToMap(), + "organization": utils.GetOrganization(g.Config), + "verification_url": utils.GetEmailVerificationURL(verificationToken, hostname, redirectURL), + }) + + } + + if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) { + phone := strings.TrimSpace(refs.StringValue(params.PhoneNumber)) + if len(phone) < 10 || len(phone) > 15 { + log.Debug().Str("phone", phone).Msg("Invalid phone number") + return nil, fmt.Errorf("invalid phone number") + } + // check if user with new phone number exists + _, err = g.StorageProvider.GetUserByPhoneNumber(ctx, phone) + // err = nil means user exists + if err == nil { + log.Debug().Str("phone", phone).Msg("User with phone number already exists") + return nil, fmt.Errorf("user with this phone number already exists") + } + go g.MemoryStoreProvider.DeleteAllUserSessions(user.ID) + user.PhoneNumber = &phone + user.PhoneNumberVerifiedAt = nil + } + + rolesToSave := "" + if len(params.Roles) > 0 { + currentRoles := strings.Split(user.Roles, ",") + inputRoles := []string{} + for _, item := range params.Roles { + inputRoles = append(inputRoles, *item) + } + + roles := g.Config.Roles + protectedRoles := g.Config.ProtectedRoles + + if !validators.IsValidRoles(inputRoles, append([]string{}, append(roles, protectedRoles...)...)) { + log.Debug().Msg("Invalid list of roles") + return nil, fmt.Errorf("invalid list of roles") + } + + if !validators.IsStringArrayEqual(inputRoles, currentRoles) { + rolesToSave = strings.Join(inputRoles, ",") + } + + go g.MemoryStoreProvider.DeleteAllUserSessions(user.ID) + } + + if rolesToSave != "" { + user.Roles = rolesToSave + } + user, err = g.StorageProvider.UpdateUser(ctx, user) + if err != nil { + log.Debug().Err(err).Msg("failed UpdateUser") + return nil, err + } + + return user.AsAPIUser(), nil +} diff --git a/server/resolvers/update_webhook.go b/internal/graphql/update_webhook.go similarity index 50% rename from server/resolvers/update_webhook.go rename to internal/graphql/update_webhook.go index 3d0956888..7f4401282 100644 --- a/server/resolvers/update_webhook.go +++ b/internal/graphql/update_webhook.go @@ -1,4 +1,4 @@ -package resolvers +package graphql import ( "context" @@ -6,61 +6,65 @@ import ( "fmt" "strings" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" - log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/utils" + "github.com/authorizerdev/authorizer/internal/validators" ) -// UpdateWebhookResolver resolver for update webhook mutation -func UpdateWebhookResolver(ctx context.Context, params model.UpdateWebhookRequest) (*model.Response, error) { +// UpdateWebhook is the method to update webhook details +// Permission: authorizer:admin +func (g *graphqlProvider) UpdateWebhook(ctx context.Context, params *model.UpdateWebhookRequest) (*model.Response, error) { + log := g.Log.With().Str("func", "UpdateWebhook").Logger() gc, err := utils.GinContextFromContext(ctx) if err != nil { - log.Debug("Failed to get GinContext: ", err) + log.Debug().Err(err).Msg("Failed to get GinContext") return nil, err } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") return nil, fmt.Errorf("unauthorized") } - webhook, err := db.Provider.GetWebhookByID(ctx, params.ID) + webhook, err := g.StorageProvider.GetWebhookByID(ctx, params.ID) if err != nil { - log.Debug("failed to get webhook: ", err) + log.Debug().Err(err).Msg("failed GetWebhookByID") return nil, err } + var headersMap map[string]interface{} + err = json.Unmarshal([]byte(webhook.Headers), &headersMap) + if err != nil { + log.Debug().Err(err).Msg("error un-marshalling headers") + } headersString := "" - if webhook.Headers != nil { + if headersMap != nil { headerBytes, err := json.Marshal(webhook.Headers) if err != nil { - log.Debug("failed to marshall source headers: ", err) + log.Debug().Err(err).Msg("failed to marshall headers") + return nil, err } headersString = string(headerBytes) } - webhookDetails := &models.Webhook{ + webhookDetails := &schemas.Webhook{ ID: webhook.ID, Key: webhook.ID, - EventName: refs.StringValue(webhook.EventName), - EventDescription: refs.StringValue(webhook.EventDescription), - EndPoint: refs.StringValue(webhook.Endpoint), - Enabled: refs.BoolValue(webhook.Enabled), + EventName: webhook.EventName, + EventDescription: webhook.EventDescription, + EndPoint: webhook.EndPoint, + Enabled: webhook.Enabled, Headers: headersString, - CreatedAt: refs.Int64Value(webhook.CreatedAt), + CreatedAt: webhook.CreatedAt, } if params.EventName != nil && webhookDetails.EventName != refs.StringValue(params.EventName) { if isValid := validators.IsValidWebhookEventName(refs.StringValue(params.EventName)); !isValid { - log.Debug("invalid event name: ", refs.StringValue(params.EventName)) + log.Debug().Str("event_name", refs.StringValue(params.EventName)).Msg("invalid event name") return nil, fmt.Errorf("invalid event name %s", refs.StringValue(params.EventName)) } webhookDetails.EventName = refs.StringValue(params.EventName) } if params.Endpoint != nil && webhookDetails.EndPoint != refs.StringValue(params.Endpoint) { if strings.TrimSpace(refs.StringValue(params.Endpoint)) == "" { - log.Debug("empty endpoint not allowed") + log.Debug().Msg("empty endpoint not allowed") return nil, fmt.Errorf("empty endpoint not allowed") } webhookDetails.EndPoint = refs.StringValue(params.Endpoint) @@ -74,14 +78,15 @@ func UpdateWebhookResolver(ctx context.Context, params model.UpdateWebhookReques if params.Headers != nil { headerBytes, err := json.Marshal(params.Headers) if err != nil { - log.Debug("failed to marshall headers: ", err) + log.Debug().Err(err).Msg("failed to marshall headers") return nil, err } webhookDetails.Headers = string(headerBytes) } - _, err = db.Provider.UpdateWebhook(ctx, webhookDetails) + _, err = g.StorageProvider.UpdateWebhook(ctx, webhookDetails) if err != nil { + log.Debug().Err(err).Msg("failed UpdateWebhook") return nil, err } return &model.Response{ diff --git a/internal/graphql/user.go b/internal/graphql/user.go new file mode 100644 index 000000000..cc568d5f1 --- /dev/null +++ b/internal/graphql/user.go @@ -0,0 +1,45 @@ +package graphql + +import ( + "context" + "fmt" + "strings" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// User is the method to get user details +// Permission: authorizer:admin +func (g *graphqlProvider) User(ctx context.Context, params *model.GetUserRequest) (*model.User, error) { + log := g.Log.With().Str("func", "User").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + // Try getting user by ID + if params.ID != nil && strings.Trim(*params.ID, " ") != "" { + res, err := g.StorageProvider.GetUserByID(ctx, *params.ID) + if err != nil { + log.Debug().Err(err).Msg("failed GetUserByID") + return nil, err + } + return res.AsAPIUser(), nil + } + // Try getting user by email + if params.Email != nil && strings.Trim(*params.Email, " ") != "" { + res, err := g.StorageProvider.GetUserByEmail(ctx, *params.Email) + if err != nil { + log.Debug().Err(err).Msg("failed GetUserByEmail") + return nil, err + } + return res.AsAPIUser(), nil + } + // Return error if no params are provided + return nil, fmt.Errorf("invalid params, user id or email is required") +} diff --git a/internal/graphql/users.go b/internal/graphql/users.go new file mode 100644 index 000000000..caa4daaf8 --- /dev/null +++ b/internal/graphql/users.go @@ -0,0 +1,40 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// Users is the method to get list of users +// Permission: authorizer:admin +func (g *graphqlProvider) Users(ctx context.Context, params *model.PaginatedRequest) (*model.Users, error) { + log := g.Log.With().Str("func", "Users").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + pagination := utils.GetPagination(params) + + res, pagination, err := g.StorageProvider.ListUsers(ctx, pagination) + if err != nil { + log.Debug().Err(err).Msg("failed ListUsers") + return nil, err + } + resItems := make([]*model.User, len(res)) + for i, user := range res { + resItems[i] = user.AsAPIUser() + } + return &model.Users{ + Pagination: pagination, + Users: resItems, + }, nil +} diff --git a/server/resolvers/validate_jwt_token.go b/internal/graphql/validate_jwt_token.go similarity index 50% rename from server/resolvers/validate_jwt_token.go rename to internal/graphql/validate_jwt_token.go index 7dbb32fde..02c3acace 100644 --- a/server/resolvers/validate_jwt_token.go +++ b/internal/graphql/validate_jwt_token.go @@ -1,37 +1,38 @@ -package resolvers +package graphql import ( "context" "errors" "fmt" - "github.com/golang-jwt/jwt" - log "github.com/sirupsen/logrus" + "github.com/golang-jwt/jwt/v4" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" ) -// ValidateJwtTokenResolver is used to validate a jwt token without its rotation +// ValidateJwtToken is used to validate a jwt token without its rotation // this can be used at API level (backend) // it can validate: // access_token // id_token // refresh_token -func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) { +// Permission: none +func (g *graphqlProvider) ValidateJWTToken(ctx context.Context, params *model.ValidateJWTTokenRequest) (*model.ValidateJWTTokenResponse, error) { + log := g.Log.With().Str("func", "ValidateJWTToken").Logger() gc, err := utils.GinContextFromContext(ctx) if err != nil { - log.Debug("Failed to get GinContext: ", err) + log.Debug().Err(err).Msg("Failed to get GinContext") return nil, err } tokenType := params.TokenType if tokenType != constants.TokenTypeAccessToken && tokenType != constants.TokenTypeRefreshToken && tokenType != constants.TokenTypeIdentityToken { - log.Debug("Invalid token type: ", tokenType) + log.Debug().Str("token_type", tokenType).Msg("Invalid token type") return nil, errors.New("invalid token type") } @@ -40,9 +41,9 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken userID := "" nonce := "" - claims, err = token.ParseJWTToken(params.Token) + claims, err = g.TokenProvider.ParseJWTToken(params.Token) if err != nil { - log.Debug("Failed to parse JWT token: ", err) + log.Debug().Err(err).Msg("Failed to parse jwt token") return nil, err } userID = claims["sub"].(string) @@ -55,9 +56,9 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken if loginMethod != nil && loginMethod != "" { sessionKey = loginMethod.(string) + ":" + userID } - token, err := memorystore.Provider.GetUserSession(sessionKey, tokenType+"_"+claims["nonce"].(string)) + token, err := g.MemoryStoreProvider.GetUserSession(sessionKey, tokenType+"_"+claims["nonce"].(string)) if err != nil || token == "" { - log.Debug("Failed to get user session: ", err) + log.Debug().Err(err).Msg("Failed to get token from session store") return nil, errors.New("invalid token") } } @@ -66,36 +67,39 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken // we cannot validate nonce in case of id_token as that token is not persisted in session store if nonce != "" { - if ok, err := token.ValidateJWTClaims(claims, hostname, nonce, userID); !ok || err != nil { - log.Debug("Failed to parse jwt token: ", err) + if ok, err := g.TokenProvider.ValidateJWTClaims(claims, &token.AuthTokenConfig{ + HostName: hostname, + Nonce: nonce, + User: &schemas.User{ + ID: userID, + }, + }); !ok || err != nil { + log.Debug().Err(err).Msg("Failed to validate jwt claims") return nil, errors.New("invalid claims") } } else { - if ok, err := token.ValidateJWTTokenWithoutNonce(claims, hostname, userID); !ok || err != nil { - log.Debug("Failed to parse jwt token without nonce: ", err) + if ok, err := g.TokenProvider.ValidateJWTTokenWithoutNonce(claims, &token.AuthTokenConfig{ + HostName: hostname, + User: &schemas.User{ + ID: userID, + }, + }); !ok || err != nil { + log.Debug().Err(err).Msg("Failed to validate jwt claims") return nil, errors.New("invalid claims") } } - claimKey := "roles" - - if tokenType == constants.TokenTypeIdentityToken { - claimKey, err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtRoleClaim) - if err != nil { - claimKey = "roles" - } - } - + claimKey := g.Config.JWTRoleClaim claimRolesInterface := claims[claimKey] roleSlice := utils.ConvertInterfaceToSlice(claimRolesInterface) for _, v := range roleSlice { claimRoles = append(claimRoles, v.(string)) } - if params.Roles != nil && len(params.Roles) > 0 { + if len(params.Roles) > 0 { for _, v := range params.Roles { if !utils.StringSliceContains(claimRoles, v) { - log.Debug("Token does not have required role: ", v) + log.Debug().Str("role", v).Msg("Role not found in claims") return nil, fmt.Errorf(`unauthorized`) } } diff --git a/server/resolvers/validate_session.go b/internal/graphql/validate_session.go similarity index 50% rename from server/resolvers/validate_session.go rename to internal/graphql/validate_session.go index e5be53956..b3afe7d4d 100644 --- a/server/resolvers/validate_session.go +++ b/internal/graphql/validate_session.go @@ -1,23 +1,22 @@ -package resolvers +package graphql import ( "context" "errors" "fmt" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" ) -// ValidateSessionResolver is used to validate a cookie session without its rotation -func ValidateSessionResolver(ctx context.Context, params *model.ValidateSessionInput) (*model.ValidateSessionResponse, error) { +// ValidateSession is used to validate a cookie session without its rotation +// Permission: authorized:user +func (g *graphqlProvider) ValidateSession(ctx context.Context, params *model.ValidateSessionRequest) (*model.ValidateSessionResponse, error) { + log := g.Log.With().Str("func", "ValidateSession").Logger() gc, err := utils.GinContextFromContext(ctx) if err != nil { - log.Debug("Failed to get GinContext: ", err) + log.Debug().Err(err).Msg("Failed to get GinContext") return nil, err } sessionToken := "" @@ -26,29 +25,27 @@ func ValidateSessionResolver(ctx context.Context, params *model.ValidateSessionI } else { sessionToken, err = cookie.GetSession(gc) if err != nil { - log.Debug("Failed to get session token: ", err) + log.Debug().Err(err).Msg("Failed to get session token") return nil, errors.New("unauthorized") } } if sessionToken == "" { sessionToken, err = cookie.GetSession(gc) if err != nil { - log.Debug("Failed to get session token: ", err) + log.Debug().Err(err).Msg("Failed to get session token") return nil, errors.New("unauthorized") } } - claims, err := token.ValidateBrowserSession(gc, sessionToken) + claims, err := g.TokenProvider.ValidateBrowserSession(gc, sessionToken) if err != nil { - log.Debug("Failed to validate session token", err) + log.Debug().Err(err).Msg("Failed to validate session") return nil, errors.New("unauthorized") } userID := claims.Subject - log := log.WithFields(log.Fields{ - "user_id": userID, - }) - user, err := db.Provider.GetUserByID(ctx, userID) + log.Debug().Str("userID", userID).Msg("Validated session") + user, err := g.StorageProvider.GetUserByID(ctx, userID) if err != nil { - log.Debug("Failed to get user: ", err) + log.Debug().Err(err).Msg("failed GetUserByID") return nil, err } // refresh token has "roles" as claim @@ -58,7 +55,7 @@ func ValidateSessionResolver(ctx context.Context, params *model.ValidateSessionI if params != nil && params.Roles != nil && len(params.Roles) > 0 { for _, v := range params.Roles { if !utils.StringSliceContains(claimRoles, v) { - log.Debug("User does not have required role: ", claimRoles, v) + log.Debug().Str("role", v).Msg("Role not found in claims") return nil, fmt.Errorf(`unauthorized`) } } diff --git a/internal/graphql/verification_requests.go b/internal/graphql/verification_requests.go new file mode 100644 index 000000000..896f2dd8e --- /dev/null +++ b/internal/graphql/verification_requests.go @@ -0,0 +1,41 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// VerificationRequests is used to get all verification requests +// Permission: authorizer:admin +func (g *graphqlProvider) VerificationRequests(ctx context.Context, params *model.PaginatedRequest) (*model.VerificationRequests, error) { + log := g.Log.With().Str("func", "VerificationRequests").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + pagination := utils.GetPagination(params) + requests, pagination, err := g.StorageProvider.ListVerificationRequests(ctx, pagination) + if err != nil { + log.Debug().Err(err).Msg("failed ListVerificationRequests") + return nil, err + } + + res := make([]*model.VerificationRequest, len(requests)) + for i, request := range requests { + res[i] = request.AsAPIVerificationRequest() + } + + return &model.VerificationRequests{ + Pagination: pagination, + VerificationRequests: res, + }, nil +} diff --git a/internal/graphql/verify_email.go b/internal/graphql/verify_email.go new file mode 100644 index 000000000..23aeff186 --- /dev/null +++ b/internal/graphql/verify_email.go @@ -0,0 +1,228 @@ +package graphql + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// VerifyEmail is the method to verify email +// Permission: none +func (g *graphqlProvider) VerifyEmail(ctx context.Context, params *model.VerifyEmailRequest) (*model.AuthResponse, error) { + log := g.Log.With().Str("func", "VerifyEmail").Logger() + + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + verificationRequest, err := g.StorageProvider.GetVerificationRequestByToken(ctx, params.Token) + if err != nil { + log.Debug().Err(err).Msg("failed GetVerificationRequestByToken") + return nil, fmt.Errorf(`invalid token: %s`, err.Error()) + } + + // verify if token exists in db + hostname := parsers.GetHost(gc) + claim, err := g.TokenProvider.ParseJWTToken(params.Token) + if err != nil { + log.Debug().Err(err).Msg("Failed to parse jwt token") + return nil, fmt.Errorf(`invalid token: %s`, err.Error()) + } + + if ok, err := g.TokenProvider.ValidateJWTClaims(claim, &token.AuthTokenConfig{ + HostName: hostname, + Nonce: verificationRequest.Nonce, + User: &schemas.User{ + Email: &verificationRequest.Email, + }, + }); !ok || err != nil { + log.Debug().Err(err).Msg("Failed to validate jwt claims") + return nil, fmt.Errorf(`invalid token: %s`, err.Error()) + } + + email := claim["sub"].(string) + log.Debug().Str("email", email).Msg("Email verified successfully") + user, err := g.StorageProvider.GetUserByEmail(ctx, email) + if err != nil { + log.Debug().Err(err).Msg("failed GetUserByEmail") + return nil, err + } + + isMFAEnabled := g.Config.EnableMFA + isTOTPLoginEnabled := g.Config.EnableTOTPLogin + + setOTPMFaSession := func(expiresAt int64) error { + mfaSession := uuid.NewString() + err = g.MemoryStoreProvider.SetMfaSession(user.ID, mfaSession, expiresAt) + if err != nil { + log.Debug().Err(err).Msg("Failed to set mfa session") + return err + } + cookie.SetMfaSession(gc, mfaSession, g.Config.AppCookieSecure) + return nil + } + + // If mfa enabled and also totp enabled + if refs.BoolValue(user.IsMultiFactorAuthEnabled) && isMFAEnabled && isTOTPLoginEnabled { + expiresAt := time.Now().Add(3 * time.Minute).Unix() + if err := setOTPMFaSession(expiresAt); err != nil { + log.Debug().Err(err).Msg("Failed to set mfa session") + return nil, err + } + authenticator, err := g.StorageProvider.GetAuthenticatorDetailsByUserId(ctx, user.ID, constants.EnvKeyTOTPAuthenticator) + if err != nil || authenticator == nil || authenticator.VerifiedAt == nil { + // generate totp + // Generate a base64 URL and initiate the registration for TOTP + authConfig, err := g.AuthenticatorProvider.Generate(ctx, user.ID) + if err != nil { + log.Debug().Err(err).Msg("Failed to generate totp") + return nil, err + } + recoveryCodes := []*string{} + for _, code := range authConfig.RecoveryCodes { + recoveryCodes = append(recoveryCodes, refs.NewStringRef(code)) + } + // when user is first time registering for totp + res := &model.AuthResponse{ + Message: `Proceed to totp verification screen`, + ShouldShowTotpScreen: refs.NewBoolRef(true), + AuthenticatorScannerImage: refs.NewStringRef(authConfig.ScannerImage), + AuthenticatorSecret: refs.NewStringRef(authConfig.Secret), + AuthenticatorRecoveryCodes: recoveryCodes, + } + return res, nil + } else { + //when user is already register for totp + res := &model.AuthResponse{ + Message: `Proceed to totp screen`, + ShouldShowTotpScreen: refs.NewBoolRef(true), + } + return res, nil + } + } + + isSignUp := false + if user.EmailVerifiedAt == nil { + isSignUp = true + // update email_verified_at in users table + now := time.Now().Unix() + user.EmailVerifiedAt = &now + user, err = g.StorageProvider.UpdateUser(ctx, user) + if err != nil { + log.Debug().Err(err).Msg("failed UpdateUser") + return nil, err + } + } + // delete from verification table + err = g.StorageProvider.DeleteVerificationRequest(gc, verificationRequest) + if err != nil { + log.Debug().Err(err).Msg("failed DeleteVerificationRequest") + return nil, err + } + + loginMethod := constants.AuthRecipeMethodBasicAuth + if loginMethod == constants.VerificationTypeMagicLinkLogin { + loginMethod = constants.AuthRecipeMethodMagicLinkLogin + } + + roles := strings.Split(user.Roles, ",") + scope := []string{"openid", "email", "profile"} + code := "" + // Not required as /oauth/token cannot be resumed from other tab + // codeChallenge := "" + nonce := "" + if params.State != nil { + // Get state from store + authorizeState, _ := g.MemoryStoreProvider.GetState(refs.StringValue(params.State)) + if authorizeState != "" { + authorizeStateSplit := strings.Split(authorizeState, "@@") + if len(authorizeStateSplit) > 1 { + code = authorizeStateSplit[0] + // Not required as /oauth/token cannot be resumed from other tab + // codeChallenge = authorizeStateSplit[1] + } else { + nonce = authorizeState + } + go g.MemoryStoreProvider.RemoveState(refs.StringValue(params.State)) + } + } + if nonce == "" { + nonce = uuid.New().String() + } + authToken, err := g.TokenProvider.CreateAuthToken(gc, &token.AuthTokenConfig{ + HostName: hostname, + User: user, + Roles: roles, + Scope: scope, + LoginMethod: loginMethod, + Nonce: nonce, + Code: code, + }) + if err != nil { + log.Debug().Err(err).Msg("Failed to create auth token") + return nil, err + } + + // Code challenge could be optional if PKCE flow is not used + // Not required as /oauth/token cannot be resumed from other tab + // if code != "" { + // if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { + // log.Debug("SetState failed: ", err) + // return nil, err + // } + // } + go func() { + if isSignUp { + g.EventsProvider.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user) + // User is also logged in with signup + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) + } else { + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) + } + + if err := g.StorageProvider.AddSession(ctx, &schemas.Session{ + UserID: user.ID, + UserAgent: utils.GetUserAgent(gc.Request), + IP: utils.GetIP(gc.Request), + }); err != nil { + log.Debug().Err(err).Msg("Failed to add session") + } + }() + expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() + if expiresIn <= 0 { + expiresIn = 1 + } + + res := &model.AuthResponse{ + Message: `Email verified successfully.`, + AccessToken: &authToken.AccessToken.Token, + IDToken: &authToken.IDToken.Token, + ExpiresIn: &expiresIn, + User: user.AsAPIUser(), + } + + sessionKey := loginMethod + ":" + user.ID + cookie.SetSession(gc, authToken.FingerPrintHash, g.Config.AppCookieSecure) + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) + + if authToken.RefreshToken != nil { + res.RefreshToken = &authToken.RefreshToken.Token + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) + } + return res, nil +} diff --git a/internal/graphql/verify_otp.go b/internal/graphql/verify_otp.go new file mode 100644 index 000000000..27b8a87aa --- /dev/null +++ b/internal/graphql/verify_otp.go @@ -0,0 +1,229 @@ +package graphql + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// VerifyOtp is the method to verify OTP +// authorized otp request +func (g *graphqlProvider) VerifyOTP(ctx context.Context, params *model.VerifyOTPRequest) (*model.AuthResponse, error) { + log := g.Log.With().Str("func", "VerifyOTP").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + + mfaSession, err := cookie.GetMfaSession(gc) + if err != nil { + log.Debug().Err(err).Msg("Failed to get mfa session") + return nil, fmt.Errorf(`invalid session: %s`, err.Error()) + } + + email := strings.TrimSpace(refs.StringValue(params.Email)) + phoneNumber := strings.TrimSpace(refs.StringValue(params.PhoneNumber)) + if email == "" && phoneNumber == "" { + log.Debug().Msg("Email or phone number is required") + return nil, fmt.Errorf(`email or phone number is required`) + } + isEmailVerification := email != "" + isMobileVerification := phoneNumber != "" + log = log.With().Str("email", email).Str("phone_number", phoneNumber).Logger() + // Get user by email or phone number + var user *schemas.User + if isEmailVerification { + user, err = g.StorageProvider.GetUserByEmail(ctx, refs.StringValue(params.Email)) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by email") + } + } else { + user, err = g.StorageProvider.GetUserByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber)) + if err != nil { + log.Debug().Err(err).Msg("Failed to get user by phone number") + } + } + if user == nil || err != nil { + log.Debug().Err(err).Msg("User not found") + return nil, fmt.Errorf(`user not found`) + } + // Verify OTP based on TOPT or OTP + if refs.BoolValue(params.IsTotp) { + status, err := g.AuthenticatorProvider.Validate(ctx, params.Otp, user.ID) + if err != nil { + log.Debug().Err(err).Msg("Failed to validate passcode") + return nil, fmt.Errorf("error while validating passcode") + } + if !status { + log.Debug().Msg("Failed to verify otp request: Incorrect value") + log.Info().Msg("Checking if otp is recovery code") + // Check if otp is recovery code + isValidRecoveryCode, err := g.AuthenticatorProvider.ValidateRecoveryCode(ctx, params.Otp, user.ID) + if err != nil { + log.Debug().Err(err).Msg("Failed to validate recovery code") + return nil, fmt.Errorf("error while validating recovery code") + } + if !isValidRecoveryCode { + log.Debug().Msg("Failed to verify otp request: Incorrect value") + return nil, fmt.Errorf(`invalid otp`) + } + } + } else { + var otp *schemas.OTP + if isEmailVerification { + otp, err = g.StorageProvider.GetOTPByEmail(ctx, refs.StringValue(params.Email)) + if err != nil { + log.Debug().Err(err).Msg("Failed to get otp request for email") + } + } else { + otp, err = g.StorageProvider.GetOTPByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber)) + if err != nil { + log.Debug().Err(err).Msg("Failed to get otp request for phone number") + } + } + if otp == nil && err != nil { + log.Debug().Msg("OTP not found") + return nil, fmt.Errorf(`OTP not found`) + } + if params.Otp != otp.Otp { + log.Debug().Msg("Failed to verify otp request: OTP mismatch") + return nil, fmt.Errorf(`invalid otp`) + } + expiresIn := otp.ExpiresAt - time.Now().Unix() + if expiresIn < 0 { + log.Debug().Msg("OTP expired") + return nil, fmt.Errorf("otp expired") + } + if err := g.StorageProvider.DeleteOTP(gc, otp); err != nil { + log.Debug().Err(err).Msg("Failed to delete otp") + } + } + + if _, err := g.MemoryStoreProvider.GetMfaSession(user.ID, mfaSession); err != nil { + log.Debug().Err(err).Msg("Failed to get mfa session") + return nil, fmt.Errorf(`invalid session: %s`, err.Error()) + } + + isSignUp := false + if user.EmailVerifiedAt == nil && isEmailVerification { + isSignUp = true + now := time.Now().Unix() + user.EmailVerifiedAt = &now + } + if user.PhoneNumberVerifiedAt == nil && isMobileVerification { + isSignUp = true + now := time.Now().Unix() + user.PhoneNumberVerifiedAt = &now + } + if isSignUp { + user, err = g.StorageProvider.UpdateUser(ctx, user) + if err != nil { + log.Debug().Err(err).Msg("Failed to update user") + return nil, err + } + } + loginMethod := constants.AuthRecipeMethodBasicAuth + if isMobileVerification { + loginMethod = constants.AuthRecipeMethodMobileOTP + } + roles := strings.Split(user.Roles, ",") + scope := []string{"openid", "email", "profile"} + code := "" + codeChallenge := "" + nonce := "" + if params.State != nil { + // Get state from store + authorizeState, _ := g.MemoryStoreProvider.GetState(refs.StringValue(params.State)) + if authorizeState != "" { + authorizeStateSplit := strings.Split(authorizeState, "@@") + if len(authorizeStateSplit) > 1 { + code = authorizeStateSplit[0] + codeChallenge = authorizeStateSplit[1] + } else { + nonce = authorizeState + } + go g.MemoryStoreProvider.RemoveState(refs.StringValue(params.State)) + } + } + if nonce == "" { + nonce = uuid.New().String() + } + hostname := parsers.GetHost(gc) + // user, roles, scope, loginMethod, nonce, code + authToken, err := g.TokenProvider.CreateAuthToken(gc, &token.AuthTokenConfig{ + User: user, + Roles: roles, + Scope: scope, + LoginMethod: loginMethod, + Nonce: nonce, + Code: code, + HostName: hostname, + }) + if err != nil { + log.Debug().Err(err).Msg("Failed to create auth token") + return nil, err + } + + // Code challenge could be optional if PKCE flow is not used + if code != "" { + if err := g.MemoryStoreProvider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { + log.Debug().Err(err).Msg("Failed to set state") + return nil, err + } + } + + go func() { + if isSignUp { + g.EventsProvider.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user) + // User is also logged in with signup + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) + } else { + g.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) + } + + if err := g.StorageProvider.AddSession(ctx, &schemas.Session{ + UserID: user.ID, + UserAgent: utils.GetUserAgent(gc.Request), + IP: utils.GetIP(gc.Request), + }); err != nil { + log.Debug().Err(err).Msg("Failed to add session") + } + }() + + authTokenExpiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() + if authTokenExpiresIn <= 0 { + authTokenExpiresIn = 1 + } + + res := &model.AuthResponse{ + Message: `OTP verified successfully.`, + AccessToken: &authToken.AccessToken.Token, + IDToken: &authToken.IDToken.Token, + ExpiresIn: &authTokenExpiresIn, + User: user.AsAPIUser(), + } + + sessionKey := loginMethod + ":" + user.ID + cookie.SetSession(gc, authToken.FingerPrintHash, g.Config.AppCookieSecure) + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) + + if authToken.RefreshToken != nil { + res.RefreshToken = &authToken.RefreshToken.Token + g.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) + } + return res, nil +} diff --git a/internal/graphql/webhook.go b/internal/graphql/webhook.go new file mode 100644 index 000000000..b3cc65017 --- /dev/null +++ b/internal/graphql/webhook.go @@ -0,0 +1,31 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// Webhook is the method to get webhook details +// Permission: authorizer:admin +func (g *graphqlProvider) Webhook(ctx context.Context, params *model.WebhookRequest) (*model.Webhook, error) { + log := g.Log.With().Str("func", "Webhook").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + webhook, err := g.StorageProvider.GetWebhookByID(ctx, params.ID) + if err != nil { + log.Debug().Err(err).Msg("failed GetWebhookByID") + return nil, err + } + return webhook.AsAPIWebhook(), nil +} diff --git a/internal/graphql/webhook_logs.go b/internal/graphql/webhook_logs.go new file mode 100644 index 000000000..d1dce5370 --- /dev/null +++ b/internal/graphql/webhook_logs.go @@ -0,0 +1,51 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// WebhookLogs is the method to get webhook logs +// Permission: authorizer:admin +func (g *graphqlProvider) WebhookLogs(ctx context.Context, params *model.ListWebhookLogRequest) (*model.WebhookLogs, error) { + log := g.Log.With().Str("func", "WebhookLogs").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + var pagination *model.Pagination + var webhookID string + + if params != nil { + pagination = utils.GetPagination(&model.PaginatedRequest{ + Pagination: params.Pagination, + }) + webhookID = refs.StringValue(params.WebhookID) + } else { + pagination = utils.GetPagination(nil) + webhookID = "" + } + webhookLogs, pagination, err := g.StorageProvider.ListWebhookLogs(ctx, pagination, webhookID) + if err != nil { + log.Debug().Err(err).Msg("failed ListWebhookLogs") + return nil, err + } + resItems := make([]*model.WebhookLog, len(webhookLogs)) + for i, webhookLog := range webhookLogs { + resItems[i] = webhookLog.AsAPIWebhookLog() + } + return &model.WebhookLogs{ + Pagination: pagination, + WebhookLogs: resItems, + }, nil +} diff --git a/internal/graphql/webhooks.go b/internal/graphql/webhooks.go new file mode 100644 index 000000000..1799adf79 --- /dev/null +++ b/internal/graphql/webhooks.go @@ -0,0 +1,39 @@ +package graphql + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/utils" +) + +// Webhooks is the method to list webhooks +// Permission: authorizer:admin +func (g *graphqlProvider) Webhooks(ctx context.Context, params *model.PaginatedRequest) (*model.Webhooks, error) { + log := g.Log.With().Str("func", "Webhooks").Logger() + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + log.Debug().Err(err).Msg("Failed to get GinContext") + return nil, err + } + if !g.TokenProvider.IsSuperAdmin(gc) { + log.Debug().Msg("Not logged in as super admin") + return nil, fmt.Errorf("unauthorized") + } + + pagination := utils.GetPagination(params) + webhooks, pagination, err := g.StorageProvider.ListWebhook(ctx, pagination) + if err != nil { + log.Debug().Err(err).Msg("failed ListWebhook") + return nil, err + } + res := make([]*model.Webhook, len(webhooks)) + for i, webhook := range webhooks { + res[i] = webhook.AsAPIWebhook() + } + return &model.Webhooks{ + Pagination: pagination, + Webhooks: res, + }, nil +} diff --git a/server/handlers/app.go b/internal/http_handlers/app.go similarity index 57% rename from server/handlers/app.go rename to internal/http_handlers/app.go index 9b30977b8..4362e0fc7 100644 --- a/server/handlers/app.go +++ b/internal/http_handlers/app.go @@ -1,16 +1,13 @@ -package handlers +package http_handlers import ( "net/http" "strings" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/validators" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/validators" ) // State is the struct that holds authorizer url and redirect url @@ -21,11 +18,12 @@ type State struct { } // AppHandler is the handler for the /app route -func AppHandler() gin.HandlerFunc { +func (h *httpProvider) AppHandler() gin.HandlerFunc { + log := h.Log.With().Str("func", "AppHandler").Logger() return func(c *gin.Context) { hostname := parsers.GetHost(c) - if isLoginPageDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableLoginPage); err != nil || isLoginPageDisabled { - log.Debug("Login page is disabled") + if !h.Config.EnableLoginPage { + log.Debug().Msg("Login page is disabled") c.JSON(400, gin.H{"error": "login page is not enabled"}) return } @@ -45,8 +43,8 @@ func AppHandler() gin.HandlerFunc { redirectURI = hostname + "/app" } else { // validate redirect url with allowed origins - if !validators.IsValidOrigin(redirectURI) { - log.Debug("Invalid redirect_uri") + if !validators.IsValidOrigin(redirectURI, h.Config.AllowedOrigins) { + log.Debug().Msg("Invalid redirect url") c.JSON(400, gin.H{"error": "invalid redirect url"}) return } @@ -56,22 +54,12 @@ func AppHandler() gin.HandlerFunc { if pusher := c.Writer.Pusher(); pusher != nil { // use pusher.Push() to do server push if err := pusher.Push("/app/build/bundle.js", nil); err != nil { - log.Debug("Failed to push file path: ", err) + log.Debug().Err(err).Msg("Failed to push bundle.js") } } - orgName, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName) - if err != nil { - log.Debug("Failed to get organization name") - c.JSON(400, gin.H{"error": "failed to get organization name"}) - return - } - orgLogo, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo) - if err != nil { - log.Debug("Failed to get organization logo") - c.JSON(400, gin.H{"error": "failed to get organization logo"}) - return - } + orgName := h.Config.OrganizationName + orgLogo := h.Config.OrganizationLogo c.HTML(http.StatusOK, "app.tmpl", gin.H{ "data": map[string]interface{}{ "authorizerURL": hostname, diff --git a/server/handlers/authorize.go b/internal/http_handlers/authorize.go similarity index 73% rename from server/handlers/authorize.go rename to internal/http_handlers/authorize.go index d9c368656..1e26635e5 100644 --- a/server/handlers/authorize.go +++ b/internal/http_handlers/authorize.go @@ -1,4 +1,4 @@ -package handlers +package http_handlers /** LOGIC TO REMEMBER THE AUTHORIZE FLOW @@ -39,13 +39,11 @@ import ( "github.com/gin-gonic/gin" "github.com/google/uuid" - log "github.com/sirupsen/logrus" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/token" ) // Check the flow for generating and verifying codes: https://developer.okta.com/blog/2019/08/22/okta-authjs-pkce#:~:text=PKCE%20works%20by%20having%20the,is%20called%20the%20Code%20Challenge. @@ -66,7 +64,8 @@ const ( // state[recommended] = to prevent CSRF attack (for authorizer its compulsory) // code_challenge = to prevent CSRF attack // code_challenge_method = to prevent CSRF attack [only sh256 is supported] -func AuthorizeHandler() gin.HandlerFunc { +func (h *httpProvider) AuthorizeHandler() gin.HandlerFunc { + log := h.Log.With().Str("func", "AuthorizeHandler").Logger() return func(gc *gin.Context) { redirectURI := strings.TrimSpace(gc.Query("redirect_uri")) responseType := strings.TrimSpace(gc.Query("response_type")) @@ -86,11 +85,7 @@ func AuthorizeHandler() gin.HandlerFunc { } if responseMode == "" { - if val, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultAuthorizeResponseMode); err == nil { - responseMode = val - } else { - responseMode = constants.ResponseModeQuery - } + responseMode = h.Config.DefaultAuthorizeResponseMode } if redirectURI == "" { @@ -98,15 +93,11 @@ func AuthorizeHandler() gin.HandlerFunc { } if responseType == "" { - if val, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultAuthorizeResponseType); err == nil { - responseType = val - } else { - responseType = constants.ResponseTypeToken - } + responseType = h.Config.DefaultAuthorizeResponseType } - if err := validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge); err != nil { - log.Debug("invalid authorization request: ", err) + if err := h.validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge); err != nil { + log.Debug().Err(err).Msg("Invalid request") gc.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } @@ -116,23 +107,24 @@ func AuthorizeHandler() gin.HandlerFunc { nonce = uuid.New().String() } - log := log.WithFields(log.Fields{ - "response_mode": responseMode, - "response_type": responseType, - }) + log = log.With().Str("response_type", responseType).Str("response_mode", responseMode).Str("state", state).Str("code_challenge", codeChallenge).Str("scope", scopeString).Str("client_id", clientID).Str("nonce", nonce).Logger() // TODO add state with timeout // used for response mode query or fragment authState := "state=" + state + "&scope=" + scopeString + "&redirect_uri=" + redirectURI if responseType == constants.ResponseTypeCode { authState += "&code=" + code - if err := memorystore.Provider.SetState(state, code+"@@"+codeChallenge); err != nil { - log.Debug("Error setting temp code", err) + if err := h.MemoryStoreProvider.SetState(state, code+"@@"+codeChallenge); err != nil { + log.Debug().Err(err).Msg("Error setting temp code") + gc.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"}) + return } } else { authState += "&nonce=" + nonce - if err := memorystore.Provider.SetState(state, nonce); err != nil { - log.Debug("Error setting temp code", err) + if err := h.MemoryStoreProvider.SetState(state, nonce); err != nil { + log.Debug().Err(err).Msg("Error setting temp nonce") + gc.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"}) + return } } @@ -168,23 +160,23 @@ func AuthorizeHandler() gin.HandlerFunc { } sessionToken, err := cookie.GetSession(gc) if err != nil { - log.Debug("GetSession failed: ", err) + log.Debug().Err(err).Msg("Error getting session token") handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK) return } // get session from cookie - claims, err := token.ValidateBrowserSession(gc, sessionToken) + claims, err := h.TokenProvider.ValidateBrowserSession(gc, sessionToken) if err != nil { - log.Debug("ValidateBrowserSession failed: ", err) + log.Debug().Err(err).Msg("Error validating session token") handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK) return } userID := claims.Subject - user, err := db.Provider.GetUserByID(gc, userID) + user, err := h.StorageProvider.GetUserByID(gc, userID) if err != nil { - log.Debug("GetUserByID failed: ", err) + log.Debug().Err(err).Msg("Error getting user") handleResponse(gc, responseMode, authURL, redirectURI, map[string]interface{}{ "type": "authorization_response", "response": map[string]interface{}{ @@ -201,11 +193,17 @@ func AuthorizeHandler() gin.HandlerFunc { } // rollover the session for security - go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce) + go h.MemoryStoreProvider.DeleteUserSession(sessionKey, claims.Nonce) if responseType == constants.ResponseTypeCode { - newSessionTokenData, newSessionToken, newSessionExpiresAt, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod) + newSessionTokenData, newSessionToken, newSessionExpiresAt, err := h.TokenProvider.CreateSessionToken(&token.AuthTokenConfig{ + User: user, + Nonce: nonce, + Roles: claims.Roles, + Scope: scope, + LoginMethod: claims.LoginMethod, + }) if err != nil { - log.Debug("CreateSessionToken failed: ", err) + log.Debug().Err(err).Msg("Error creating session token") handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK) return } @@ -218,19 +216,19 @@ func AuthorizeHandler() gin.HandlerFunc { // } // TODO: add state with timeout - if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+newSessionToken); err != nil { - log.Debug("SetState failed: ", err) + if err := h.MemoryStoreProvider.SetState(code, codeChallenge+"@@"+newSessionToken); err != nil { + log.Debug().Err(err).Msg("Error setting temp code") handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK) return } - if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken, newSessionExpiresAt); err != nil { - log.Debug("SetUserSession failed: ", err) + if err := h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken, newSessionExpiresAt); err != nil { + log.Debug().Err(err).Msg("Error setting session token") handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK) return } - cookie.SetSession(gc, newSessionToken) + cookie.SetSession(gc, newSessionToken, h.Config.AppCookieSecure) // in case, response type is code and user is already logged in send the code and state // and cookie session will already be rolled over and set @@ -272,27 +270,35 @@ func AuthorizeHandler() gin.HandlerFunc { } if responseType == constants.ResponseTypeToken || responseType == constants.ResponseTypeIDToken { + hostname := parsers.GetHost(gc) // rollover the session for security - authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod, nonce, "") + authToken, err := h.TokenProvider.CreateAuthToken(gc, &token.AuthTokenConfig{ + User: user, + Nonce: nonce, + Roles: claims.Roles, + Scope: scope, + LoginMethod: claims.LoginMethod, + HostName: hostname, + }) if err != nil { - log.Debug("CreateAuthToken failed: ", err) + log.Debug().Err(err).Msg("Error creating auth token") handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK) return } - if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+nonce, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt); err != nil { - log.Debug("SetUserSession failed: ", err) + if err := h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+nonce, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt); err != nil { + log.Debug().Err(err).Msg("Error setting session token") handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK) return } - if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt); err != nil { - log.Debug("SetUserSession failed: ", err) + if err := h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt); err != nil { + log.Debug().Err(err).Msg("Error setting access token") handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK) return } - cookie.SetSession(gc, authToken.FingerPrintHash) + cookie.SetSession(gc, authToken.FingerPrintHash, h.Config.AppCookieSecure) // used of query mode params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(authToken.IDToken.ExpiresAt, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token @@ -314,7 +320,11 @@ func AuthorizeHandler() gin.HandlerFunc { if authToken.RefreshToken != nil { res["refresh_token"] = authToken.RefreshToken.Token params += "&refresh_token=" + authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) + if err := h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt); err != nil { + log.Debug().Err(err).Msg("Error setting refresh token") + handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK) + return + } } if responseMode == constants.ResponseModeQuery { @@ -342,7 +352,7 @@ func AuthorizeHandler() gin.HandlerFunc { } } -func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge string) error { +func (h *httpProvider) validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge string) error { if strings.TrimSpace(state) == "" { return fmt.Errorf("invalid state. state is required to prevent csrf attack") } @@ -354,7 +364,7 @@ func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeC return fmt.Errorf("invalid response mode %s. 'query', 'fragment', 'form_post' and 'web_message' are valid response_mode", responseMode) } - if client, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); client != clientID || err != nil { + if h.Config.ClientID != clientID { return fmt.Errorf("invalid client_id %s", clientID) } diff --git a/server/middlewares/client_check.go b/internal/http_handlers/client_check.go similarity index 51% rename from server/middlewares/client_check.go rename to internal/http_handlers/client_check.go index 269a07570..2efd50ed9 100644 --- a/server/middlewares/client_check.go +++ b/internal/http_handlers/client_check.go @@ -1,22 +1,19 @@ -package middlewares +package http_handlers import ( "net/http" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" ) // ClientCheckMiddleware is a middleware to verify the client ID // Note: client ID is passed in the header -func ClientCheckMiddleware() gin.HandlerFunc { +func (h *httpProvider) ClientCheckMiddleware() gin.HandlerFunc { + log := h.Log.With().Str("func", "ClientCheckMiddleware").Logger() return func(c *gin.Context) { clientID := c.Request.Header.Get("X-Authorizer-Client-ID") - if client, _ := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); clientID != "" && client != "" && client != clientID { - log.Debug("Client ID is invalid: ", clientID) + if clientID != "" && clientID != h.Config.ClientID { + log.Debug().Str("client_id", clientID).Msg("Client ID is invalid") c.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_client_id", "error_description": "The client id is invalid", diff --git a/internal/http_handlers/context.go b/internal/http_handlers/context.go new file mode 100644 index 000000000..3c4ca2635 --- /dev/null +++ b/internal/http_handlers/context.go @@ -0,0 +1,21 @@ +package http_handlers + +import ( + "context" + + "github.com/gin-gonic/gin" +) + +// Define a custom type for context key +type contextKey string + +const ginContextKey contextKey = "GinContextKey" + +// ContextMiddleware is a middleware to add gin context in context +func (h *httpProvider) ContextMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + ctx := context.WithValue(c.Request.Context(), ginContextKey, c) + c.Request = c.Request.WithContext(ctx) + c.Next() + } +} diff --git a/server/middlewares/cors.go b/internal/http_handlers/cors.go similarity index 78% rename from server/middlewares/cors.go rename to internal/http_handlers/cors.go index 514bf2aa5..00ba280a3 100644 --- a/server/middlewares/cors.go +++ b/internal/http_handlers/cors.go @@ -1,15 +1,16 @@ -package middlewares +package http_handlers import ( - "github.com/authorizerdev/authorizer/server/validators" "github.com/gin-gonic/gin" + + "github.com/authorizerdev/authorizer/internal/validators" ) // CORSMiddleware is a middleware to add cors headers -func CORSMiddleware() gin.HandlerFunc { +func (h *httpProvider) CORSMiddleware() gin.HandlerFunc { return func(c *gin.Context) { origin := c.Request.Header.Get("Origin") - if validators.IsValidOrigin(origin) { + if validators.IsValidOrigin(origin, h.Config.AllowedOrigins) { c.Writer.Header().Set("Access-Control-Allow-Origin", origin) } diff --git a/internal/http_handlers/dashboard.go b/internal/http_handlers/dashboard.go new file mode 100644 index 000000000..b05cecb5d --- /dev/null +++ b/internal/http_handlers/dashboard.go @@ -0,0 +1,19 @@ +package http_handlers + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +// DashboardHandler is the handler for the /dashboard route +func (h *httpProvider) DashboardHandler() gin.HandlerFunc { + return func(c *gin.Context) { + + c.HTML(http.StatusOK, "dashboard.tmpl", gin.H{ + "data": map[string]interface{}{ + "isOnboardingCompleted": true, + }, + }) + } +} diff --git a/internal/http_handlers/graphql.go b/internal/http_handlers/graphql.go new file mode 100644 index 000000000..152388b4c --- /dev/null +++ b/internal/http_handlers/graphql.go @@ -0,0 +1,82 @@ +package http_handlers + +import ( + "context" + "net/http" + + gql "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/handler" + "github.com/99designs/gqlgen/graphql/handler/extension" + "github.com/99designs/gqlgen/graphql/handler/lru" + "github.com/99designs/gqlgen/graphql/handler/transport" + "github.com/gin-gonic/gin" + "github.com/vektah/gqlparser/v2/ast" + + "github.com/authorizerdev/authorizer/internal/graph" + "github.com/authorizerdev/authorizer/internal/graph/generated" + "github.com/authorizerdev/authorizer/internal/graphql" +) + +func (h *httpProvider) gqlLoggingMiddleware() gql.FieldMiddleware { + return func(ctx context.Context, next gql.Resolver) (res interface{}, err error) { + // Get details of the current operation + oc := gql.GetOperationContext(ctx) + field := gql.GetFieldContext(ctx) + + // Log operation details + h.Dependencies.Log.Info(). + Str("operation", oc.OperationName). + Str("query", field.Field.Name). + // Interface("arguments", field.Args). // Enable only for debugging purpose else sensitive data will be logged + Msg("GraphQL field resolved") + + // Call the next resolver + return next(ctx) + } +} + +// GraphqlHandler is the main handler that handels all the graphql requests +func (h *httpProvider) GraphqlHandler() gin.HandlerFunc { + gqlProvider, err := graphql.New(h.Config, &graphql.Dependencies{ + Log: h.Log, + AuthenticatorProvider: h.AuthenticatorProvider, + EmailProvider: h.EmailProvider, + EventsProvider: h.EventsProvider, + MemoryStoreProvider: h.MemoryStoreProvider, + SMSProvider: h.SMSProvider, + StorageProvider: h.StorageProvider, + TokenProvider: h.TokenProvider, + }) + if err != nil { + h.Log.Error().Err(err).Msg("Failed to create graphql provider") + return nil + } + + // NewExecutableSchema and Config are in the generated.go file + // Resolver is in the resolver.go file + srv := handler.New(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{ + GraphQLProvider: gqlProvider, + }})) + + srv.AddTransport(transport.Options{}) + srv.AddTransport(transport.GET{}) + srv.AddTransport(transport.POST{}) + + srv.SetQueryCache(lru.New[*ast.QueryDocument](1000)) + srv.AroundFields(h.gqlLoggingMiddleware()) + srv.Use(extension.Introspection{}) + srv.Use(extension.AutomaticPersistedQuery{ + Cache: lru.New[string](100), + }) + + return func(c *gin.Context) { + // Create a custom handler that ensures gin context is available + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Ensure the gin context is available in the request context + ctx := context.WithValue(r.Context(), "GinContextKey", c) + r = r.WithContext(ctx) + srv.ServeHTTP(w, r) + }) + handler.ServeHTTP(c.Writer, c.Request) + } +} diff --git a/server/handlers/health.go b/internal/http_handlers/health.go similarity index 66% rename from server/handlers/health.go rename to internal/http_handlers/health.go index 2ee314294..63d8a668f 100644 --- a/server/handlers/health.go +++ b/internal/http_handlers/health.go @@ -1,4 +1,4 @@ -package handlers +package http_handlers import ( "net/http" @@ -8,7 +8,8 @@ import ( // HealthHandler is the handler for /health route. // It states if server is in healthy state or not -func HealthHandler() gin.HandlerFunc { +func (h *httpProvider) HealthHandler() gin.HandlerFunc { + h.Log.Info().Msg("Health check") return func(c *gin.Context) { c.String(http.StatusOK, "OK") } diff --git a/internal/http_handlers/jwks.go b/internal/http_handlers/jwks.go new file mode 100644 index 000000000..a82468b43 --- /dev/null +++ b/internal/http_handlers/jwks.go @@ -0,0 +1,81 @@ +package http_handlers + +import ( + "encoding/json" + + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/gin-gonic/gin" +) + +// generateJWKBasedOnEnv generates JWK based on root args config +// make sure clientID, jwtType, jwtSecret / public & private key pair is set +// this is called while initializing app / when env is updated +func (h *httpProvider) generateJWKBasedOnEnv() (string, error) { + jwk := "" + algo := h.JWTType + clientID := h.ClientID + jwtSecret := h.JWTSecret + jwtPublicKey := h.JWTPublicKey + var err error + // check if jwt secret is provided + if crypto.IsHMACA(algo) { + jwk, err = crypto.GetPubJWK(algo, clientID, []byte(jwtSecret)) + if err != nil { + return "", err + } + } + + if crypto.IsRSA(algo) { + publicKeyInstance, err := crypto.ParseRsaPublicKeyFromPemStr(jwtPublicKey) + if err != nil { + return "", err + } + + jwk, err = crypto.GetPubJWK(algo, clientID, publicKeyInstance) + if err != nil { + return "", err + } + } + + if crypto.IsECDSA(algo) { + publicKeyInstance, err := crypto.ParseEcdsaPublicKeyFromPemStr(jwtPublicKey) + if err != nil { + return "", err + } + + jwk, err = crypto.GetPubJWK(algo, clientID, publicKeyInstance) + if err != nil { + return "", err + } + } + + return jwk, nil +} + +func (h *httpProvider) JWKsHandler() gin.HandlerFunc { + log := h.Log.With().Str("func", "JWKsHandler").Logger() + return func(c *gin.Context) { + var data map[string]string + jwk, err := h.generateJWKBasedOnEnv() + if err != nil { + log.Debug().Err(err).Msg("Error generating JWK") + c.JSON(500, gin.H{ + "error": err.Error(), + }) + return + } + err = json.Unmarshal([]byte(jwk), &data) + if err != nil { + log.Debug().Err(err).Msg("Error unmarshalling JWK") + c.JSON(500, gin.H{ + "error": err.Error(), + }) + return + } + c.JSON(200, gin.H{ + "keys": []map[string]string{ + data, + }, + }) + } +} diff --git a/internal/http_handlers/logger.go b/internal/http_handlers/logger.go new file mode 100644 index 000000000..eaad9d3d1 --- /dev/null +++ b/internal/http_handlers/logger.go @@ -0,0 +1,27 @@ +package http_handlers + +import ( + "time" + + "github.com/gin-gonic/gin" +) + +// LoggerMiddleware adds logging to Gin using rs/zerolog. +func (h *httpProvider) LoggerMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + start := time.Now() + + // Process the request + c.Next() + + // Log the request and response details + h.Dependencies.Log.Info(). + Str("method", c.Request.Method). + Str("path", c.Request.URL.Path). + Int("status", c.Writer.Status()). + Int("size", c.Writer.Size()). + Str("client_ip", c.ClientIP()). + Dur("latency", time.Since(start)). + Msg("HTTP request") + } +} diff --git a/server/handlers/logout.go b/internal/http_handlers/logout.go similarity index 60% rename from server/handlers/logout.go rename to internal/http_handlers/logout.go index fbac22d49..364702f84 100644 --- a/server/handlers/logout.go +++ b/internal/http_handlers/logout.go @@ -1,4 +1,4 @@ -package handlers +package http_handlers import ( "encoding/json" @@ -6,31 +6,30 @@ import ( "strings" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/token" ) // Handler to logout user -func LogoutHandler() gin.HandlerFunc { +func (h *httpProvider) LogoutHandler() gin.HandlerFunc { + log := h.Log.With().Str("func", "LogoutHandler").Logger() return func(gc *gin.Context) { redirectURL := strings.TrimSpace(gc.Query("redirect_uri")) // get fingerprint hash fingerprintHash, err := cookie.GetSession(gc) if err != nil { - log.Debug("Failed to get session: ", err) + log.Debug().Err(err).Msg("failed GetSession") gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) return } - decryptedFingerPrint, err := crypto.DecryptAES(fingerprintHash) + decryptedFingerPrint, err := crypto.DecryptAES(h.ClientSecret, fingerprintHash) if err != nil { - log.Debug("Failed to decrypt fingerprint: ", err) + log.Debug().Err(err).Msg("failed to decrypt fingerprint") gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) @@ -40,7 +39,7 @@ func LogoutHandler() gin.HandlerFunc { var sessionData token.SessionData err = json.Unmarshal([]byte(decryptedFingerPrint), &sessionData) if err != nil { - log.Debug("Failed to decrypt fingerprint: ", err) + log.Debug().Err(err).Msg("failed to unmarshal session data") gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) @@ -54,8 +53,8 @@ func LogoutHandler() gin.HandlerFunc { sessionToken = loginMethod + ":" + userID } - memorystore.Provider.DeleteUserSession(sessionToken, sessionData.Nonce) - cookie.DeleteSession(gc) + h.MemoryStoreProvider.DeleteUserSession(sessionToken, sessionData.Nonce) + cookie.DeleteSession(gc, h.Config.AppCookieSecure) if redirectURL != "" { gc.Redirect(http.StatusFound, redirectURL) diff --git a/server/handlers/oauth_callback.go b/internal/http_handlers/oauth_callback.go similarity index 59% rename from server/handlers/oauth_callback.go rename to internal/http_handlers/oauth_callback.go index f3610f47c..c04d0ec15 100644 --- a/server/handlers/oauth_callback.go +++ b/internal/http_handlers/oauth_callback.go @@ -1,7 +1,6 @@ -package handlers +package http_handlers import ( - "context" "encoding/base64" "encoding/json" "fmt" @@ -16,20 +15,16 @@ import ( "github.com/gin-gonic/gin" "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/oauth" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" ) -// OAuthCallbackHandler handles the OAuth callback for various oauth providers +// AppleUserInfo is the struct for apple user info type AppleUserInfo struct { Email string `json:"email"` Name struct { @@ -38,13 +33,15 @@ type AppleUserInfo struct { } `json:"name"` } -func OAuthCallbackHandler() gin.HandlerFunc { +// OAuthCallbackHandler handles the OAuth callback for various oauth providers +func (h *httpProvider) OAuthCallbackHandler() gin.HandlerFunc { + log := h.Log.With().Str("func", "OAuthCallbackHandler").Logger() return func(ctx *gin.Context) { provider := ctx.Param("oauth_provider") state := ctx.Request.FormValue("state") - sessionState, err := memorystore.Provider.GetState(state) + sessionState, err := h.MemoryStoreProvider.GetState(state) if sessionState == "" || err != nil { - log.Debug("Invalid oauth state: ", state) + log.Debug().Err(err).Msg("Failed to get state from store") ctx.JSON(400, gin.H{"error": "invalid oauth state"}) return } @@ -52,12 +49,12 @@ func OAuthCallbackHandler() gin.HandlerFunc { sessionSplit := strings.Split(state, "___") if len(sessionSplit) < 3 { - log.Debug("Unable to get redirect url from state: ", state) + log.Debug().Err(err).Msg("Invalid state") ctx.JSON(400, gin.H{"error": "invalid redirect url"}) return } // remove state from store - go memorystore.Provider.RemoveState(state) + go h.MemoryStoreProvider.RemoveState(state) stateValue := sessionSplit[0] redirectURL := sessionSplit[1] inputRoles := strings.Split(sessionSplit[2], ",") @@ -71,68 +68,68 @@ func OAuthCallbackHandler() gin.HandlerFunc { scopes = strings.Split(scopeString, " ") } } - var user *models.User + var user *schemas.User oauthCode := ctx.Request.FormValue("code") if oauthCode == "" { - log.Debug("Invalid oauth code: ", oauthCode) + log.Debug().Err(err).Msg("Invalid oauth code") ctx.JSON(400, gin.H{"error": "invalid oauth code"}) return } switch provider { case constants.AuthRecipeMethodGoogle: - user, err = processGoogleUserInfo(ctx, oauthCode) + user, err = h.processGoogleUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodGithub: - user, err = processGithubUserInfo(ctx, oauthCode) + user, err = h.processGithubUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodFacebook: - user, err = processFacebookUserInfo(ctx, oauthCode) + user, err = h.processFacebookUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodLinkedIn: - user, err = processLinkedInUserInfo(ctx, oauthCode) + user, err = h.processLinkedInUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodApple: user_ := AppleUserInfo{} userRaw := ctx.Request.FormValue("user") err = json.Unmarshal([]byte(userRaw), &user_) - user, err = processAppleUserInfo(ctx, oauthCode, &user_) + if err != nil { + log.Debug().Err(err).Msg("Failed to unmarshal apple user info") + ctx.JSON(400, gin.H{"error": "invalid apple user info"}) + return + } + user, err = h.processAppleUserInfo(ctx, oauthCode, &user_) case constants.AuthRecipeMethodDiscord: - user, err = processDiscordUserInfo(ctx, oauthCode) + user, err = h.processDiscordUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodTwitter: - user, err = processTwitterUserInfo(ctx, oauthCode, sessionState) + user, err = h.processTwitterUserInfo(ctx, oauthCode, sessionState) case constants.AuthRecipeMethodMicrosoft: - user, err = processMicrosoftUserInfo(ctx, oauthCode) + user, err = h.processMicrosoftUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodTwitch: - user, err = processTwitchUserInfo(ctx, oauthCode) + user, err = h.processTwitchUserInfo(ctx, oauthCode) case constants.AuthRecipeMethodRoblox: - user, err = processRobloxUserInfo(ctx, oauthCode, sessionState) + user, err = h.processRobloxUserInfo(ctx, oauthCode, sessionState) default: - log.Info("Invalid oauth provider") + log.Debug().Err(err).Msg("Invalid oauth provider") err = fmt.Errorf(`invalid oauth provider`) } if err != nil { - log.Debug("Failed to process user info: ", err) + log.Debug().Err(err).Msg("Failed to process user info") ctx.JSON(400, gin.H{"error": err.Error()}) return } if user == nil { - log.Debug("User is nil") + log.Debug().Err(err).Msg("Failed to get user") ctx.JSON( 500, gin.H{"error": "Something Went Wrong. Please Try Again."}, ) return } - existingUser, err := db.Provider.GetUserByEmail(ctx, refs.StringValue(user.Email)) - log := log.WithField("user", user.Email) + existingUser, err := h.StorageProvider.GetUserByEmail(ctx, refs.StringValue(user.Email)) + log := log.With().Str("email", refs.StringValue(user.Email)).Logger() isSignUp := false if err != nil { - isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) - if err != nil { - log.Debug("Failed to get signup disabled env variable: ", err) - ctx.JSON(400, gin.H{"error": err.Error()}) - return - } - if isSignupDisabled { - log.Debug("Failed to signup as disabled") + isSignupEnabled := h.Config.EnableSignup + if !isSignupEnabled { + log.Debug().Err(err).Msg("Signup is disabled") ctx.JSON(400, gin.H{"error": "signup is disabled for this instance"}) return } @@ -141,21 +138,14 @@ func OAuthCallbackHandler() gin.HandlerFunc { // make sure inputRoles don't include protected roles hasProtectedRole := false for _, ir := range inputRoles { - protectedRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyProtectedRoles) - protectedRoles := []string{} - if err != nil { - log.Debug("Failed to get protected roles: ", err) - protectedRolesString = "" - } else { - protectedRoles = strings.Split(protectedRolesString, ",") - } + protectedRoles := h.Config.ProtectedRoles if utils.StringSliceContains(protectedRoles, ir) { hasProtectedRole = true } } if hasProtectedRole { - log.Debug("Signup is not allowed with protected roles:", inputRoles) + log.Debug().Err(err).Msg("Invalid role. User is using protected role") ctx.JSON(400, gin.H{"error": "invalid role"}) return } @@ -163,12 +153,17 @@ func OAuthCallbackHandler() gin.HandlerFunc { user.Roles = strings.Join(inputRoles, ",") now := time.Now().Unix() user.EmailVerifiedAt = &now - user, _ = db.Provider.AddUser(ctx, user) + user, err = h.StorageProvider.AddUser(ctx, user) + if err != nil { + log.Debug().Err(err).Msg("Failed to add user") + ctx.JSON(500, gin.H{"error": err.Error()}) + return + } isSignUp = true } else { user = existingUser if user.RevokedTimestamp != nil { - log.Debug("User access revoked at: ", user.RevokedTimestamp) + log.Debug().Msg("User access has been revoked") ctx.JSON(400, gin.H{"error": "user access has been revoked"}) return } @@ -204,21 +199,14 @@ func OAuthCallbackHandler() gin.HandlerFunc { // check if it contains protected unassigned role hasProtectedRole := false for _, ur := range unasignedRoles { - protectedRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyProtectedRoles) - protectedRoles := []string{} - if err != nil { - log.Debug("Failed to get protected roles: ", err) - protectedRolesString = "" - } else { - protectedRoles = strings.Split(protectedRolesString, ",") - } + protectedRoles := h.Config.ProtectedRoles if utils.StringSliceContains(protectedRoles, ur) { hasProtectedRole = true } } if hasProtectedRole { - log.Debug("Invalid role. User is using protected unassigned role") + log.Debug().Err(err).Msg("Invalid role. User is using protected role") ctx.JSON(400, gin.H{"error": "invalid role"}) return } else { @@ -228,9 +216,9 @@ func OAuthCallbackHandler() gin.HandlerFunc { user.Roles = existingUser.Roles } - user, err = db.Provider.UpdateUser(ctx, user) + user, err = h.StorageProvider.UpdateUser(ctx, user) if err != nil { - log.Debug("Failed to update user: ", err) + log.Debug().Err(err).Msg("Failed to update user") ctx.JSON(500, gin.H{"error": err.Error()}) return } @@ -244,7 +232,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { nonce := "" if stateValue != "" { // Get state from store - authorizeState, _ := memorystore.Provider.GetState(stateValue) + authorizeState, _ := h.MemoryStoreProvider.GetState(stateValue) if authorizeState != "" { authorizeStateSplit := strings.Split(authorizeState, "@@") if len(authorizeStateSplit) > 1 { @@ -253,22 +241,31 @@ func OAuthCallbackHandler() gin.HandlerFunc { } else { nonce = authorizeState } - go memorystore.Provider.RemoveState(stateValue) + go h.MemoryStoreProvider.RemoveState(stateValue) } } if nonce == "" { nonce = uuid.New().String() } - authToken, err := token.CreateAuthToken(ctx, user, inputRoles, scopes, provider, nonce, code) + hostname := parsers.GetHost(ctx) + // user, inputRoles, scopes, provider, nonce, code + authToken, err := h.TokenProvider.CreateAuthToken(ctx, &token.AuthTokenConfig{ + User: user, + Roles: inputRoles, + Scope: scopes, + LoginMethod: provider, + Nonce: nonce, + HostName: hostname, + }) if err != nil { - log.Debug("Failed to create auth token: ", err) + log.Debug().Err(err).Msg("Failed to create auth token") ctx.JSON(500, gin.H{"error": err.Error()}) } // Code challenge could be optional if PKCE flow is not used if code != "" { - if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { - log.Debug("SetState failed: ", err) + if err := h.MemoryStoreProvider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { + log.Debug().Err(err).Msg("Failed to set state") ctx.JSON(500, gin.H{"error": err.Error()}) } } @@ -286,28 +283,30 @@ func OAuthCallbackHandler() gin.HandlerFunc { } sessionKey := provider + ":" + user.ID - cookie.SetSession(ctx, 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, authToken.AccessToken.ExpiresAt) + cookie.SetSession(ctx, authToken.FingerPrintHash, h.Config.AppCookieSecure) + h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) + h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) if authToken.RefreshToken != nil { params += `&refresh_token=` + authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) + h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) } go func() { if isSignUp { - utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, provider, user) + h.EventsProvider.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, provider, user) // User is also logged in with signup - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, provider, user) + h.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, provider, user) } else { - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, provider, user) + h.EventsProvider.RegisterEvent(ctx, constants.UserLoginWebhookEvent, provider, user) } - db.Provider.AddSession(ctx, &models.Session{ + if err := h.StorageProvider.AddSession(ctx, &schemas.Session{ UserID: user.ID, UserAgent: utils.GetUserAgent(ctx.Request), IP: utils.GetIP(ctx.Request), - }) + }); err != nil { + log.Debug().Err(err).Msg("Failed to add session") + } }() if strings.Contains(redirectURL, "?") { redirectURL = redirectURL + "&" + params @@ -319,46 +318,63 @@ func OAuthCallbackHandler() gin.HandlerFunc { } } -func processGoogleUserInfo(ctx context.Context, code string) (*models.User, error) { - oauth2Token, err := oauth.OAuthProviders.GoogleConfig.Exchange(ctx, code) +func (h *httpProvider) processGoogleUserInfo(ctx *gin.Context, code string) (*schemas.User, error) { + log := h.Log.With().Str("func", "processGoogleUserInfo").Logger() + cfg, err := h.OAuthProvider.GetOAuthConfig(ctx, constants.AuthRecipeMethodGoogle) + if err != nil { + log.Debug().Err(err).Msg("Error getting oauth config") + return nil, fmt.Errorf("error getting oauth config: %s", err.Error()) + } + oauth2Token, err := cfg.Exchange(ctx, code) if err != nil { - log.Debug("Failed to exchange code for token: ", err) + log.Debug().Err(err).Msg("Failed to exchange code for token") return nil, fmt.Errorf("invalid google exchange code: %s", err.Error()) } - verifier := oauth.OIDCProviders.GoogleOIDC.Verifier(&oidc.Config{ClientID: oauth.OAuthProviders.GoogleConfig.ClientID}) + oidcProvider, err := oidc.NewProvider(ctx, "https://accounts.google.com") + verifier := oidcProvider.Verifier(&oidc.Config{ClientID: h.GoogleClientID}) + if err != nil { + return nil, fmt.Errorf("failed to create oidc provider: %s", err.Error()) + } // 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") + log.Debug().Err(err).Msg("Failed to extract ID Token from OAuth2 token") return nil, 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) + log.Debug().Err(err).Msg("Failed to verify ID Token") return nil, fmt.Errorf("unable to verify id_token: %s", err.Error()) } - user := &models.User{} + user := &schemas.User{} if err := idToken.Claims(&user); err != nil { - log.Debug("Failed to parse ID Token claims: ", err) + log.Debug().Err(err).Msg("Failed to parse ID Token claims") return nil, fmt.Errorf("unable to extract claims") } return user, nil } -func processGithubUserInfo(ctx context.Context, code string) (*models.User, error) { - oauth2Token, err := oauth.OAuthProviders.GithubConfig.Exchange(ctx, code) +func (h *httpProvider) processGithubUserInfo(ctx *gin.Context, code string) (*schemas.User, error) { + log := h.Log.With().Str("func", "processGithubUserInfo").Logger() + cfg, err := h.OAuthProvider.GetOAuthConfig(ctx, constants.AuthRecipeMethodGithub) + if err != nil { + log.Debug().Err(err).Msg("Error getting oauth config") + return nil, fmt.Errorf("error getting oauth config: %s", err.Error()) + } + + oauth2Token, err := cfg.Exchange(ctx, code) if err != nil { - log.Debug("Failed to exchange code for token: ", err) + log.Debug().Err(err).Msg("Failed to exchange code for token") return nil, fmt.Errorf("invalid github exchange code: %s", err.Error()) } client := http.Client{} req, err := http.NewRequest("GET", constants.GithubUserInfoURL, nil) if err != nil { - log.Debug("Failed to create github user info request: ", err) + log.Debug().Err(err).Msg("Failed to create github user info request") return nil, fmt.Errorf("error creating github user info request: %s", err.Error()) } req.Header.Set( @@ -367,18 +383,18 @@ func processGithubUserInfo(ctx context.Context, code string) (*models.User, erro response, err := client.Do(req) if err != nil { - log.Debug("Failed to request github user info: ", err) + log.Debug().Err(err).Msg("Failed to request github user info") return nil, err } defer response.Body.Close() body, err := io.ReadAll(response.Body) if err != nil { - log.Debug("Failed to read github user info response body: ", err) + log.Debug().Err(err).Msg("Failed to read github user info response body") return nil, fmt.Errorf("failed to read github response body: %s", err.Error()) } if response.StatusCode >= 400 { - log.Debug("Failed to request github user info: ", string(body)) + log.Debug().Err(err).Str("body", string(body)).Msg("Failed to request github user info") return nil, fmt.Errorf("failed to request github user info: %s", string(body)) } @@ -407,7 +423,7 @@ func processGithubUserInfo(ctx context.Context, code string) (*models.User, erro // fetch using /users/email endpoint req, err := http.NewRequest(http.MethodGet, constants.GithubUserEmails, nil) if err != nil { - log.Debug("Failed to create github emails request: ", err) + log.Debug().Err(err).Msg("Failed to create github emails request") return nil, fmt.Errorf("error creating github user info request: %s", err.Error()) } req.Header.Set( @@ -416,25 +432,25 @@ func processGithubUserInfo(ctx context.Context, code string) (*models.User, erro response, err := client.Do(req) if err != nil { - log.Debug("Failed to request github user email: ", err) + log.Debug().Err(err).Msg("Failed to request github user email") return nil, err } defer response.Body.Close() body, err := io.ReadAll(response.Body) if err != nil { - log.Debug("Failed to read github user email response body: ", err) + log.Debug().Err(err).Msg("Failed to read github user email response body") return nil, fmt.Errorf("failed to read github response body: %s", err.Error()) } if response.StatusCode >= 400 { - log.Debug("Failed to request github user email: ", string(body)) + log.Debug().Err(err).Str("body", string(body)).Msg("Failed to request github user email") return nil, fmt.Errorf("failed to request github user info: %s", string(body)) } emailData := []GithubUserEmails{} err = json.Unmarshal(body, &emailData) if err != nil { - log.Debug("Failed to parse github user email: ", err) + log.Debug().Err(err).Msg("Failed to parse github user email") return nil, fmt.Errorf("failed to parse github user email: %s", err.Error()) } @@ -446,7 +462,7 @@ func processGithubUserInfo(ctx context.Context, code string) (*models.User, erro } } - user := &models.User{ + user := &schemas.User{ GivenName: &firstName, FamilyName: &lastName, Picture: &picture, @@ -456,33 +472,39 @@ func processGithubUserInfo(ctx context.Context, code string) (*models.User, erro return user, nil } -func processFacebookUserInfo(ctx context.Context, code string) (*models.User, error) { - oauth2Token, err := oauth.OAuthProviders.FacebookConfig.Exchange(ctx, code) +func (h *httpProvider) processFacebookUserInfo(ctx *gin.Context, code string) (*schemas.User, error) { + log := h.Log.With().Str("func", "processFacebookUserInfo").Logger() + cfg, err := h.OAuthProvider.GetOAuthConfig(ctx, constants.AuthRecipeMethodFacebook) if err != nil { - log.Debug("Invalid facebook exchange code: ", err) + log.Debug().Err(err).Msg("Error getting oauth config") + return nil, fmt.Errorf("error getting oauth config: %s", err.Error()) + } + oauth2Token, err := cfg.Exchange(ctx, code) + if err != nil { + log.Debug().Err(err).Msg("Invalid facebook exchange code") return nil, fmt.Errorf("invalid facebook exchange code: %s", err.Error()) } client := http.Client{} req, err := http.NewRequest("GET", constants.FacebookUserInfoURL+oauth2Token.AccessToken, nil) if err != nil { - log.Debug("Error creating facebook user info request: ", err) + log.Debug().Err(err).Msg("Error creating facebook user info request") return nil, fmt.Errorf("error creating facebook user info request: %s", err.Error()) } response, err := client.Do(req) if err != nil { - log.Debug("Failed to process facebook user: ", err) + log.Debug().Err(err).Msg("Failed to process facebook user") return nil, err } defer response.Body.Close() body, err := io.ReadAll(response.Body) if err != nil { - log.Debug("Failed to read facebook response: ", err) + log.Debug().Err(err).Msg("Failed to read facebook response") return nil, fmt.Errorf("failed to read facebook response body: %s", err.Error()) } if response.StatusCode >= 400 { - log.Debug("Failed to request facebook user info: ", string(body)) + log.Debug().Err(err).Str("body", string(body)).Msg("Failed to request facebook user info") return nil, fmt.Errorf("failed to request facebook user info: %s", string(body)) } userRawData := make(map[string]interface{}) @@ -496,7 +518,7 @@ func processFacebookUserInfo(ctx context.Context, code string) (*models.User, er lastName := fmt.Sprintf("%v", userRawData["last_name"]) picture := fmt.Sprintf("%v", picDataObject["url"]) - user := &models.User{ + user := &schemas.User{ GivenName: &firstName, FamilyName: &lastName, Picture: &picture, @@ -506,17 +528,24 @@ func processFacebookUserInfo(ctx context.Context, code string) (*models.User, er return user, nil } -func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, error) { - oauth2Token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(ctx, code) +func (h *httpProvider) processLinkedInUserInfo(ctx *gin.Context, code string) (*schemas.User, error) { + log := h.Log.With().Str("func", "processLinkedInUserInfo").Logger() + cfg, err := h.OAuthProvider.GetOAuthConfig(ctx, constants.AuthRecipeMethodLinkedIn) + if err != nil { + log.Debug().Err(err).Msg("Error getting oauth config") + return nil, fmt.Errorf("error getting oauth config: %s", err.Error()) + } + + oauth2Token, err := cfg.Exchange(ctx, code) if err != nil { - log.Debug("Failed to exchange code for token: ", err) + log.Debug().Err(err).Msg("Failed to exchange code for token") return nil, fmt.Errorf("invalid linkedin exchange code: %s", err.Error()) } client := http.Client{} req, err := http.NewRequest("GET", constants.LinkedInUserInfoURL, nil) if err != nil { - log.Debug("Failed to create linkedin user info request: ", err) + log.Debug().Err(err).Msg("Failed to create linkedin user info request") return nil, fmt.Errorf("error creating linkedin user info request: %s", err.Error()) } req.Header = http.Header{ @@ -525,19 +554,19 @@ func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, er response, err := client.Do(req) if err != nil { - log.Debug("Failed to request linkedin user info: ", err) + log.Debug().Err(err).Msg("Failed to request linkedin user info") return nil, err } defer response.Body.Close() body, err := io.ReadAll(response.Body) if err != nil { - log.Debug("Failed to read linkedin user info response body: ", err) + log.Debug().Err(err).Msg("Failed to read linkedin user info response body") return nil, fmt.Errorf("failed to read linkedin response body: %s", err.Error()) } if response.StatusCode >= 400 { - log.Debug("Failed to request linkedin user info: ", string(body)) + log.Debug().Err(err).Str("body", string(body)).Msg("Failed to request linkedin user info") return nil, fmt.Errorf("failed to request linkedin user info: %s", string(body)) } @@ -546,7 +575,7 @@ func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, er req, err = http.NewRequest("GET", constants.LinkedInEmailURL, nil) if err != nil { - log.Debug("Failed to create linkedin email info request: ", err) + log.Debug().Err(err).Msg("Failed to create linkedin email info request") return nil, fmt.Errorf("error creating linkedin user info request: %s", err.Error()) } req.Header = http.Header{ @@ -555,18 +584,18 @@ func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, er response, err = client.Do(req) if err != nil { - log.Debug("Failed to request linkedin email info: ", err) + log.Debug().Err(err).Msg("Failed to request linkedin email info") return nil, err } defer response.Body.Close() body, err = io.ReadAll(response.Body) if err != nil { - log.Debug("Failed to read linkedin email info response body: ", err) + log.Debug().Err(err).Msg("Failed to read linkedin email info response body") return nil, fmt.Errorf("failed to read linkedin email response body: %s", err.Error()) } if response.StatusCode >= 400 { - log.Debug("Failed to request linkedin user info: ", string(body)) + log.Debug().Err(err).Str("body", string(body)).Msg("Failed to request linkedin user info") return nil, fmt.Errorf("failed to request linkedin user info: %s", string(body)) } emailRawData := make(map[string]interface{}) @@ -577,7 +606,7 @@ func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, er profilePicture := userRawData["profilePicture"].(map[string]interface{})["displayImage~"].(map[string]interface{})["elements"].([]interface{})[0].(map[string]interface{})["identifiers"].([]interface{})[0].(map[string]interface{})["identifier"].(string) emailAddress := emailRawData["elements"].([]interface{})[0].(map[string]interface{})["handle~"].(map[string]interface{})["emailAddress"].(string) - user := &models.User{ + user := &schemas.User{ GivenName: &firstName, FamilyName: &lastName, Picture: &profilePicture, @@ -587,18 +616,25 @@ func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, er return user, nil } -func processAppleUserInfo(ctx context.Context, code string, user_ *AppleUserInfo) (*models.User, error) { - var user = &models.User{} - oauth2Token, err := oauth.OAuthProviders.AppleConfig.Exchange(ctx, code) +func (h *httpProvider) processAppleUserInfo(ctx *gin.Context, code string, user_ *AppleUserInfo) (*schemas.User, error) { + log := h.Log.With().Str("func", "processAppleUserInfo").Logger() + cfg, err := h.OAuthProvider.GetOAuthConfig(ctx, constants.AuthRecipeMethodApple) if err != nil { - log.Debug("Failed to exchange code for token: ", err) + log.Debug().Err(err).Msg("Error getting oauth config") + return nil, fmt.Errorf("error getting oauth config: %s", err.Error()) + } + + var user = &schemas.User{} + oauth2Token, err := cfg.Exchange(ctx, code) + if err != nil { + log.Debug().Err(err).Msg("Failed to exchange code for token") return user, fmt.Errorf("invalid apple exchange code: %s", err.Error()) } // 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") + log.Debug().Err(err).Msg("Failed to extract ID Token from OAuth2 token") return user, fmt.Errorf("unable to extract id_token") } @@ -606,18 +642,18 @@ func processAppleUserInfo(ctx context.Context, code string, user_ *AppleUserInfo claimsData := tokenSplit[1] decodedClaimsData, err := base64.RawURLEncoding.DecodeString(claimsData) if err != nil { - log.Debugf("Failed to decrypt claims %s: %s", claimsData, err.Error()) + log.Debug().Err(err).Msg("Failed to decode claims data") return user, fmt.Errorf("failed to decrypt claims data: %s", err.Error()) } claims := make(map[string]interface{}) err = json.Unmarshal(decodedClaimsData, &claims) if err != nil { - log.Debug("Failed to unmarshal claims data: ", err) + log.Debug().Err(err).Msg("Failed to unmarshal claims data") return user, fmt.Errorf("failed to unmarshal claims data: %s", err.Error()) } if val, ok := claims["email"]; !ok || val == nil { - log.Debug("Failed to extract email from claims.") + log.Debug().Err(err).Msg("Failed to extract email from claims.") return user, fmt.Errorf("unable to extract email, please check the scopes enabled for your app. It needs `email`, `name` scopes") } else { email := val.(string) @@ -642,17 +678,23 @@ func processAppleUserInfo(ctx context.Context, code string, user_ *AppleUserInfo return user, err } -func processDiscordUserInfo(ctx context.Context, code string) (*models.User, error) { - oauth2Token, err := oauth.OAuthProviders.DiscordConfig.Exchange(ctx, code) +func (h *httpProvider) processDiscordUserInfo(ctx *gin.Context, code string) (*schemas.User, error) { + log := h.Log.With().Str("func", "processDiscordUserInfo").Logger() + cfg, err := h.OAuthProvider.GetOAuthConfig(ctx, constants.AuthRecipeMethodDiscord) if err != nil { - log.Debug("Failed to exchange code for token: ", err) + log.Debug().Err(err).Msg("Error getting oauth config") + return nil, fmt.Errorf("error getting oauth config: %s", err.Error()) + } + oauth2Token, err := cfg.Exchange(ctx, code) + if err != nil { + log.Debug().Err(err).Msg("Failed to exchange code for token") return nil, fmt.Errorf("invalid discord exchange code: %s", err.Error()) } client := http.Client{} req, err := http.NewRequest("GET", constants.DiscordUserInfoURL, nil) if err != nil { - log.Debug("Failed to create Discord user info request: ", err) + log.Debug().Err(err).Msg("Failed to create Discord user info request") return nil, fmt.Errorf("error creating Discord user info request: %s", err.Error()) } req.Header = http.Header{ @@ -661,45 +703,45 @@ func processDiscordUserInfo(ctx context.Context, code string) (*models.User, err response, err := client.Do(req) if err != nil { - log.Debug("Failed to request Discord user info: ", err) + log.Debug().Err(err).Msg("Failed to request Discord user info") return nil, err } defer response.Body.Close() body, err := io.ReadAll(response.Body) if err != nil { - log.Debug("Failed to read Discord user info response body: ", err) + log.Debug().Err(err).Msg("Failed to read Discord user info response body") return nil, fmt.Errorf("failed to read Discord response body: %s", err.Error()) } if response.StatusCode >= 400 { - log.Debug("Failed to request Discord user info: ", string(body)) + log.Debug().Err(err).Msg("Failed to request Discord user info") return nil, fmt.Errorf("failed to request Discord user info: %s", string(body)) } // Unmarshal the response body into a map responseRawData := make(map[string]interface{}) if err := json.Unmarshal(body, &responseRawData); err != nil { - log.Debug("Failed to unmarshal Discord response: ", err) + log.Debug().Err(err).Msg("Failed to unmarshal Discord response") return nil, fmt.Errorf("failed to unmarshal Discord response: %s", err.Error()) } // Safely extract the user data userRawData, ok := responseRawData["user"].(map[string]interface{}) if !ok { - log.Debug("User data is not in expected format or missing in response") + log.Debug().Err(err).Msg("User data is not in expected format or missing in response") return nil, fmt.Errorf("user data is not in expected format or missing in response") } // Extract the username firstName, ok := userRawData["username"].(string) if !ok { - log.Debug("Username is not in expected format or missing in user data") + log.Debug().Err(err).Msg("Username is not in expected format or missing in user data") return nil, fmt.Errorf("username is not in expected format or missing in user data") } profilePicture := fmt.Sprintf("https://cdn.discordapp.com/avatars/%s/%s.png", userRawData["id"].(string), userRawData["avatar"].(string)) - user := &models.User{ + user := &schemas.User{ GivenName: &firstName, Picture: &profilePicture, } @@ -707,17 +749,24 @@ func processDiscordUserInfo(ctx context.Context, code string) (*models.User, err return user, nil } -func processTwitterUserInfo(ctx context.Context, code, verifier string) (*models.User, error) { - oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(ctx, code, oauth2.SetAuthURLParam("code_verifier", verifier)) +func (h *httpProvider) processTwitterUserInfo(ctx *gin.Context, code, verifier string) (*schemas.User, error) { + log := h.Log.With().Str("func", "processTwitterUserInfo").Logger() + cfg, err := h.OAuthProvider.GetOAuthConfig(ctx, constants.AuthRecipeMethodTwitter) + if err != nil { + log.Debug().Err(err).Msg("Error getting oauth config") + return nil, fmt.Errorf("error getting oauth config: %s", err.Error()) + } + + oauth2Token, err := cfg.Exchange(ctx, code, oauth2.SetAuthURLParam("code_verifier", verifier)) if err != nil { - log.Debug("Failed to exchange code for token: ", err) + log.Debug().Err(err).Msg("Failed to exchange code for token") return nil, fmt.Errorf("invalid twitter exchange code: %s", err.Error()) } client := http.Client{} req, err := http.NewRequest("GET", constants.TwitterUserInfoURL, nil) if err != nil { - log.Debug("Failed to create Twitter user info request: ", err) + log.Debug().Err(err).Msg("Failed to create Twitter user info request") return nil, fmt.Errorf("error creating Twitter user info request: %s", err.Error()) } req.Header = http.Header{ @@ -726,19 +775,19 @@ func processTwitterUserInfo(ctx context.Context, code, verifier string) (*models response, err := client.Do(req) if err != nil { - log.Debug("Failed to request Twitter user info: ", err) + log.Debug().Err(err).Msg("Failed to request Twitter user info") return nil, err } defer response.Body.Close() body, err := io.ReadAll(response.Body) if err != nil { - log.Debug("Failed to read Twitter user info response body: ", err) + log.Debug().Err(err).Msg("Failed to read Twitter user info response body") return nil, fmt.Errorf("failed to read Twitter response body: %s", err.Error()) } if response.StatusCode >= 400 { - log.Debug("Failed to request Twitter user info: ", string(body)) + log.Debug().Err(err).Str("body", string(body)).Msg("Failed to request Twitter user info") return nil, fmt.Errorf("failed to request Twitter user info: %s", string(body)) } @@ -763,7 +812,7 @@ func processTwitterUserInfo(ctx context.Context, code, verifier string) (*models nickname := userRawData["username"].(string) profilePicture := userRawData["profile_image_url"].(string) - user := &models.User{ + user := &schemas.User{ GivenName: &firstName, FamilyName: &lastName, Picture: &profilePicture, @@ -774,32 +823,39 @@ func processTwitterUserInfo(ctx context.Context, code, verifier string) (*models } // process microsoft user information -func processMicrosoftUserInfo(ctx context.Context, code string) (*models.User, error) { - oauth2Token, err := oauth.OAuthProviders.MicrosoftConfig.Exchange(ctx, code) +func (h *httpProvider) processMicrosoftUserInfo(ctx *gin.Context, code string) (*schemas.User, error) { + log := h.Log.With().Str("func", "processMicrosoftUserInfo").Logger() + cfg, err := h.OAuthProvider.GetOAuthConfig(ctx, constants.AuthRecipeMethodMicrosoft) + if err != nil { + log.Debug().Err(err).Msg("Error getting oauth config") + return nil, fmt.Errorf("error getting oauth config: %s", err.Error()) + } + oauth2Token, err := cfg.Exchange(ctx, code) if err != nil { - log.Debug("Failed to exchange code for token: ", err) + log.Debug().Err(err).Msg("Failed to exchange code for token") return nil, fmt.Errorf("invalid microsoft exchange code: %s", err.Error()) } + oidcProvider, err := oidc.NewProvider(ctx, fmt.Sprintf("https://login.microsoftonline.com/%s/v2.0", h.MicrosoftTenantID)) // we need to skip issuer check because for common tenant it will return internal issuer which does not match - verifier := oauth.OIDCProviders.MicrosoftOIDC.Verifier(&oidc.Config{ - ClientID: oauth.OAuthProviders.MicrosoftConfig.ClientID, + verifier := oidcProvider.Verifier(&oidc.Config{ + ClientID: h.MicrosoftClientID, SkipIssuerCheck: true, }) // Extract the ID Token from OAuth2 token. rawIDToken, ok := oauth2Token.Extra("id_token").(string) if !ok { - log.Debug("Failed to extract ID Token from OAuth2 token") + log.Debug().Err(err).Msg("Failed to extract ID Token from OAuth2 token") return nil, 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) + log.Debug().Err(err).Msg("Failed to verify ID Token") return nil, fmt.Errorf("unable to verify id_token: %s", err.Error()) } - user := &models.User{} + user := &schemas.User{} if err := idToken.Claims(&user); err != nil { - log.Debug("Failed to parse ID Token claims: ", err) + log.Debug().Err(err).Msg("Failed to parse ID Token claims") return nil, fmt.Errorf("unable to extract claims") } @@ -807,34 +863,46 @@ func processMicrosoftUserInfo(ctx context.Context, code string) (*models.User, e } // process twitch user information -func processTwitchUserInfo(ctx context.Context, code string) (*models.User, error) { - oauth2Token, err := oauth.OAuthProviders.TwitchConfig.Exchange(ctx, code) +func (h *httpProvider) processTwitchUserInfo(ctx *gin.Context, code string) (*schemas.User, error) { + log := h.Log.With().Str("func", "processTwitchUserInfo").Logger() + cfg, err := h.OAuthProvider.GetOAuthConfig(ctx, constants.AuthRecipeMethodTwitch) if err != nil { - log.Debug("Failed to exchange code for token: ", err) + log.Debug().Err(err).Msg("Error getting oauth config") + return nil, fmt.Errorf("error getting oauth config: %s", err.Error()) + } + + oauth2Token, err := cfg.Exchange(ctx, code) + if err != nil { + log.Debug().Err(err).Msg("Failed to exchange code for token") return nil, fmt.Errorf("invalid twitch exchange code: %s", err.Error()) } // 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") + log.Debug().Err(err).Msg("Failed to extract ID Token from OAuth2 token") return nil, fmt.Errorf("unable to extract id_token") } - verifier := oauth.OIDCProviders.TwitchOIDC.Verifier(&oidc.Config{ - ClientID: oauth.OAuthProviders.TwitchConfig.ClientID, + oidcProvider, err := oidc.NewProvider(ctx, "https://id.twitch.tv/oauth2") + if err != nil { + log.Debug().Err(err).Msg("Failed to create OIDC provider") + return nil, fmt.Errorf("failed to create oidc provider: %s", err.Error()) + } + verifier := oidcProvider.Verifier(&oidc.Config{ + ClientID: h.TwitchClientID, SkipIssuerCheck: true, }) // Parse and verify ID Token payload. idToken, err := verifier.Verify(ctx, rawIDToken) if err != nil { - log.Debug("Failed to verify ID Token: ", err) + log.Debug().Err(err).Msg("Failed to verify ID Token") return nil, fmt.Errorf("unable to verify id_token: %s", err.Error()) } - user := &models.User{} + user := &schemas.User{} if err := idToken.Claims(&user); err != nil { - log.Debug("Failed to parse ID Token claims: ", err) + log.Debug().Err(err).Msg("Failed to parse ID Token claims") return nil, fmt.Errorf("unable to extract claims") } @@ -842,17 +910,23 @@ func processTwitchUserInfo(ctx context.Context, code string) (*models.User, erro } // process roblox user information -func processRobloxUserInfo(ctx context.Context, code, verifier string) (*models.User, error) { - oauth2Token, err := oauth.OAuthProviders.RobloxConfig.Exchange(ctx, code, oauth2.SetAuthURLParam("code_verifier", verifier)) +func (h *httpProvider) processRobloxUserInfo(ctx *gin.Context, code, verifier string) (*schemas.User, error) { + log := h.Log.With().Str("func", "processRobloxUserInfo").Logger() + cfg, err := h.OAuthProvider.GetOAuthConfig(ctx, constants.AuthRecipeMethodRoblox) + if err != nil { + log.Debug().Err(err).Msg("Error getting oauth config") + return nil, fmt.Errorf("error getting oauth config: %s", err.Error()) + } + oauth2Token, err := cfg.Exchange(ctx, code, oauth2.SetAuthURLParam("code_verifier", verifier)) if err != nil { - log.Debug("Failed to exchange code for token: ", err) + log.Debug().Err(err).Msg("Failed to exchange code for token") return nil, fmt.Errorf("invalid roblox exchange code: %s", err.Error()) } client := http.Client{} req, err := http.NewRequest("GET", constants.RobloxUserInfoURL, nil) if err != nil { - log.Debug("Failed to create roblox user info request: ", err) + log.Debug().Err(err).Msg("Failed to create roblox user info request") return nil, fmt.Errorf("error creating roblox user info request: %s", err.Error()) } req.Header = http.Header{ @@ -861,19 +935,19 @@ func processRobloxUserInfo(ctx context.Context, code, verifier string) (*models. response, err := client.Do(req) if err != nil { - log.Debug("Failed to request roblox user info: ", err) + log.Debug().Err(err).Msg("Failed to request roblox user info") return nil, err } defer response.Body.Close() body, err := io.ReadAll(response.Body) if err != nil { - log.Debug("Failed to read roblox user info response body: ", err) + log.Debug().Err(err).Msg("Failed to read roblox user info response body") return nil, fmt.Errorf("failed to read roblox response body: %s", err.Error()) } if response.StatusCode >= 400 { - log.Debug("Failed to request roblox user info: ", string(body)) + log.Debug().Err(err).Str("body", string(body)).Msg("Failed to request roblox user info") return nil, fmt.Errorf("failed to request roblox user info: %s", string(body)) } @@ -895,7 +969,7 @@ func processRobloxUserInfo(ctx context.Context, code, verifier string) (*models. } else { email = userRawData["sub"].(string) } - user := &models.User{ + user := &schemas.User{ GivenName: &firstName, FamilyName: &lastName, Picture: &profilePicture, diff --git a/internal/http_handlers/oauth_login.go b/internal/http_handlers/oauth_login.go new file mode 100644 index 000000000..1c872f51d --- /dev/null +++ b/internal/http_handlers/oauth_login.go @@ -0,0 +1,88 @@ +package http_handlers + +import ( + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/validators" +) + +// OAuthLoginHandler set host in the oauth state that is useful for redirecting to oauth_callback +func (h *httpProvider) OAuthLoginHandler() gin.HandlerFunc { + log := h.Log.With().Str("func", "OAuthLoginHandler").Logger() + return func(c *gin.Context) { + // deprecating redirectURL instead use redirect_uri + redirectURI := strings.TrimSpace(c.Query("redirectURL")) + if redirectURI == "" { + redirectURI = strings.TrimSpace(c.Query("redirect_uri")) + } + roles := strings.TrimSpace(c.Query("roles")) + state := strings.TrimSpace(c.Query("state")) + scopeString := strings.TrimSpace(c.Query("scope")) + + if redirectURI == "" { + log.Debug().Msg("redirect uri is missing") + c.JSON(400, gin.H{ + "error": "invalid redirect uri", + }) + return + } + + if state == "" { + log.Debug().Msg("state is missing, creating new state") + state = uuid.New().String() + } + + var scope []string + if scopeString == "" { + scope = []string{"openid", "profile", "email"} + } else { + scope = strings.Split(scopeString, " ") + } + + if roles != "" { + // validate role + rolesSplit := strings.Split(roles, ",") + + // use protected roles verification for admin login only. + // though if not associated with user, it will be rejected from oauth_callback + allowedRoles := h.Config.Roles + protectedRoles := h.Config.ProtectedRoles + if !validators.IsValidRoles(rolesSplit, append([]string{}, append(allowedRoles, protectedRoles...)...)) { + log.Debug().Msg("invalid role") + c.JSON(400, gin.H{ + "error": "invalid role", + }) + return + } + } else { + roles = strings.Join(h.Config.DefaultRoles, ",") + } + + oauthStateString := state + "___" + redirectURI + "___" + roles + "___" + strings.Join(scope, " ") + + provider := c.Param("oauth_provider") + log := log.With().Str("provider", provider).Logger() + cfg, err := h.OAuthProvider.GetOAuthConfig(c, provider) + if err != nil { + log.Debug().Err(err).Msg("Error getting oauth config") + c.JSON(422, gin.H{ + "error": err.Error(), + }) + return + } + if err := h.MemoryStoreProvider.SetState(oauthStateString, provider); err != nil { + log.Debug().Err(err).Msg("Error setting state") + c.JSON(500, gin.H{ + "error": "internal server error", + }) + return + } + url := cfg.AuthCodeURL(oauthStateString) + log.Debug().Str("url", url).Msg("redirecting to oauth provider") + c.Redirect(http.StatusTemporaryRedirect, url) + } +} diff --git a/server/handlers/openid_config.go b/internal/http_handlers/openid_config.go similarity index 80% rename from server/handlers/openid_config.go rename to internal/http_handlers/openid_config.go index 3414e09e5..0c570953e 100644 --- a/server/handlers/openid_config.go +++ b/internal/http_handlers/openid_config.go @@ -1,18 +1,16 @@ -package handlers +package http_handlers import ( "github.com/gin-gonic/gin" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" + "github.com/authorizerdev/authorizer/internal/parsers" ) // OpenIDConfigurationHandler handler for open-id configurations -func OpenIDConfigurationHandler() gin.HandlerFunc { +func (h *httpProvider) OpenIDConfigurationHandler() gin.HandlerFunc { return func(c *gin.Context) { issuer := parsers.GetHost(c) - jwtType, _ := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType) + jwtType := h.Config.JWTType c.JSON(200, gin.H{ "issuer": issuer, diff --git a/internal/http_handlers/playground.go b/internal/http_handlers/playground.go new file mode 100644 index 000000000..c476ddd35 --- /dev/null +++ b/internal/http_handlers/playground.go @@ -0,0 +1,36 @@ +package http_handlers + +import ( + "net/http" + + "github.com/99designs/gqlgen/graphql/playground" + "github.com/gin-gonic/gin" + "github.com/rs/zerolog/log" +) + +// PlaygroundHandler is the handler for the /playground route +func (h *httpProvider) PlaygroundHandler() gin.HandlerFunc { + // log := h.Log.With().Str("func", "PlaygroundHandler").Logger() + return func(c *gin.Context) { + var handlerFunc http.HandlerFunc + + enablePlayground := h.Config.EnablePlayground + + // if env set to true, then check if logged in as super admin, if logged in then return graphql else 401 error + // if env set to false, then disabled the playground with 404 error + if enablePlayground { + if h.TokenProvider.IsSuperAdmin(c) { + handlerFunc = playground.Handler("GraphQL", "/graphql") + } else { + log.Debug().Msg("not logged in as super admin") + c.JSON(http.StatusUnauthorized, gin.H{"error": "not logged in as super admin"}) + return + } + } else { + log.Debug().Msg("playground is disabled") + c.JSON(http.StatusNotFound, gin.H{"error": "playground is disabled"}) + return + } + handlerFunc.ServeHTTP(c.Writer, c.Request) + } +} diff --git a/internal/http_handlers/provider.go b/internal/http_handlers/provider.go new file mode 100644 index 000000000..c11341cca --- /dev/null +++ b/internal/http_handlers/provider.go @@ -0,0 +1,103 @@ +package http_handlers + +import ( + "github.com/gin-gonic/gin" + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/authenticators" + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/email" + "github.com/authorizerdev/authorizer/internal/events" + "github.com/authorizerdev/authorizer/internal/memory_store" + "github.com/authorizerdev/authorizer/internal/oauth" + "github.com/authorizerdev/authorizer/internal/sms" + "github.com/authorizerdev/authorizer/internal/storage" + "github.com/authorizerdev/authorizer/internal/token" +) + +// Dependencies for a graphql provider +type Dependencies struct { + Log *zerolog.Logger + + // Providers for various services + // AuthenticatorProvider is used to register authenticators like totp (Google Authenticator) + AuthenticatorProvider authenticators.Provider + // EmailProvider is used to send emails + EmailProvider email.Provider + // EventsProvider is used to register events + EventsProvider events.Provider + // MemoryStoreProvider is used to store data in memory + MemoryStoreProvider memory_store.Provider + // SMSProvider is used to send SMS + SMSProvider sms.Provider + // StorageProvider is used to register storage like database + StorageProvider storage.Provider + // TokenProvider is used to generate tokens + TokenProvider token.Provider + // OAuthProvider is used to register oauth providers + OAuthProvider oauth.Provider +} + +// New constructs a new http provider with given arguments +func New(cfg *config.Config, deps *Dependencies) (Provider, error) { + // TODO - Add any validation here for config and dependencies + g := &httpProvider{ + Config: cfg, + Dependencies: *deps, + } + return g, nil +} + +// httpProvider is the struct that provides resolver functions for http routes. +type httpProvider struct { + *config.Config + Dependencies +} + +// Ensure interface is implemented +var _ Provider = &httpProvider{} + +// Provider is the interface that provides the methods to interact with the http handlers. +type Provider interface { + // AppHandler is the main handler that handels all the app requests + AppHandler() gin.HandlerFunc + // AuthorizeHandler is the main handler that handels all the authorize requests + AuthorizeHandler() gin.HandlerFunc + // DashboardHandler is the main handler that handels all the dashboard requests + DashboardHandler() gin.HandlerFunc + // GraphqlHandler is the main handler that handels all the graphql requests + GraphqlHandler() gin.HandlerFunc + // HealthHandler is the main handler that handels all the health requests + HealthHandler() gin.HandlerFunc + // JWKsHandler is the main handler that handels all the jwks requests + JWKsHandler() gin.HandlerFunc + // LogoutHandler is the main handler that handels all the logout requests + LogoutHandler() gin.HandlerFunc + // OAuthCallbackHandler is the main handler that handels all the oauth callback requests + OAuthCallbackHandler() gin.HandlerFunc + // OAuthLoginHandler is the main handler that handels all the oauth login requests + OAuthLoginHandler() gin.HandlerFunc + // OpenIDConfigurationHandler is the main handler that handels all the openid configuration requests + OpenIDConfigurationHandler() gin.HandlerFunc + // PlaygroundHandler is the main handler that handels all the playground requests + PlaygroundHandler() gin.HandlerFunc + // RevokeRefreshTokenHandler is the main handler that handels all the revoke refresh token requests + RevokeRefreshTokenHandler() gin.HandlerFunc + // RootHandler is the main handler that handels all the root requests + RootHandler() gin.HandlerFunc + // TokenHandler is the main handler that handels all the token requests + TokenHandler() gin.HandlerFunc + // UserInfoHandler is the main handler that handels all the user info requests + UserInfoHandler() gin.HandlerFunc + // VerifyEmailHandler is the main handler that handels all the verify email requests + VerifyEmailHandler() gin.HandlerFunc + + // ClientCheckMiddleware is the middleware that checks if the client is valid + ClientCheckMiddleware() gin.HandlerFunc + // ContextMiddleware is the middleware that adds the context to the request + ContextMiddleware() gin.HandlerFunc + // CORSMiddleware is the middleware that adds the cors headers to the response + CORSMiddleware() gin.HandlerFunc + // LoggerMiddleware is the middleware that logs the request + LoggerMiddleware() gin.HandlerFunc +} diff --git a/internal/http_handlers/revoke_refresh_token.go b/internal/http_handlers/revoke_refresh_token.go new file mode 100644 index 000000000..cf08f2d9a --- /dev/null +++ b/internal/http_handlers/revoke_refresh_token.go @@ -0,0 +1,108 @@ +package http_handlers + +import ( + "net/http" + "strings" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/gin-gonic/gin" +) + +// RevokeRefreshTokenHandler handler to revoke refresh token +func (h *httpProvider) RevokeRefreshTokenHandler() gin.HandlerFunc { + log := h.Log.With().Str("func", "RevokeRefreshTokenHandler").Logger() + return func(gc *gin.Context) { + var reqBody map[string]string + if err := gc.BindJSON(&reqBody); err != nil { + log.Debug().Err(err).Msg("failed to bind json") + gc.JSON(http.StatusBadRequest, gin.H{ + "error": "error_binding_json", + "error_description": err.Error(), + }) + return + } + // get client ID + clientID := strings.TrimSpace(reqBody["client_id"]) // kept for backward compatibility // else we expect to be present as header + if clientID == "" { + clientID = gc.Request.Header.Get("x-authorizer-client-id") + } + // get fingerprint hash + refreshToken := strings.TrimSpace(reqBody["refresh_token"]) + + if clientID == "" { + log.Debug().Msg("Client ID is mising") + gc.JSON(http.StatusBadRequest, gin.H{ + "error": "client_id_required", + "error_description": "The client id is missing", + }) + return + } + + if h.Config.ClientID != clientID { + log.Debug().Str("client_id", clientID).Msg("Client ID is invalid") + gc.JSON(http.StatusBadRequest, gin.H{ + "error": "invalid_client_id", + "error_description": "The client id is invalid", + }) + return + } + + claims, err := h.TokenProvider.ParseJWTToken(refreshToken) + if err != nil { + log.Debug().Err(err).Msg("failed to parse jwt") + gc.JSON(http.StatusBadRequest, gin.H{ + "error": err.Error(), + "error_description": "Failed to parse jwt", + }) + return + } + + userID := claims["sub"].(string) + loginMethod := claims["login_method"] + sessionToken := userID + if loginMethod != nil && loginMethod != "" { + sessionToken = loginMethod.(string) + ":" + userID + } + + existingToken, err := h.MemoryStoreProvider.GetUserSession(sessionToken, constants.TokenTypeRefreshToken+"_"+claims["nonce"].(string)) + if err != nil { + log.Debug().Err(err).Msg("Failed to get refresh token") + gc.JSON(http.StatusInternalServerError, gin.H{ + "error": "failed_to_get_refresh_token", + "error_description": "Failed to get user refresh token: " + err.Error(), + }) + return + } + + if existingToken == "" { + log.Debug().Msg("Token not found") + gc.JSON(http.StatusBadRequest, gin.H{ + "error": "token_not_found", + "error_description": "Token not found", + }) + return + } + + if existingToken != refreshToken { + log.Debug().Msg("Token does not match") + gc.JSON(http.StatusBadRequest, gin.H{ + "error": "token_does_not_match", + "error_description": "Token does not match", + }) + return + } + + if err := h.MemoryStoreProvider.DeleteUserSession(sessionToken, claims["nonce"].(string)); err != nil { + log.Debug().Err(err).Msg("failed to delete user session") + gc.JSON(http.StatusInternalServerError, gin.H{ + "error": "failed_to_delete_user_session", + "error_description": "Failed to delete user session: " + err.Error(), + }) + return + } + + gc.JSON(http.StatusOK, gin.H{ + "message": "Token revoked successfully", + }) + } +} diff --git a/server/handlers/root.go b/internal/http_handlers/root.go similarity index 71% rename from server/handlers/root.go rename to internal/http_handlers/root.go index 70cfc3065..9c39463f0 100644 --- a/server/handlers/root.go +++ b/internal/http_handlers/root.go @@ -1,4 +1,4 @@ -package handlers +package http_handlers import ( "net/http" @@ -7,7 +7,7 @@ import ( ) // RootHandler is the handler for / root route. -func RootHandler() gin.HandlerFunc { +func (h *httpProvider) RootHandler() gin.HandlerFunc { return func(c *gin.Context) { c.Redirect(http.StatusTemporaryRedirect, "/dashboard") } diff --git a/server/handlers/token.go b/internal/http_handlers/token.go similarity index 70% rename from server/handlers/token.go rename to internal/http_handlers/token.go index 1a6013042..b41fde8c5 100644 --- a/server/handlers/token.go +++ b/internal/http_handlers/token.go @@ -1,4 +1,4 @@ -package handlers +package http_handlers import ( "crypto/sha256" @@ -9,13 +9,11 @@ import ( "github.com/gin-gonic/gin" "github.com/google/uuid" - log "github.com/sirupsen/logrus" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/token" ) type RequestBody struct { @@ -30,11 +28,12 @@ type RequestBody struct { // TokenHandler to handle /oauth/token requests // grant type required -func TokenHandler() gin.HandlerFunc { +func (h *httpProvider) TokenHandler() gin.HandlerFunc { + log := h.Log.With().Str("func", "TokenHandler").Logger() return func(gc *gin.Context) { var reqBody RequestBody if err := gc.Bind(&reqBody); err != nil { - log.Debug("Error binding JSON: ", err) + log.Debug().Err(err).Msg("failed to bind json") gc.JSON(http.StatusBadRequest, gin.H{ "error": "error_binding_json", "error_description": err.Error(), @@ -57,7 +56,7 @@ func TokenHandler() gin.HandlerFunc { isAuthorizationCodeGrant := grantType == "authorization_code" if !isRefreshTokenGrant && !isAuthorizationCodeGrant { - log.Debug("Invalid grant type: ", grantType) + log.Debug().Str("grant_type", grantType).Msg("Invalid grant type") gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_grant_type", "error_description": "grant_type is invalid", @@ -71,16 +70,16 @@ func TokenHandler() gin.HandlerFunc { } if clientID == "" { - log.Debug("Client ID is empty") + log.Debug().Msg("Client ID is missing") gc.JSON(http.StatusBadRequest, gin.H{ "error": "client_id_required", - "error_description": "The client id is required", + "error_description": "The client id is missing", }) return } - if client, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); clientID != client || err != nil { - log.Debug("Client ID is invalid: ", clientID) + if h.Config.ClientID != clientID { + log.Debug().Str("client_id", clientID).Msg("Client ID is invalid") gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_client_id", "error_description": "The client id is invalid", @@ -95,7 +94,7 @@ func TokenHandler() gin.HandlerFunc { if isAuthorizationCodeGrant { if code == "" { - log.Debug("Code is empty") + log.Debug().Msg("Code is missing") gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_code", "error_description": "The code is required", @@ -111,9 +110,9 @@ func TokenHandler() gin.HandlerFunc { return } // Get state - sessionData, err := memorystore.Provider.GetState(code) + sessionData, err := h.MemoryStoreProvider.GetState(code) if sessionData == "" || err != nil { - log.Debug("Session data is empty") + log.Debug().Err(err).Msg("Error getting session data") gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_code", "error_description": "The code is invalid", @@ -125,7 +124,7 @@ func TokenHandler() gin.HandlerFunc { // [1] -> session cookie sessionDataSplit := strings.Split(sessionData, "@@") - go memorystore.Provider.RemoveState(code) + go h.MemoryStoreProvider.RemoveState(code) if codeVerifier != "" { hash := sha256.New() @@ -142,8 +141,8 @@ func TokenHandler() gin.HandlerFunc { } } else { - if clientHash, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientSecret); clientSecret != clientHash || err != nil { - log.Debug("Client Secret is invalid: ", clientID) + if clientSecret != h.Config.ClientSecret { + log.Debug().Err(err).Msg("Error getting client secret") gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_client_secret", "error_description": "The client secret is invalid", @@ -153,9 +152,9 @@ func TokenHandler() gin.HandlerFunc { } // validate session - claims, err := token.ValidateBrowserSession(gc, sessionDataSplit[1]) + claims, err := h.TokenProvider.ValidateBrowserSession(gc, sessionDataSplit[1]) if err != nil { - log.Debug("Error validating session: ", err) + log.Debug().Err(err).Msg("Error validating session") gc.JSON(http.StatusUnauthorized, gin.H{ "error": "unauthorized", "error_description": "Invalid session data", @@ -174,12 +173,12 @@ func TokenHandler() gin.HandlerFunc { sessionKey = loginMethod + ":" + userID } - go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce) + go h.MemoryStoreProvider.DeleteUserSession(sessionKey, claims.Nonce) } else { // validate refresh token if refreshToken == "" { - log.Debug("Refresh token is empty") + log.Debug().Msg("Refresh token is missing") gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_refresh_token", "error_description": "The refresh token is invalid", @@ -187,9 +186,9 @@ func TokenHandler() gin.HandlerFunc { return } - claims, err := token.ValidateRefreshToken(gc, refreshToken) + claims, err := h.TokenProvider.ValidateRefreshToken(gc, refreshToken) if err != nil { - log.Debug("Error validating refresh token: ", err) + log.Debug().Err(err).Msg("Error validating refresh token") gc.JSON(http.StatusUnauthorized, gin.H{ "error": "unauthorized", "error_description": err.Error(), @@ -214,11 +213,11 @@ func TokenHandler() gin.HandlerFunc { } // remove older refresh token and rotate it for security - go memorystore.Provider.DeleteUserSession(sessionKey, claims["nonce"].(string)) + go h.MemoryStoreProvider.DeleteUserSession(sessionKey, claims["nonce"].(string)) } if sessionKey == "" { - log.Debug("Error getting sessionKey: ", sessionKey, loginMethod) + log.Debug().Str("session_key", sessionKey).Str("login_method", loginMethod).Msg("Session key not found") gc.JSON(http.StatusUnauthorized, gin.H{ "error": "unauthorized", "error_description": "User not found", @@ -226,20 +225,27 @@ func TokenHandler() gin.HandlerFunc { return } - user, err := db.Provider.GetUserByID(gc, userID) + user, err := h.StorageProvider.GetUserByID(gc, userID) if err != nil { - log.Debug("Error getting user: ", err) + log.Debug().Err(err).Str("user_id", userID).Msg("Error getting user") gc.JSON(http.StatusUnauthorized, gin.H{ "error": "unauthorized", "error_description": "User not found", }) return } - + hostname := parsers.GetHost(gc) nonce := uuid.New().String() + "@@" + code - authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod, nonce, code) + authToken, err := h.TokenProvider.CreateAuthToken(gc, &token.AuthTokenConfig{ + User: user, + Roles: roles, + Scope: scope, + LoginMethod: loginMethod, + Nonce: nonce, + HostName: hostname, + }) if err != nil { - log.Debug("Error creating auth token: ", err) + log.Debug().Err(err).Msg("Error creating auth token") gc.JSON(http.StatusUnauthorized, gin.H{ "error": "unauthorized", "error_description": "User not found", @@ -247,9 +253,9 @@ func TokenHandler() gin.HandlerFunc { return } - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) - cookie.SetSession(gc, authToken.FingerPrintHash) + h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) + h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) + cookie.SetSession(gc, authToken.FingerPrintHash, h.Config.AppCookieSecure) expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() if expiresIn <= 0 { @@ -265,7 +271,7 @@ func TokenHandler() gin.HandlerFunc { } if authToken.RefreshToken != nil { res["refresh_token"] = authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) + h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) } gc.JSON(http.StatusOK, res) } diff --git a/server/handlers/userinfo.go b/internal/http_handlers/userinfo.go similarity index 62% rename from server/handlers/userinfo.go rename to internal/http_handlers/userinfo.go index 1512e41bb..6001d8b9f 100644 --- a/server/handlers/userinfo.go +++ b/internal/http_handlers/userinfo.go @@ -1,38 +1,35 @@ -package handlers +package http_handlers import ( "encoding/json" "net/http" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/token" ) -func UserInfoHandler() gin.HandlerFunc { +func (h *httpProvider) UserInfoHandler() gin.HandlerFunc { + log := h.Log.With().Str("func", "UserInfoHandler").Logger() return func(gc *gin.Context) { - accessToken, err := token.GetAccessToken(gc) + accessToken, err := h.TokenProvider.GetAccessToken(gc) if err != nil { - log.Debug("Error getting access token: ", err) + log.Debug().Msg("Error getting access token") gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) return } - claims, err := token.ValidateAccessToken(gc, accessToken) + claims, err := h.TokenProvider.ValidateAccessToken(gc, accessToken) if err != nil { - log.Debug("Error validating access token: ", err) + log.Debug().Msg("Error validating access token") gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) return } userID := claims["sub"].(string) - user, err := db.Provider.GetUserByID(gc, userID) + user, err := h.StorageProvider.GetUserByID(gc, userID) if err != nil { - log.Debug("Error getting user: ", err) + log.Debug().Msg("Error getting user by ID") gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) @@ -41,7 +38,7 @@ func UserInfoHandler() gin.HandlerFunc { apiUser := user.AsAPIUser() userBytes, err := json.Marshal(apiUser) if err != nil { - log.Debug("Error marshalling user: ", err) + log.Debug().Msg("Error marshalling user") gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) @@ -50,7 +47,7 @@ func UserInfoHandler() gin.HandlerFunc { res := map[string]interface{}{} err = json.Unmarshal(userBytes, &res) if err != nil { - log.Debug("Error un-marshalling user: ", err) + log.Debug().Msg("Error unmarshalling user") gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) diff --git a/server/handlers/verify_email.go b/internal/http_handlers/verify_email.go similarity index 62% rename from server/handlers/verify_email.go rename to internal/http_handlers/verify_email.go index 34f9d9fed..ffb909fcf 100644 --- a/server/handlers/verify_email.go +++ b/internal/http_handlers/verify_email.go @@ -1,4 +1,4 @@ -package handlers +package http_handlers import ( "net/http" @@ -8,21 +8,20 @@ import ( "github.com/gin-gonic/gin" "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/token" + "github.com/authorizerdev/authorizer/internal/utils" ) // VerifyEmailHandler handles the verify email route. // It verifies email based on JWT token in query string -func VerifyEmailHandler() gin.HandlerFunc { +func (h *httpProvider) VerifyEmailHandler() gin.HandlerFunc { + log := h.Log.With().Str("func", "VerifyEmailHandler").Logger() return func(c *gin.Context) { redirectURL := strings.TrimSpace(c.Query("redirect_uri")) errorRes := gin.H{ @@ -30,14 +29,14 @@ func VerifyEmailHandler() gin.HandlerFunc { } tokenInQuery := c.Query("token") if tokenInQuery == "" { - log.Debug("Token is empty") + log.Debug().Msg("Token is missing") utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes)) return } - verificationRequest, err := db.Provider.GetVerificationRequestByToken(c, tokenInQuery) + verificationRequest, err := h.StorageProvider.GetVerificationRequestByToken(c, tokenInQuery) if err != nil { - log.Debug("Error getting verification request: ", err) + log.Debug().Err(err).Msg("Error getting verification request") errorRes["error"] = err.Error() utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes)) return @@ -45,24 +44,30 @@ func VerifyEmailHandler() gin.HandlerFunc { // verify if token exists in db hostname := parsers.GetHost(c) - claim, err := token.ParseJWTToken(tokenInQuery) + claim, err := h.TokenProvider.ParseJWTToken(tokenInQuery) if err != nil { - log.Debug("Error parsing token: ", err) + log.Debug().Err(err).Msg("Error parsing jwt token") errorRes["error"] = err.Error() utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes)) return } - - if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil { - log.Debug("Error validating jwt claims: ", err) + // // hostname, verificationRequest.Nonce, verificationRequest.Email + if ok, err := h.TokenProvider.ValidateJWTClaims(claim, &token.AuthTokenConfig{ + HostName: hostname, + Nonce: verificationRequest.Nonce, + User: &schemas.User{ + Email: refs.NewStringRef(verificationRequest.Email), + }, + }); !ok || err != nil { + log.Debug().Err(err).Msg("Error validating jwt token") errorRes["error"] = err.Error() utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes)) return } - user, err := db.Provider.GetUserByEmail(c, verificationRequest.Email) + user, err := h.StorageProvider.GetUserByEmail(c, verificationRequest.Email) if err != nil { - log.Debug("Error getting user: ", err) + log.Debug().Err(err).Msg("Error getting user by email") errorRes["error"] = err.Error() utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes)) return @@ -74,16 +79,18 @@ func VerifyEmailHandler() gin.HandlerFunc { now := time.Now().Unix() user.EmailVerifiedAt = &now isSignUp = true - user, err = db.Provider.UpdateUser(c, user) + user, err = h.StorageProvider.UpdateUser(c, user) if err != nil { - log.Debug("Error updating user: ", err) + log.Debug().Err(err).Msg("Error updating user") errorRes["error"] = err.Error() utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes)) return } } // delete from verification table - db.Provider.DeleteVerificationRequest(c, verificationRequest) + if err := h.StorageProvider.DeleteVerificationRequest(c, verificationRequest); err != nil { + log.Debug().Err(err).Msg("Error deleting verification request") + } state := strings.TrimSpace(c.Query("state")) rolesString := strings.TrimSpace(c.Query("roles")) @@ -112,7 +119,7 @@ func VerifyEmailHandler() gin.HandlerFunc { nonce := "" if state != "" { // Get state from store - authorizeState, _ := memorystore.Provider.GetState(state) + authorizeState, _ := h.MemoryStoreProvider.GetState(state) if authorizeState != "" { authorizeStateSplit := strings.Split(authorizeState, "@@") if len(authorizeStateSplit) > 1 { @@ -122,15 +129,23 @@ func VerifyEmailHandler() gin.HandlerFunc { } else { nonce = authorizeState } - go memorystore.Provider.RemoveState(state) + go h.MemoryStoreProvider.RemoveState(state) } } if nonce == "" { nonce = uuid.New().String() } - authToken, err := token.CreateAuthToken(c, user, roles, scope, loginMethod, nonce, code) + authToken, err := h.TokenProvider.CreateAuthToken(c, &token.AuthTokenConfig{ + User: user, + Roles: roles, + Scope: scope, + LoginMethod: loginMethod, + Nonce: nonce, + Code: code, + HostName: hostname, + }) if err != nil { - log.Debug("Error creating auth token: ", err) + log.Debug().Err(err).Msg("Error creating auth token") errorRes["error"] = err.Error() utils.HandleRedirectORJsonResponse(c, http.StatusInternalServerError, errorRes, generateRedirectURL(redirectURL, errorRes)) return @@ -159,13 +174,13 @@ func VerifyEmailHandler() gin.HandlerFunc { } sessionKey := loginMethod + ":" + user.ID - cookie.SetSession(c, 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, authToken.AccessToken.ExpiresAt) + cookie.SetSession(c, authToken.FingerPrintHash, h.Config.AppCookieSecure) + h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) + h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) if authToken.RefreshToken != nil { params = params + `&refresh_token=` + authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) + h.MemoryStoreProvider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) } if redirectURL == "" { @@ -180,17 +195,19 @@ func VerifyEmailHandler() gin.HandlerFunc { go func() { if isSignUp { - utils.RegisterEvent(c, constants.UserSignUpWebhookEvent, loginMethod, user) + h.EventsProvider.RegisterEvent(c, constants.UserSignUpWebhookEvent, loginMethod, user) // User is also logged in with signup - utils.RegisterEvent(c, constants.UserLoginWebhookEvent, loginMethod, user) + h.EventsProvider.RegisterEvent(c, constants.UserLoginWebhookEvent, loginMethod, user) } else { - utils.RegisterEvent(c, constants.UserLoginWebhookEvent, loginMethod, user) + h.EventsProvider.RegisterEvent(c, constants.UserLoginWebhookEvent, loginMethod, user) } - db.Provider.AddSession(c, &models.Session{ + if err := h.StorageProvider.AddSession(c, &schemas.Session{ UserID: user.ID, UserAgent: utils.GetUserAgent(c.Request), IP: utils.GetIP(c.Request), - }) + }); err != nil { + log.Debug().Err(err).Msg("Error adding session") + } }() c.Redirect(http.StatusTemporaryRedirect, redirectURL) diff --git a/internal/integration_tests/add_email_template_test.go b/internal/integration_tests/add_email_template_test.go new file mode 100644 index 000000000..76798cb85 --- /dev/null +++ b/internal/integration_tests/add_email_template_test.go @@ -0,0 +1,203 @@ +package integration_tests + +import ( + "fmt" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestAddEmailTemplate tests the add email template functionality by the admin +func TestAddEmailTemplate(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "add_email_template_user_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + require.NotNil(t, signupRes.User) + + t.Run("should fail without admin cookie", func(t *testing.T) { + // Attempt to add template without admin authentication + params := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeBasicAuthSignup, + Subject: "Verify your email", + Template: "Please verify your email by clicking the link: {{.URL}}", + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, params) + require.Error(t, err) + require.Nil(t, resp) + assert.Contains(t, err.Error(), "unauthorized") + }) + + // Add admin cookie for the rest of the tests + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + + t.Run("should fail with invalid event name", func(t *testing.T) { + params := &model.AddEmailTemplateRequest{ + EventName: "invalid_event_name", + Subject: "Test Subject", + Template: "Test Template", + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, params) + require.Error(t, err) + require.Nil(t, resp) + }) + + t.Run("should fail with empty subject", func(t *testing.T) { + params := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeBasicAuthSignup, + Subject: "", + Template: "Test Template", + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, params) + require.Error(t, err) + require.Nil(t, resp) + }) + + t.Run("should fail with whitespace-only subject", func(t *testing.T) { + params := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeBasicAuthSignup, + Subject: " ", + Template: "Test Template", + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, params) + require.Error(t, err) + require.Nil(t, resp) + }) + + t.Run("should fail with empty template", func(t *testing.T) { + params := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeBasicAuthSignup, + Subject: "Test Subject", + Template: "", + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, params) + require.Error(t, err) + require.Nil(t, resp) + }) + + t.Run("should fail with whitespace-only template", func(t *testing.T) { + params := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeBasicAuthSignup, + Subject: "Test Subject", + Template: " ", + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, params) + require.Error(t, err) + require.Nil(t, resp) + }) + + t.Run("should add email template with design", func(t *testing.T) { + // First clean up any existing template + existingTemplate, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeMagicLinkLogin) + if err == nil && existingTemplate != nil { + err = ts.StorageProvider.DeleteEmailTemplate(ctx, existingTemplate) + require.NoError(t, err) + } + + params := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeMagicLinkLogin, + Subject: "Login with Magic Link", + Template: "Click this link to login: {{.URL}}", + Design: refs.NewStringRef("custom design"), + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, params) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "Email template added successfully") + + // Verify template was saved + template, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeMagicLinkLogin) + require.NoError(t, err) + require.NotNil(t, template) + assert.Equal(t, params.EventName, template.EventName) + assert.Equal(t, params.Subject, template.Subject) + assert.Equal(t, params.Template, template.Template) + }) + + t.Run("should add email template without design", func(t *testing.T) { + // First clean up any existing template + existingTemplate, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeOTP) + if err == nil && existingTemplate != nil { + err = ts.StorageProvider.DeleteEmailTemplate(ctx, existingTemplate) + require.NoError(t, err) + } + + params := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeOTP, + Subject: "Your OTP Code", + Template: "Your OTP code is: {{.OTP}}", + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, params) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "Email template added successfully") + + // Verify template was saved + template, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeOTP) + require.NoError(t, err) + require.NotNil(t, template) + assert.Equal(t, params.EventName, template.EventName) + assert.Equal(t, params.Subject, template.Subject) + assert.Equal(t, params.Template, template.Template) + assert.Equal(t, "", template.Design) + }) + + t.Run("should add email template with empty design string", func(t *testing.T) { + // First clean up any existing template + existingTemplate, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeForgotPassword) + if err == nil && existingTemplate != nil { + err = ts.StorageProvider.DeleteEmailTemplate(ctx, existingTemplate) + require.NoError(t, err) + } + + params := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeForgotPassword, + Subject: "Reset Your Password", + Template: "Click here to reset your password: {{.URL}}", + Design: refs.NewStringRef(""), + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, params) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "Email template added successfully") + + // Verify template was saved + template, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeForgotPassword) + require.NoError(t, err) + require.NotNil(t, template) + assert.Equal(t, params.EventName, template.EventName) + assert.Equal(t, params.Subject, template.Subject) + assert.Equal(t, params.Template, template.Template) + assert.Equal(t, "", template.Design) + }) +} diff --git a/internal/integration_tests/add_webhook_test.go b/internal/integration_tests/add_webhook_test.go new file mode 100644 index 000000000..c60796aa3 --- /dev/null +++ b/internal/integration_tests/add_webhook_test.go @@ -0,0 +1,116 @@ +package integration_tests + +import ( + "fmt" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestAddWebhookTest tests the add webhook functionality by the admin +func TestAddWebhookTest(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "add_webhook_user_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + require.NotNil(t, signupRes.User) + + t.Run("should fail without admin cookie", func(t *testing.T) { + addedWebhook, err := ts.GraphQLProvider.AddWebhook(ctx, &model.AddWebhookRequest{ + EventName: "test", + EventDescription: refs.NewStringRef("test"), + Endpoint: "test", + Enabled: false, + Headers: map[string]any{ + "test": "test", + }, + }) + require.Error(t, err) + require.Nil(t, addedWebhook) + }) + + t.Run("should fail with blank event name", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + addedWebhook, err := ts.GraphQLProvider.AddWebhook(ctx, &model.AddWebhookRequest{ + EventName: "", + EventDescription: refs.NewStringRef("test"), + Endpoint: "test", + Enabled: false, + Headers: map[string]any{ + "test": "test", + }, + }) + require.Error(t, err) + require.Nil(t, addedWebhook) + }) + + t.Run("should fail with blank endpoint", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + addedWebhook, err := ts.GraphQLProvider.AddWebhook(ctx, &model.AddWebhookRequest{ + EventName: "test", + EventDescription: refs.NewStringRef("test"), + Endpoint: "", + Enabled: false, + Headers: map[string]any{ + "test": "test", + }, + }) + require.Error(t, err) + require.Nil(t, addedWebhook) + }) + + t.Run("should add webhook", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + addedWebhook, err := ts.GraphQLProvider.AddWebhook(ctx, &model.AddWebhookRequest{ + EventName: constants.UserCreatedWebhookEvent, + EventDescription: refs.NewStringRef("test"), + Endpoint: "test", + Enabled: false, + Headers: map[string]any{ + "test": "test", + }, + }) + require.NoError(t, err) + assert.NotNil(t, addedWebhook) + + res, err := ts.StorageProvider.GetWebhookByEventName(ctx, constants.UserCreatedWebhookEvent) + require.NoError(t, err) + assert.NotNil(t, res) + assert.Equal(t, 1, len(res)) + assert.Equal(t, "test", res[0].EventDescription) + assert.Equal(t, "test", res[0].EndPoint) + assert.Equal(t, false, res[0].Enabled) + assert.Equal(t, "{\"test\":\"test\"}", res[0].Headers) + assert.NotNil(t, res[0].ID) + assert.NotNil(t, res[0].CreatedAt) + assert.NotNil(t, res[0].UpdatedAt) + assert.NotNil(t, res[0].Key) + }) +} diff --git a/internal/integration_tests/admin_login_test.go b/internal/integration_tests/admin_login_test.go new file mode 100644 index 000000000..5f61beb73 --- /dev/null +++ b/internal/integration_tests/admin_login_test.go @@ -0,0 +1,35 @@ +package integration_tests + +import ( + "testing" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestAdminLogin tests the login functionality of the Authorizer application admin. +func TestAdminLogin(t *testing.T) { + // Initialize test setup + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + t.Run("should fail login with invalid admin secret", func(t *testing.T) { + adminLoginReq := &model.AdminLoginRequest{ + AdminSecret: "invalid_secret", + } + adminLoginRes, err := ts.GraphQLProvider.AdminLogin(ctx, adminLoginReq) + require.Error(t, err) + assert.Nil(t, adminLoginRes) + }) + + t.Run("should complete admin login", func(t *testing.T) { + adminLoginReq := &model.AdminLoginRequest{ + AdminSecret: cfg.AdminSecret, + } + res, err := ts.GraphQLProvider.AdminLogin(ctx, adminLoginReq) + require.NoError(t, err) + assert.NotNil(t, res) + }) +} diff --git a/internal/integration_tests/admin_logout_test.go b/internal/integration_tests/admin_logout_test.go new file mode 100644 index 000000000..5321f86f6 --- /dev/null +++ b/internal/integration_tests/admin_logout_test.go @@ -0,0 +1,33 @@ +package integration_tests + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" +) + +// TestAdminLogout tests the logout functionality of the Authorizer application admin. +func TestAdminLogout(t *testing.T) { + // Initialize test setup + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + t.Run("should complete admin login", func(t *testing.T) { + _, err := ts.GraphQLProvider.AdminLogout(ctx) + require.NotNil(t, err) + + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + res, err := ts.GraphQLProvider.AdminLogout(ctx) + require.Nil(t, err) + assert.NotNil(t, res) + }) +} diff --git a/internal/integration_tests/deactivate_account_test.go b/internal/integration_tests/deactivate_account_test.go new file mode 100644 index 000000000..12fe511a1 --- /dev/null +++ b/internal/integration_tests/deactivate_account_test.go @@ -0,0 +1,76 @@ +package integration_tests + +import ( + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// TestDeactivateAccount tests the account deactivation functionality. +func TestDeactivateAccount(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + // Create a test user and login to get tokens + email := "deactivate_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, signupRes) + assert.Equal(t, email, *signupRes.User.Email) + assert.NotEmpty(t, *signupRes.AccessToken) + + // Login to get fresh tokens + loginReq := &model.LoginRequest{ + Email: &email, + Password: password, + } + loginRes, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.NoError(t, err) + assert.NotNil(t, loginRes) + assert.NotEmpty(t, *loginRes.AccessToken) + + // Test cases + t.Run("should fail deactivate account without access token", func(t *testing.T) { + // Clear any existing authorization header + ts.GinContext.Request.Header.Set("Authorization", "") + deactivateRes, err := ts.GraphQLProvider.DeactivateAccount(ctx) + assert.Error(t, err) + assert.Nil(t, deactivateRes) + }) + + t.Run("should fail deactivate account with invalid access token", func(t *testing.T) { + // Set an invalid token + ts.GinContext.Request.Header.Set("Authorization", "Bearer invalid_token") + deactivateRes, err := ts.GraphQLProvider.DeactivateAccount(ctx) + assert.Error(t, err) + assert.Nil(t, deactivateRes) + }) + + t.Run("should deactivate account successfully", func(t *testing.T) { + // Set the valid token + ts.GinContext.Request.Header.Set("Authorization", "Bearer "+*loginRes.AccessToken) + deactivateRes, err := ts.GraphQLProvider.DeactivateAccount(ctx) + + assert.NoError(t, err) + assert.NotNil(t, deactivateRes) + + t.Run("should fail login after deactivation", func(t *testing.T) { + // Attempt to login with the deactivated account + loginRes, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.Error(t, err) + assert.Nil(t, loginRes) + }) + }) +} diff --git a/internal/integration_tests/delete_email_template_test.go b/internal/integration_tests/delete_email_template_test.go new file mode 100644 index 000000000..70120cbd9 --- /dev/null +++ b/internal/integration_tests/delete_email_template_test.go @@ -0,0 +1,230 @@ +package integration_tests + +import ( + "fmt" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestDeleteEmailTemplate tests the delete email template functionality +func TestDeleteEmailTemplate(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "delete_email_template_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + + // Test without admin cookie first + t.Run("should fail without admin cookie", func(t *testing.T) { + deleteParams := &model.DeleteEmailTemplateRequest{ + ID: "some-id", + } + + resp, err := ts.GraphQLProvider.DeleteEmailTemplate(ctx, deleteParams) + require.Error(t, err) + require.Nil(t, resp) + assert.Contains(t, err.Error(), "unauthorized") + }) + + // Add admin cookie for the rest of the tests + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + + t.Run("should fail with empty ID", func(t *testing.T) { + deleteParams := &model.DeleteEmailTemplateRequest{ + ID: "", + } + + resp, err := ts.GraphQLProvider.DeleteEmailTemplate(ctx, deleteParams) + require.Error(t, err) + require.Nil(t, resp) + assert.Contains(t, err.Error(), "email template ID required") + }) + + t.Run("should fail with whitespace-only ID", func(t *testing.T) { + deleteParams := &model.DeleteEmailTemplateRequest{ + ID: " ", + } + + resp, err := ts.GraphQLProvider.DeleteEmailTemplate(ctx, deleteParams) + require.Error(t, err) + require.Nil(t, resp) + assert.Contains(t, err.Error(), "email template ID required") + }) + + t.Run("should fail for non-existent template", func(t *testing.T) { + nonExistentID := uuid.New().String() + deleteParams := &model.DeleteEmailTemplateRequest{ + ID: nonExistentID, + } + + resp, err := ts.GraphQLProvider.DeleteEmailTemplate(ctx, deleteParams) + require.Error(t, err) + require.Nil(t, resp) + // The error message may vary depending on the storage implementation + assert.NotEmpty(t, err.Error()) + }) + + // First create a template to test deletion + var templateID string + t.Run("setup - create template for deletion", func(t *testing.T) { + // Clean up any existing template + existingTemplate, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeInviteMember) + if err == nil && existingTemplate != nil { + err = ts.StorageProvider.DeleteEmailTemplate(ctx, existingTemplate) + require.NoError(t, err) + } + + // Create a new template + addParams := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeInviteMember, + Subject: "Invitation to Join", + Template: "You've been invited to join our platform: {{.URL}}", + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, addParams) + require.NoError(t, err) + require.NotNil(t, resp) + + // Get the created template to get its ID + template, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeInviteMember) + require.NoError(t, err) + require.NotNil(t, template) + templateID = template.ID + }) + + t.Run("should successfully delete template", func(t *testing.T) { + deleteParams := &model.DeleteEmailTemplateRequest{ + ID: templateID, + } + + resp, err := ts.GraphQLProvider.DeleteEmailTemplate(ctx, deleteParams) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "Email templated deleted successfully") + + // Verify the template was deleted + template, err := ts.StorageProvider.GetEmailTemplateByID(ctx, templateID) + assert.Error(t, err) // Should get an error because template should be gone + assert.Nil(t, template) + }) + + t.Run("should fail when trying to delete already deleted template", func(t *testing.T) { + // Try to delete the same template again + deleteParams := &model.DeleteEmailTemplateRequest{ + ID: templateID, + } + + resp, err := ts.GraphQLProvider.DeleteEmailTemplate(ctx, deleteParams) + require.Error(t, err) + require.Nil(t, resp) + // The error message may vary depending on the storage implementation + assert.NotEmpty(t, err.Error()) + }) + + // Test with multiple email templates + var template1ID, template2ID string + t.Run("setup - create multiple templates", func(t *testing.T) { + // First, clean up any existing templates with these event names + existingTemplate1, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeBasicAuthSignup) + if err == nil && existingTemplate1 != nil { + err = ts.StorageProvider.DeleteEmailTemplate(ctx, existingTemplate1) + require.NoError(t, err) + } + + existingTemplate2, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeForgotPassword) + if err == nil && existingTemplate2 != nil { + err = ts.StorageProvider.DeleteEmailTemplate(ctx, existingTemplate2) + require.NoError(t, err) + } + + // Create first template + addParams1 := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeBasicAuthSignup, + Subject: "Verify Your Signup", + Template: "Please verify your signup: {{.URL}}", + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, addParams1) + require.NoError(t, err) + require.NotNil(t, resp) + + template1, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeBasicAuthSignup) + require.NoError(t, err) + require.NotNil(t, template1) + template1ID = template1.ID + + // Create second template + addParams2 := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeForgotPassword, + Subject: "Password Reset", + Template: "Please reset your password: {{.URL}}", + } + + resp, err = ts.GraphQLProvider.AddEmailTemplate(ctx, addParams2) + require.NoError(t, err) + require.NotNil(t, resp) + + template2, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeForgotPassword) + require.NoError(t, err) + require.NotNil(t, template2) + template2ID = template2.ID + }) + + t.Run("should delete first template without affecting second", func(t *testing.T) { + deleteParams := &model.DeleteEmailTemplateRequest{ + ID: template1ID, + } + + resp, err := ts.GraphQLProvider.DeleteEmailTemplate(ctx, deleteParams) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "Email templated deleted successfully") + + // First template should be gone + template1, err := ts.StorageProvider.GetEmailTemplateByID(ctx, template1ID) + assert.Error(t, err) + assert.Nil(t, template1) + + // Second template should still exist + template2, err := ts.StorageProvider.GetEmailTemplateByID(ctx, template2ID) + assert.NoError(t, err) + assert.NotNil(t, template2) + assert.Equal(t, constants.VerificationTypeForgotPassword, template2.EventName) + }) + + t.Run("should delete second template", func(t *testing.T) { + deleteParams := &model.DeleteEmailTemplateRequest{ + ID: template2ID, + } + + resp, err := ts.GraphQLProvider.DeleteEmailTemplate(ctx, deleteParams) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "Email templated deleted successfully") + + // Second template should now be gone + template2, err := ts.StorageProvider.GetEmailTemplateByID(ctx, template2ID) + assert.Error(t, err) + assert.Nil(t, template2) + }) +} diff --git a/internal/integration_tests/delete_user_test.go b/internal/integration_tests/delete_user_test.go new file mode 100644 index 000000000..32a61e79d --- /dev/null +++ b/internal/integration_tests/delete_user_test.go @@ -0,0 +1,51 @@ +package integration_tests + +import ( + "fmt" + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// TestDeleteUser tests the delete user functionality by the admin +func TestDeleteUser(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "delete_user_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + require.NotNil(t, signupRes.User) + + t.Run("should fail without admin cookie", func(t *testing.T) { + deleteRes, err := ts.GraphQLProvider.DeleteUser(ctx, &model.DeleteUserRequest{Email: email}) + require.Error(t, err) + require.Nil(t, deleteRes) + }) + + t.Run("should delete user", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + deleteRes, err := ts.GraphQLProvider.DeleteUser(ctx, &model.DeleteUserRequest{Email: email}) + require.NoError(t, err) + require.NotNil(t, deleteRes) + }) +} diff --git a/internal/integration_tests/delete_webhook_test.go b/internal/integration_tests/delete_webhook_test.go new file mode 100644 index 000000000..ec31f9a51 --- /dev/null +++ b/internal/integration_tests/delete_webhook_test.go @@ -0,0 +1,135 @@ +package integration_tests + +import ( + "fmt" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestDeleteWebhookTest tests the delete webhook functionality by the admin +func TestDeleteWebhookTest(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "delete_webhook_user_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + require.NotNil(t, signupRes.User) + + // First add a webhook to delete + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + + eventNameToDelete := constants.UserCreatedWebhookEvent + eventNameToPersist := constants.UserLoginWebhookEvent + + addedWebhook, err := ts.GraphQLProvider.AddWebhook(ctx, &model.AddWebhookRequest{ + EventName: eventNameToDelete, + EventDescription: refs.NewStringRef("webhook to be deleted"), + Endpoint: "http://webhook-to-delete.com", + Enabled: true, + Headers: map[string]any{ + "Content-Type": "application/json", + }, + }) + require.NoError(t, err) + assert.NotNil(t, addedWebhook) + + // Get the webhook to delete + webhooks, err := ts.StorageProvider.GetWebhookByEventName(ctx, eventNameToDelete) + require.NoError(t, err) + require.NotEmpty(t, webhooks) + webhookID := webhooks[0].ID + + // Create another webhook that won't be deleted (to verify we're not deleting all webhooks) + persistentWebhook, err := ts.GraphQLProvider.AddWebhook(ctx, &model.AddWebhookRequest{ + EventName: eventNameToPersist, + EventDescription: refs.NewStringRef("webhook that should persist"), + Endpoint: "http://persistent-webhook.com", + Enabled: true, + }) + require.NoError(t, err) + assert.NotNil(t, persistentWebhook) + + t.Run("should fail without admin cookie", func(t *testing.T) { + // Remove admin cookie + req.Header.Del("Cookie") + + resp, err := ts.GraphQLProvider.DeleteWebhook(ctx, &model.WebhookRequest{ + ID: webhookID, + }) + require.Error(t, err) + require.Nil(t, resp) + }) + + // Re-add the admin cookie for the rest of the tests + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + + t.Run("should fail with invalid webhook ID", func(t *testing.T) { + resp, err := ts.GraphQLProvider.DeleteWebhook(ctx, &model.WebhookRequest{ + ID: uuid.NewString(), + }) + require.Error(t, err) + require.Nil(t, resp) + }) + + t.Run("should fail with blank webhook ID", func(t *testing.T) { + resp, err := ts.GraphQLProvider.DeleteWebhook(ctx, &model.WebhookRequest{ + ID: "", + }) + require.Error(t, err) + require.Nil(t, resp) + }) + + t.Run("should delete webhook successfully", func(t *testing.T) { + // Verify webhook exists before deletion + webhookBeforeDelete, err := ts.StorageProvider.GetWebhookByID(ctx, webhookID) + require.NoError(t, err) + require.NotNil(t, webhookBeforeDelete) + + // Delete the webhook + resp, err := ts.GraphQLProvider.DeleteWebhook(ctx, &model.WebhookRequest{ + ID: webhookID, + }) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "successfully") + + // Verify webhook was deleted + webhookAfterDelete, err := ts.StorageProvider.GetWebhookByID(ctx, webhookID) + require.Error(t, err) // Should error because webhook no longer exists + require.Nil(t, webhookAfterDelete) + + // Verify other webhooks still exist + persistentWebhooks, err := ts.StorageProvider.GetWebhookByEventName(ctx, eventNameToPersist) + require.NoError(t, err) + require.NotEmpty(t, persistentWebhooks) + }) + + t.Run("should fail to delete already deleted webhook", func(t *testing.T) { + // Try to delete the same webhook again + resp, err := ts.GraphQLProvider.DeleteWebhook(ctx, &model.WebhookRequest{ + ID: webhookID, + }) + require.Error(t, err) + require.Nil(t, resp) + }) +} diff --git a/internal/integration_tests/enable_access_test.go b/internal/integration_tests/enable_access_test.go new file mode 100644 index 000000000..f4ba6d09b --- /dev/null +++ b/internal/integration_tests/enable_access_test.go @@ -0,0 +1,76 @@ +package integration_tests + +import ( + "fmt" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestEnableAccessUser tests the enable access functionality by the admin +func TestEnableAccessUser(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "enable_access_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + require.NotNil(t, signupRes.User) + + t.Run("should fail without admin cookie", func(t *testing.T) { + revokedUserDets, err := ts.GraphQLProvider.EnableAccess(ctx, &model.UpdateAccessRequest{ + UserID: signupRes.User.ID, + }) + require.Error(t, err) + require.Nil(t, revokedUserDets) + }) + + t.Run("should fail with blank userid", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + _, err = ts.GraphQLProvider.EnableAccess(ctx, &model.UpdateAccessRequest{ + UserID: "", + }) + require.Error(t, err) + }) + + t.Run("should fail with unknown userid", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + _, err = ts.GraphQLProvider.EnableAccess(ctx, &model.UpdateAccessRequest{ + UserID: uuid.NewString(), + }) + require.Error(t, err) + }) + + t.Run("should enable access user", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + enableAccessDets, err := ts.GraphQLProvider.EnableAccess(ctx, &model.UpdateAccessRequest{ + UserID: signupRes.User.ID, + }) + require.NoError(t, err) + assert.NotNil(t, enableAccessDets) + }) +} diff --git a/internal/integration_tests/forgot_password_test.go b/internal/integration_tests/forgot_password_test.go new file mode 100644 index 000000000..6b8e21255 --- /dev/null +++ b/internal/integration_tests/forgot_password_test.go @@ -0,0 +1,60 @@ +package integration_tests + +import ( + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +// TestForgotPassword tests the forgot password functionality +func TestForgotPassword(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + // Create a test user + email := "forgot_password_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, signupRes) + assert.NotNil(t, signupRes.User) + + // Create forgot password request + t.Run("should fail for invalid email", func(t *testing.T) { + forgotPasswordReq := &model.ForgotPasswordRequest{ + Email: refs.NewStringRef("invalid-email@gmail.com"), + } + forgotPasswordRes, err := ts.GraphQLProvider.ForgotPassword(ctx, forgotPasswordReq) + assert.Error(t, err) + assert.Nil(t, forgotPasswordRes) + }) + + t.Run("should send forgot password email", func(t *testing.T) { + forgotPasswordReq := &model.ForgotPasswordRequest{ + Email: refs.NewStringRef(email), + } + forgotPasswordRes, err := ts.GraphQLProvider.ForgotPassword(ctx, forgotPasswordReq) + assert.NoError(t, err) + assert.NotNil(t, forgotPasswordRes) + assert.NotEmpty(t, forgotPasswordRes.Message) + + // Validate if the entry is created in db + request, err := ts.StorageProvider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeForgotPassword) + assert.NoError(t, err) + assert.NotNil(t, request) + assert.NotEmpty(t, request.Token) + assert.Equal(t, email, request.Email) + }) +} diff --git a/internal/integration_tests/invite_members_test.go b/internal/integration_tests/invite_members_test.go new file mode 100644 index 000000000..a90ee1d2e --- /dev/null +++ b/internal/integration_tests/invite_members_test.go @@ -0,0 +1,90 @@ +package integration_tests + +import ( + "fmt" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestInviteMembersUser tests the invite user functionality by the admin +func TestInviteMembersUser(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "invite_user_test_" + uuid.New().String() + "@authorizer.dev" + emailTo := "test_user_invitation_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + url := "https://authorizer.dev/" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + require.NotNil(t, signupRes.User) + + t.Run("should fail without admin cookie", func(t *testing.T) { + invitedUserDets, err := ts.GraphQLProvider.InviteMembers(ctx, &model.InviteMemberRequest{ + Emails: []string{emailTo}, + RedirectURI: &url, + }) + require.Error(t, err) + require.Nil(t, invitedUserDets) + }) + + t.Run("should fail to invite user as email sending is disabled", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + _, err = ts.GraphQLProvider.InviteMembers(ctx, &model.InviteMemberRequest{ + Emails: []string{emailTo}, + RedirectURI: &url, + }) + require.Error(t, err) + }) + + t.Run("should fail to invite user as email is blank", func(t *testing.T) { + cfg.IsEmailServiceEnabled = true + cfg.EnableBasicAuthentication = true + cfg.EnableMagicLinkLogin = true + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + _, err = ts.GraphQLProvider.InviteMembers(ctx, &model.InviteMemberRequest{ + Emails: []string{}, + RedirectURI: &url, + }) + require.Error(t, err) + }) + + t.Run("should invite user as email sending is enabled", func(t *testing.T) { + cfg.IsEmailServiceEnabled = true + cfg.EnableBasicAuthentication = true + cfg.EnableMagicLinkLogin = true + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + invitedUserDets, err := ts.GraphQLProvider.InviteMembers(ctx, &model.InviteMemberRequest{ + Emails: []string{emailTo}, + RedirectURI: &url, + }) + require.NoError(t, err) + for _, user := range invitedUserDets.Users { + assert.Equal(t, *user.Email, emailTo) + } + }) +} diff --git a/internal/integration_tests/login_test.go b/internal/integration_tests/login_test.go new file mode 100644 index 000000000..c4374744f --- /dev/null +++ b/internal/integration_tests/login_test.go @@ -0,0 +1,101 @@ +package integration_tests + +import ( + "fmt" + "testing" + "time" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +// TestLogin tests the login functionality of the Authorizer application. +func TestLogin(t *testing.T) { + // Initialize test setup + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + // Test setup - create a test user + email := "login_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, res) + + // Login tests + t.Run("should fail login with invalid email", func(t *testing.T) { + invalidEmail := "invalid@email.com" + loginReq := &model.LoginRequest{ + Email: &invalidEmail, + Password: password, + } + res, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should fail login with invalid password", func(t *testing.T) { + loginReq := &model.LoginRequest{ + Email: &email, + Password: "WrongPassword@123", + } + res, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should login successfully with valid credentials", func(t *testing.T) { + loginReq := &model.LoginRequest{ + Email: &email, + Password: password, + } + res, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.NoError(t, err) + assert.NotNil(t, res) + + // Verify response contains expected tokens + assert.NotEmpty(t, res.AccessToken) + assert.NotNil(t, res.User) + assert.Equal(t, email, *res.User.Email) + assert.True(t, res.User.EmailVerified) + }) + + t.Run("should fail login with empty credentials", func(t *testing.T) { + loginReq := &model.LoginRequest{} + res, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("mobile login", func(t *testing.T) { + mobile := fmt.Sprintf("%d", time.Now().Add(10*time.Second).Unix()) + signUpReq := &model.SignUpRequest{ + PhoneNumber: &mobile, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signUpReq) + assert.NoError(t, err) + assert.NotNil(t, res) + + // Login + loginReq := &model.LoginRequest{ + PhoneNumber: &mobile, + Password: password, + } + res, err = ts.GraphQLProvider.Login(ctx, loginReq) + assert.NoError(t, err) + assert.NotEmpty(t, res.AccessToken) + assert.NotNil(t, res.User) + assert.Equal(t, mobile, *res.User.PhoneNumber) + assert.True(t, res.User.PhoneNumberVerified) + }) +} diff --git a/internal/integration_tests/logout_test.go b/internal/integration_tests/logout_test.go new file mode 100644 index 000000000..f8477422f --- /dev/null +++ b/internal/integration_tests/logout_test.go @@ -0,0 +1,76 @@ +package integration_tests + +import ( + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// TestLogout tests the logout functionality of the Authorizer application. +func TestLogout(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + // Create a test user and login to get tokens + email := "logout_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, signupRes) + assert.Equal(t, email, *signupRes.User.Email) + assert.NotEmpty(t, *signupRes.AccessToken) + + // Login to get fresh tokens + loginReq := &model.LoginRequest{ + Email: &email, + Password: password, + } + loginRes, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.NoError(t, err) + assert.NotNil(t, loginRes) + assert.NotEmpty(t, *loginRes.AccessToken) + + // Test cases + t.Run("should fail logout without access token", func(t *testing.T) { + // Clear any existing authorization header + ts.GinContext.Request.Header.Set("Authorization", "") + + logoutRes, err := ts.GraphQLProvider.Logout(ctx) + assert.Error(t, err) + assert.Nil(t, logoutRes) + }) + + t.Run("should fail logout with invalid access token", func(t *testing.T) { + // Set an invalid token + ts.GinContext.Request.Header.Set("Authorization", "Bearer invalid_token") + + logoutRes, err := ts.GraphQLProvider.Logout(ctx) + assert.Error(t, err) + assert.Nil(t, logoutRes) + }) + + t.Run("should successfully logout with valid access token", func(t *testing.T) { + // Set the valid access token + ts.GinContext.Request.Header.Set("Authorization", "Bearer "+*loginRes.AccessToken) + logoutRes, err := ts.GraphQLProvider.Logout(ctx) + assert.NoError(t, err) + assert.NotNil(t, logoutRes) + assert.NotNil(t, logoutRes.Message) + + // Try to access a protected endpoint with the same token + profile, err := ts.GraphQLProvider.Profile(ctx) + assert.Error(t, err) + assert.Nil(t, profile) + }) +} diff --git a/internal/integration_tests/magic_link_login_test.go b/internal/integration_tests/magic_link_login_test.go new file mode 100644 index 000000000..a303a07a8 --- /dev/null +++ b/internal/integration_tests/magic_link_login_test.go @@ -0,0 +1,72 @@ +package integration_tests + +import ( + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// TestMagicLinkLogin tests the magic link login functionality of the Authorizer application. +func TestMagicLinkLogin(t *testing.T) { + cfg := getTestConfig() + cfg.EnableMagicLinkLogin = true + cfg.SMTPHost = "localhost" + cfg.SMTPPort = 1025 + cfg.SMTPSenderEmail = "test@authorizer.dev" + cfg.SMTPSenderName = "Test" + cfg.SMTPLocalName = "Test" + cfg.SkipTLSVerification = true + cfg.IsEmailServiceEnabled = true + cfg.IsSMSServiceEnabled = true + cfg.EnableEmailVerification = true + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + email := "magic_link_user" + uuid.New().String() + "@authorizer.dev" + + t.Run("should fail for missing email", func(t *testing.T) { + loginReq := &model.MagicLinkLoginRequest{} + res, err := ts.GraphQLProvider.MagicLinkLogin(ctx, loginReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + t.Run("should fail for invalid email", func(t *testing.T) { + loginReq := &model.MagicLinkLoginRequest{ + Email: "invalid-email", + } + res, err := ts.GraphQLProvider.MagicLinkLogin(ctx, loginReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + t.Run("should pass for valid email", func(t *testing.T) { + res, err := ts.GraphQLProvider.MagicLinkLogin(ctx, &model.MagicLinkLoginRequest{ + Email: email, + }) + assert.NoError(t, err) + assert.NotNil(t, res) + assert.NotEmpty(t, res.Message) + + verificationRequest, err := ts.StorageProvider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin) + assert.NoError(t, err) + assert.NotNil(t, verificationRequest) + verifyRes, err := ts.GraphQLProvider.VerifyEmail(ctx, &model.VerifyEmailRequest{ + Token: verificationRequest.Token, + }) + assert.NoError(t, err) + assert.NotEmpty(t, *verifyRes.AccessToken) + + // Set the Authorization header for the Profile request + ts.GinContext.Request.Header.Set("Authorization", "Bearer "+*verifyRes.AccessToken) + + profile, err := ts.GraphQLProvider.Profile(ctx) + assert.Nil(t, err) + assert.NotNil(t, profile) + + // Clean up the header after the test + ts.GinContext.Request.Header.Set("Authorization", "") + }) +} diff --git a/internal/integration_tests/profile_test.go b/internal/integration_tests/profile_test.go new file mode 100644 index 000000000..a206ff507 --- /dev/null +++ b/internal/integration_tests/profile_test.go @@ -0,0 +1,97 @@ +package integration_tests + +import ( + "fmt" + "strings" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestProfile tests the profile functionality +func TestProfile(t *testing.T) { + // Initialize test setup + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Test setup - create a test user + email := "profile_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, res) + + // Profile tests + t.Run("after login", func(t *testing.T) { + loginReq := &model.LoginRequest{ + Email: &email, + Password: password, + } + loginRes, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.NoError(t, err) + assert.NotNil(t, loginRes) + + // Verify response contains expected tokens + assert.NotEmpty(t, loginRes.AccessToken) + assert.NotNil(t, loginRes.User) + assert.Equal(t, email, *loginRes.User.Email) + assert.True(t, loginRes.User.EmailVerified) + + t.Run("should fail without cookie and authorization header", func(t *testing.T) { + res, err := ts.GraphQLProvider.Profile(ctx) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should return profile with browser session", func(t *testing.T) { + allData, err := ts.MemoryStoreProvider.GetAllData() + require.NoError(t, err) + sessionToken := "" + for k, v := range allData { + if strings.Contains(k, constants.TokenTypeSessionToken) { + sessionToken = v + break + } + } + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AppCookieName+"_session", sessionToken)) + defer func() { + req.Header.Del("Cookie") + }() + res, err := ts.GraphQLProvider.Profile(ctx) + require.NoError(t, err) + require.NotNil(t, res) + assert.Equal(t, email, *res.Email) + }) + + t.Run("should return profile with authorization header", func(t *testing.T) { + allData, err := ts.MemoryStoreProvider.GetAllData() + require.NoError(t, err) + accessToken := "" + for k, v := range allData { + if strings.Contains(k, constants.TokenTypeAccessToken) { + accessToken = v + break + } + } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) + defer func() { + req.Header.Del("Authorization") + }() + res, err := ts.GraphQLProvider.Profile(ctx) + require.NoError(t, err) + require.NotNil(t, res) + assert.Equal(t, email, *res.Email) + }) + }) +} diff --git a/internal/integration_tests/resend_otp_test.go b/internal/integration_tests/resend_otp_test.go new file mode 100644 index 000000000..066cc9528 --- /dev/null +++ b/internal/integration_tests/resend_otp_test.go @@ -0,0 +1,117 @@ +package integration_tests + +import ( + "fmt" + "strings" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestResendOTP tests the resend verify OTP functionality +func TestResendOTP(t *testing.T) { + cfg := getTestConfig() + cfg.IsSMSServiceEnabled = true + cfg.EnableEmailOTP = true + cfg.EnableSMSOTP = true + cfg.EnablePhoneVerification = true + cfg.EnableMobileBasicAuthentication = true + cfg.EnableMFA = true + cfg.SMTPHost = "localhost" + cfg.SMTPPort = 1025 + cfg.SMTPSenderEmail = "test@authorizer.dev" + cfg.SMTPSenderName = "Test" + cfg.SMTPLocalName = "Test" + cfg.SkipTLSVerification = true + cfg.IsEmailServiceEnabled = true + cfg.IsSMSServiceEnabled = true + cfg.EnableEmailVerification = true + cfg.TwilioAPISecret = "test-twilio-api-secret" + cfg.TwilioAPIKey = "test-twilio-api-key" + cfg.TwilioAccountSID = "test-twilio-account-sid" + cfg.TwilioSender = "test-twilio-sender" + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + mobile := "+14155552672" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + PhoneNumber: &mobile, + Password: password, + ConfirmPassword: password, + } + + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, signupRes) + // Expect the user to be nil, as the email is not verified yet + assert.Nil(t, signupRes.User) + + // Get the OTP from db + otpData, err := ts.StorageProvider.GetOTPByPhoneNumber(ctx, mobile) + require.NoError(t, err) + assert.NotNil(t, otpData) + // User + userData, err := ts.StorageProvider.GetUserByPhoneNumber(ctx, mobile) + require.NoError(t, err) + assert.NotNil(t, userData) + + t.Run("should fail if request for given email or phone number does not exists", func(t *testing.T) { + resendReq := &model.ResendOTPRequest{ + PhoneNumber: refs.NewStringRef("2131231212"), + } + resendRes, err := ts.GraphQLProvider.ResendOTP(ctx, resendReq) + assert.Error(t, err) + assert.Nil(t, resendRes) + }) + t.Run("should send resend request{mobile}", func(t *testing.T) { + resendReq := &model.ResendOTPRequest{ + PhoneNumber: refs.NewStringRef(mobile), + } + resendRes, err := ts.GraphQLProvider.ResendOTP(ctx, resendReq) + assert.NoError(t, err) + assert.NotNil(t, resendRes) + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.MfaCookieName+"_session", constants.TestEnv)) + t.Run("old OTP should be invalidated", func(t *testing.T) { + verificationReq := &model.VerifyOTPRequest{ + PhoneNumber: &mobile, + Otp: otpData.Otp, + } + verificationRes, err := ts.GraphQLProvider.VerifyOTP(ctx, verificationReq) + assert.Error(t, err) + assert.Nil(t, verificationRes) + }) + t.Run("should verify OTP", func(t *testing.T) { + // Get MFA session cookie + allData, err := ts.MemoryStoreProvider.GetAllData() + require.NoError(t, err) + sessionKey := "" + for k := range allData { + if strings.Contains(k, userData.ID) { + splitData := strings.Split(k, ":") + if len(splitData) > 1 { + sessionKey = splitData[1] + break + } + } + } + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.MfaCookieName+"_session", sessionKey)) + newOtpData, err := ts.StorageProvider.GetOTPByPhoneNumber(ctx, mobile) + require.NoError(t, err) + assert.NotNil(t, newOtpData) + verificationReq := &model.VerifyOTPRequest{ + PhoneNumber: &mobile, + Otp: newOtpData.Otp, + } + verificationRes, err := ts.GraphQLProvider.VerifyOTP(ctx, verificationReq) + require.NoError(t, err) + assert.NotNil(t, verificationRes) + }) + }) +} diff --git a/internal/integration_tests/resend_verify_email_test.go b/internal/integration_tests/resend_verify_email_test.go new file mode 100644 index 000000000..34fbe6f5c --- /dev/null +++ b/internal/integration_tests/resend_verify_email_test.go @@ -0,0 +1,80 @@ +package integration_tests + +import ( + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +// TestResendVerifyEmail tests the resend verify email functionality +func TestResendVerifyEmail(t *testing.T) { + cfg := getTestConfig() + cfg.IsEmailServiceEnabled = true + cfg.EnableEmailVerification = true + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + // Create a test user + email := "resend_verify_email_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, signupRes) + // Expect the user to be nil, as the email is not verified yet + assert.Nil(t, signupRes.User) + + t.Run("should fail for invalid token", func(t *testing.T) { + verificationReq := &model.VerifyEmailRequest{ + Token: "invalid-token", + } + verificationRes, err := ts.GraphQLProvider.VerifyEmail(ctx, verificationReq) + assert.Error(t, err) + assert.Nil(t, verificationRes) + }) + + t.Run("should resend verify email", func(t *testing.T) { + // Get the verification token from db + request, err := ts.StorageProvider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) + assert.NoError(t, err) + assert.NotNil(t, request) + assert.NotEmpty(t, request.Token) + + // Verify email with an invalid token + verificationReq := &model.ResendVerifyEmailRequest{ + Email: email, + Identifier: constants.VerificationTypeBasicAuthSignup, + } + + res, err := ts.GraphQLProvider.ResendVerifyEmail(ctx, verificationReq) + assert.NoError(t, err) + assert.NotNil(t, res) + + // Check if the verification request has different token + request2, err := ts.StorageProvider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) + assert.NoError(t, err) + assert.NotNil(t, request2) + assert.NotEmpty(t, request2.Token) + assert.NotEqual(t, request.Token, request2.Token) + + // Verify email with the new token + verificationReq2 := &model.VerifyEmailRequest{ + Token: request2.Token, + } + verificationRes, err := ts.GraphQLProvider.VerifyEmail(ctx, verificationReq2) + assert.NoError(t, err) + assert.NotNil(t, verificationRes) + assert.NotNil(t, verificationRes.User) + assert.Equal(t, email, *verificationRes.User.Email) + assert.Equal(t, true, verificationRes.User.EmailVerified) + }) +} diff --git a/internal/integration_tests/reset_password_test.go b/internal/integration_tests/reset_password_test.go new file mode 100644 index 000000000..8db617353 --- /dev/null +++ b/internal/integration_tests/reset_password_test.go @@ -0,0 +1,84 @@ +package integration_tests + +import ( + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +// TestResetPassword tests the reset password functionality +func TestResetPassword(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + // Create a test user + email := "reset_password_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, signupRes) + assert.NotNil(t, signupRes.User) + + // Create forgot password request + t.Run("should fail for invalid request", func(t *testing.T) { + resetPasswordReq := &model.ResetPasswordRequest{ + Token: refs.NewStringRef("test"), + Password: "NewPassword@123", + ConfirmPassword: "NewPassword@123", + } + forgotPasswordRes, err := ts.GraphQLProvider.ResetPassword(ctx, resetPasswordReq) + assert.Error(t, err) + assert.Nil(t, forgotPasswordRes) + }) + + t.Run("should reset password with verification token", func(t *testing.T) { + forgotPasswordReq := &model.ForgotPasswordRequest{ + Email: refs.NewStringRef(email), + } + forgotPasswordRes, err := ts.GraphQLProvider.ForgotPassword(ctx, forgotPasswordReq) + assert.NoError(t, err) + assert.NotNil(t, forgotPasswordRes) + assert.NotEmpty(t, forgotPasswordRes.Message) + + // Validate if the entry is created in db + request, err := ts.StorageProvider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeForgotPassword) + assert.NoError(t, err) + assert.NotNil(t, request) + assert.NotEmpty(t, request.Token) + assert.Equal(t, email, request.Email) + + // Reset password using the token + resetPasswordReq := &model.ResetPasswordRequest{ + Token: refs.NewStringRef(request.Token), + Password: "NewPassword@123", + ConfirmPassword: "NewPassword@123", + } + + resetPasswordRes, err := ts.GraphQLProvider.ResetPassword(ctx, resetPasswordReq) + assert.NoError(t, err) + assert.NotNil(t, resetPasswordRes) + assert.NotEmpty(t, resetPasswordRes.Message) + + // Validate if the password is updated in db by logging in + loginReq := &model.LoginRequest{ + Email: &email, + Password: "NewPassword@123", + } + loginRes, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.NoError(t, err) + assert.NotNil(t, loginRes) + assert.NotNil(t, loginRes.AccessToken) + }) +} diff --git a/internal/integration_tests/revoke_access_test.go b/internal/integration_tests/revoke_access_test.go new file mode 100644 index 000000000..be7d06534 --- /dev/null +++ b/internal/integration_tests/revoke_access_test.go @@ -0,0 +1,76 @@ +package integration_tests + +import ( + "fmt" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestRevokeAccessUser tests the revoke access functionality by the admin +func TestRevokeAccessUser(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "revoke_access_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + require.NotNil(t, signupRes.User) + + t.Run("should fail without admin cookie", func(t *testing.T) { + revokeAccessDets, err := ts.GraphQLProvider.RevokeAccess(ctx, &model.UpdateAccessRequest{ + UserID: signupRes.User.ID, + }) + require.Error(t, err) + require.Nil(t, revokeAccessDets) + }) + + t.Run("should fail with blank userid", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + _, err = ts.GraphQLProvider.RevokeAccess(ctx, &model.UpdateAccessRequest{ + UserID: "", + }) + require.Error(t, err) + }) + + t.Run("should fail with unknown userid", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + _, err = ts.GraphQLProvider.RevokeAccess(ctx, &model.UpdateAccessRequest{ + UserID: uuid.NewString(), + }) + require.Error(t, err) + }) + + t.Run("should revoke access", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + revokeAccessDets, err := ts.GraphQLProvider.RevokeAccess(ctx, &model.UpdateAccessRequest{ + UserID: signupRes.User.ID, + }) + require.NoError(t, err) + assert.NotNil(t, revokeAccessDets) + }) +} diff --git a/internal/integration_tests/revoke_test.go b/internal/integration_tests/revoke_test.go new file mode 100644 index 000000000..f7db4eab3 --- /dev/null +++ b/internal/integration_tests/revoke_test.go @@ -0,0 +1,67 @@ +package integration_tests + +import ( + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/authorizerdev/authorizer/internal/graph/model" +) + +// TestRevoke tests the revoke functionality +func TestRevoke(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + // Create a test user + email := "revoke_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, signupRes) + assert.NotNil(t, signupRes.User) + + // Create forgot password request + t.Run("should fail for invalid session", func(t *testing.T) { + revokeReq := &model.OAuthRevokeRequest{ + RefreshToken: "invalid_token", + } + revokeRes, err := ts.GraphQLProvider.Revoke(ctx, revokeReq) + assert.Error(t, err) + assert.Nil(t, revokeRes) + }) + + t.Run("should revoke", func(t *testing.T) { + // Login request + loginReq := &model.LoginRequest{ + Email: &email, + Password: password, + Scope: []string{"offline_access"}, + } + loginRes, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.NoError(t, err) + assert.NotNil(t, loginRes) + assert.NotEmpty(t, loginRes.RefreshToken) + assert.NotEmpty(t, loginRes.AccessToken) + + // Revoke refresh token + revokeReq := &model.OAuthRevokeRequest{ + RefreshToken: *loginRes.RefreshToken, + } + + revokeRes, err := ts.GraphQLProvider.Revoke(ctx, revokeReq) + require.NoError(t, err) + assert.NotNil(t, revokeRes) + assert.NotEmpty(t, revokeRes.Message) + }) +} diff --git a/internal/integration_tests/session_test.go b/internal/integration_tests/session_test.go new file mode 100644 index 000000000..6615b3a9b --- /dev/null +++ b/internal/integration_tests/session_test.go @@ -0,0 +1,76 @@ +package integration_tests + +import ( + "fmt" + "strings" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestSession tests the session functionality +func TestSession(t *testing.T) { + // Initialize test setup + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Test setup - create a test user + email := "session_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, res) + + // Session tests + t.Run("after login", func(t *testing.T) { + loginReq := &model.LoginRequest{ + Email: &email, + Password: password, + } + loginRes, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.NoError(t, err) + assert.NotNil(t, loginRes) + + // Verify response contains expected tokens + assert.NotEmpty(t, loginRes.AccessToken) + assert.NotNil(t, loginRes.User) + assert.Equal(t, email, *loginRes.User.Email) + assert.True(t, loginRes.User.EmailVerified) + + t.Run("should fail without cookie", func(t *testing.T) { + res, err := ts.GraphQLProvider.Session(ctx, &model.SessionQueryRequest{}) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should return new access token with cookie", func(t *testing.T) { + allData, err := ts.MemoryStoreProvider.GetAllData() + require.NoError(t, err) + sessionToken := "" + for k, v := range allData { + if strings.Contains(k, constants.TokenTypeSessionToken) { + sessionToken = v + break + } + } + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AppCookieName+"_session", sessionToken)) + res, err := ts.GraphQLProvider.Session(ctx, &model.SessionQueryRequest{}) + require.NoError(t, err) + require.NotNil(t, res) + assert.NotEmpty(t, res.AccessToken) + assert.NotEqual(t, res.AccessToken, res.RefreshToken) + assert.Equal(t, email, *res.User.Email) + }) + }) +} diff --git a/internal/integration_tests/signup_test.go b/internal/integration_tests/signup_test.go new file mode 100644 index 000000000..e3515b656 --- /dev/null +++ b/internal/integration_tests/signup_test.go @@ -0,0 +1,141 @@ +package integration_tests + +import ( + "fmt" + "testing" + "time" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +// TestSignup tests the signup functionality of the Authorizer application. +func TestSignup(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + email := "signup_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + t.Run("should fail for missing email or phone number", func(t *testing.T) { + signupReq := &model.SignUpRequest{ + Password: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should fail for missing confirm password", func(t *testing.T) { + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + } + + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should fail for mismatch confirm password", func(t *testing.T) { + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: "test@123", + } + + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should fail for weak password", func(t *testing.T) { + signupReq := &model.SignUpRequest{ + Email: &email, + Password: "test", + ConfirmPassword: "test", + } + + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should fail for invalid email", func(t *testing.T) { + invalidEmail := "test" + signupReq := &model.SignUpRequest{ + Email: &invalidEmail, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should fail for invalid mobile number", func(t *testing.T) { + invalidMobileNumber := "1243234" + signupReq := &model.SignUpRequest{ + PhoneNumber: &invalidMobileNumber, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should pass for valid email", func(t *testing.T) { + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, res) + assert.NotNil(t, res.User) + + t.Run("should fail for duplicate email", func(t *testing.T) { + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + }) + + t.Run("should pass for valid mobile number", func(t *testing.T) { + mobileNumber := fmt.Sprintf("%d", time.Now().Unix()) + signupReq := &model.SignUpRequest{ + PhoneNumber: &mobileNumber, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, res) + // Validate mobile number + assert.Equal(t, mobileNumber, *res.User.PhoneNumber) + assert.True(t, res.User.PhoneNumberVerified) + // Auth formula should be basic auth based on mobile number + assert.Contains(t, constants.AuthRecipeMethodMobileBasicAuth, res.User.SignupMethods) + + t.Run("should fail for duplicate mobile number", func(t *testing.T) { + signupReq := &model.SignUpRequest{ + PhoneNumber: &mobileNumber, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.Error(t, err) + assert.Nil(t, res) + }) + }) +} diff --git a/internal/integration_tests/test_endpoint_test.go b/internal/integration_tests/test_endpoint_test.go new file mode 100644 index 000000000..1c77bc00e --- /dev/null +++ b/internal/integration_tests/test_endpoint_test.go @@ -0,0 +1,223 @@ +package integration_tests + +import ( + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestEndpointTest tests the webhook endpoint testing functionality by the admin +func TestEndpointTest(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "test_endpoint_user_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + require.NotNil(t, signupRes.User) + + // Create a test server to simulate a webhook endpoint + var lastReceivedRequest struct { + EventName string + Headers map[string]string + } + + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Clear the previous request data + lastReceivedRequest = struct { + EventName string + Headers map[string]string + }{ + Headers: make(map[string]string), + } + + // Read request body + decoder := json.NewDecoder(r.Body) + var requestData map[string]interface{} + err := decoder.Decode(&requestData) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(`{"error":"invalid request body"}`)) + return + } + + // Capture the received event name and headers for test validation + if eventName, ok := requestData["event_name"].(string); ok { + lastReceivedRequest.EventName = eventName + } + + // Capture headers + for k, v := range r.Header { + if len(v) > 0 { + lastReceivedRequest.Headers[k] = v[0] + } + } + + // Send appropriate response + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + response := fmt.Sprintf(`{"received_event":"%s","custom_header":"%s"}`, + lastReceivedRequest.EventName, r.Header.Get("X-Custom-Header")) + w.Write([]byte(response)) + })) + defer testServer.Close() + + t.Run("should fail without admin cookie", func(t *testing.T) { + // Attempt to test endpoint without admin authentication + params := &model.TestEndpointRequest{ + Endpoint: testServer.URL, + EventName: constants.UserLoginWebhookEvent, + Headers: map[string]interface{}{ + "X-Custom-Header": "test-value", + }, + } + + resp, err := ts.GraphQLProvider.TestEndpoint(ctx, params) + require.Error(t, err) + require.Nil(t, resp) + assert.Contains(t, err.Error(), "unauthorized") + }) + + // Add admin cookie for the rest of the tests + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + + t.Run("should fail with invalid event name", func(t *testing.T) { + params := &model.TestEndpointRequest{ + Endpoint: testServer.URL, + EventName: "invalid_event_name", + Headers: map[string]interface{}{}, + } + + resp, err := ts.GraphQLProvider.TestEndpoint(ctx, params) + require.Error(t, err) + require.Nil(t, resp) + assert.Contains(t, err.Error(), "invalid event_name") + }) + + t.Run("should successfully test endpoint with login event", func(t *testing.T) { + // Clear previous request data + lastReceivedRequest.EventName = "" + lastReceivedRequest.Headers = make(map[string]string) + + params := &model.TestEndpointRequest{ + Endpoint: testServer.URL, + EventName: constants.UserLoginWebhookEvent, + Headers: map[string]interface{}{ + "X-Custom-Header": "test-login-event", + "Content-Type": "application/json", + }, + } + + resp, err := ts.GraphQLProvider.TestEndpoint(ctx, params) + require.NoError(t, err) + require.NotNil(t, resp) + + // Wait a moment for the request to be processed by our test server + time.Sleep(50 * time.Millisecond) + + // Verify HTTP status + require.NotNil(t, resp.HTTPStatus) + assert.Equal(t, int64(http.StatusOK), *resp.HTTPStatus) + + // Verify the received event name from the test server + assert.Equal(t, constants.UserLoginWebhookEvent, lastReceivedRequest.EventName) + + // Verify response body + require.NotNil(t, resp.Response) + responseBody := *resp.Response + + // Parse response JSON + var respData map[string]interface{} + err = json.Unmarshal([]byte(responseBody), &respData) + require.NoError(t, err) + + assert.Equal(t, constants.UserLoginWebhookEvent, respData["received_event"]) + assert.Equal(t, "test-login-event", respData["custom_header"]) + }) + + t.Run("should successfully test endpoint with user created event", func(t *testing.T) { + // Clear previous request data + lastReceivedRequest.EventName = "" + lastReceivedRequest.Headers = make(map[string]string) + + // Create a separate test server for user created event + userCreatedServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + decoder := json.NewDecoder(r.Body) + var requestData map[string]interface{} + decoder.Decode(&requestData) + + eventName := requestData["event_name"].(string) + customHeader := r.Header.Get("X-Custom-Header") + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + response := fmt.Sprintf(`{"received_event":"%s","custom_header":"%s"}`, + eventName, customHeader) + w.Write([]byte(response)) + })) + defer userCreatedServer.Close() + + params := &model.TestEndpointRequest{ + Endpoint: userCreatedServer.URL, + EventName: constants.UserLoginWebhookEvent, + Headers: map[string]interface{}{ + "X-Custom-Header": "test-user-login-event", + }, + } + + resp, err := ts.GraphQLProvider.TestEndpoint(ctx, params) + require.NoError(t, err) + require.NotNil(t, resp) + + // Verify HTTP status + require.NotNil(t, resp.HTTPStatus) + assert.Equal(t, int64(http.StatusOK), *resp.HTTPStatus) + + // Verify response body directly + require.NotNil(t, resp.Response) + responseBody := *resp.Response + + // Parse response JSON + var respData map[string]interface{} + err = json.Unmarshal([]byte(responseBody), &respData) + require.NoError(t, err) + + assert.Equal(t, constants.UserLoginWebhookEvent, respData["received_event"]) + assert.Equal(t, "test-user-login-event", respData["custom_header"]) + }) + + t.Run("should handle endpoint that doesn't exist", func(t *testing.T) { + params := &model.TestEndpointRequest{ + Endpoint: "http://non-existent-endpoint.example", + EventName: constants.UserLoginWebhookEvent, + Headers: map[string]interface{}{}, + } + + resp, err := ts.GraphQLProvider.TestEndpoint(ctx, params) + require.Error(t, err) + require.Nil(t, resp) + }) +} diff --git a/internal/integration_tests/test_helper.go b/internal/integration_tests/test_helper.go new file mode 100644 index 000000000..1ba2db0b0 --- /dev/null +++ b/internal/integration_tests/test_helper.go @@ -0,0 +1,176 @@ +package integration_tests + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/rs/zerolog" + "github.com/stretchr/testify/require" + + "github.com/authorizerdev/authorizer/internal/authenticators" + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/email" + "github.com/authorizerdev/authorizer/internal/events" + "github.com/authorizerdev/authorizer/internal/graphql" + "github.com/authorizerdev/authorizer/internal/http_handlers" + "github.com/authorizerdev/authorizer/internal/memory_store" + "github.com/authorizerdev/authorizer/internal/sms" + "github.com/authorizerdev/authorizer/internal/storage" + "github.com/authorizerdev/authorizer/internal/token" +) + +// testSetup represents the test setup +type testSetup struct { + GraphQLProvider graphql.Provider + HttpProvider http_handlers.Provider + HttpServer *httptest.Server + Config *config.Config + Logger *zerolog.Logger + GinContext *gin.Context + // Used for specific tests where we need to access the storage + StorageProvider storage.Provider + MemoryStoreProvider memory_store.Provider +} + +func createContext(s *testSetup) (*http.Request, context.Context) { + req, _ := http.NewRequest( + "POST", + "http://"+s.HttpServer.Listener.Addr().String()+"/graphql", + nil, + ) + + ctx := context.WithValue(req.Context(), "GinContextKey", s.GinContext) + s.GinContext.Request = req + return req, ctx +} + +func getTestConfig() *config.Config { + // Initialize config with test settings + cfg := &config.Config{ + Env: constants.TestEnv, + DatabaseType: constants.DbTypePostgres, + DatabaseURL: "postgres://postgres:postgres@localhost:5432/postgres", + JWTSecret: "test-secret", + ClientID: "test-client-id", + ClientSecret: "test-client-secret", + AllowedOrigins: []string{"http://localhost:3000"}, + JWTType: "HS256", + AdminSecret: "test-admin-secret", + TwilioAPISecret: "test-twilio-api-secret", + TwilioAPIKey: "test-twilio-api-key", + TwilioAccountSID: "test-twilio-account-sid", + TwilioSender: "test-twilio-sender", + DefaultRoles: []string{"user"}, + EnableSignup: true, + EnableBasicAuthentication: true, + EnableMobileBasicAuthentication: true, + EnableLoginPage: true, + EnableStrongPassword: true, + IsSMSServiceEnabled: true, + } + + return cfg +} + +// initTestSetup initializes the test setup +func initTestSetup(t *testing.T, cfg *config.Config) *testSetup { + // Initialize logger + logger := zerolog.New(zerolog.NewTestWriter(t)).With().Timestamp().Logger() + + // Initialize storage provider first as it's required by other providers + storageProvider, err := storage.New(cfg, &storage.Dependencies{ + Log: &logger, + }) + require.NoError(t, err) + + // Initialize other providers + authProvider, err := authenticators.New(cfg, &authenticators.Dependencies{ + Log: &logger, + StorageProvider: storageProvider, + }) + require.NoError(t, err) + + emailProvider, err := email.New(cfg, &email.Dependencies{ + Log: &logger, + StorageProvider: storageProvider, + }) + require.NoError(t, err) + + eventsProvider, err := events.New(cfg, &events.Dependencies{ + Log: &logger, + StorageProvider: storageProvider, + }) + require.NoError(t, err) + + memoryStoreProvider, err := memory_store.New(cfg, &memory_store.Dependencies{ + Log: &logger, + }) + require.NoError(t, err) + + smsProvider, err := sms.New(cfg, &sms.Dependencies{ + Log: &logger, + }) + require.NoError(t, err) + + tokenProvider, err := token.New(cfg, &token.Dependencies{ + Log: &logger, + MemoryStoreProvider: memoryStoreProvider, + }) + require.NoError(t, err) + + // Create dependencies struct + gqlDeps := &graphql.Dependencies{ + Log: &logger, + AuthenticatorProvider: authProvider, + EmailProvider: emailProvider, + EventsProvider: eventsProvider, + MemoryStoreProvider: memoryStoreProvider, + SMSProvider: smsProvider, + StorageProvider: storageProvider, + TokenProvider: tokenProvider, + } + + // Create dependencies struct + httpDeps := &http_handlers.Dependencies{ + Log: &logger, + AuthenticatorProvider: authProvider, + EmailProvider: emailProvider, + EventsProvider: eventsProvider, + MemoryStoreProvider: memoryStoreProvider, + SMSProvider: smsProvider, + StorageProvider: storageProvider, + TokenProvider: tokenProvider, + } + + // Create GraphQL provider + gqlProvider, err := graphql.New(cfg, gqlDeps) + require.NoError(t, err) + + // Create HTTP provider + httpProvider, err := http_handlers.New(cfg, httpDeps) + require.NoError(t, err) + + w := httptest.NewRecorder() + ctx, r := gin.CreateTestContext(w) + r.Use(httpProvider.CORSMiddleware()) + r.Use(httpProvider.ContextMiddleware()) + r.Use(httpProvider.LoggerMiddleware()) + + r.POST("/graphql", httpProvider.GraphqlHandler()) + + server := httptest.NewServer(r) + + return &testSetup{ + GraphQLProvider: gqlProvider, + HttpProvider: httpProvider, + HttpServer: server, + Logger: &logger, + GinContext: ctx, + StorageProvider: storageProvider, + MemoryStoreProvider: memoryStoreProvider, + } +} diff --git a/internal/integration_tests/update_email_template_test.go b/internal/integration_tests/update_email_template_test.go new file mode 100644 index 000000000..4047cb25a --- /dev/null +++ b/internal/integration_tests/update_email_template_test.go @@ -0,0 +1,248 @@ +package integration_tests + +import ( + "fmt" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestUpdateEmailTemplate tests the update email template functionality by the admin +func TestUpdateEmailTemplate(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "update_email_template_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + + // Test without admin cookie first + t.Run("should fail without admin cookie", func(t *testing.T) { + updateParams := &model.UpdateEmailTemplateRequest{ + ID: "some-id", + Subject: refs.NewStringRef("Updated Subject"), + Template: refs.NewStringRef("Updated Template"), + } + + resp, err := ts.GraphQLProvider.UpdateEmailTemplate(ctx, updateParams) + require.Error(t, err) + require.Nil(t, resp) + assert.Contains(t, err.Error(), "unauthorized") + }) + + // Add admin cookie for the rest of the tests + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + + t.Run("should fail for non-existent template", func(t *testing.T) { + nonExistentID := uuid.New().String() + updateParams := &model.UpdateEmailTemplateRequest{ + ID: nonExistentID, + Subject: refs.NewStringRef("Updated Subject"), + Template: refs.NewStringRef("Updated Template"), + } + + resp, err := ts.GraphQLProvider.UpdateEmailTemplate(ctx, updateParams) + require.Error(t, err) + require.Nil(t, resp) + // The error message may vary depending on the storage implementation + assert.NotEmpty(t, err.Error()) + }) + + // First create a template to test updating + var templateID string + t.Run("setup - create template for updating", func(t *testing.T) { + // Clean up any existing template + existingTemplate, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeForgotPassword) + if err == nil && existingTemplate != nil { + err = ts.StorageProvider.DeleteEmailTemplate(ctx, existingTemplate) + require.NoError(t, err) + } + + // Create a new template + addParams := &model.AddEmailTemplateRequest{ + EventName: constants.VerificationTypeForgotPassword, + Subject: "Reset Your Password", + Template: "Click here to reset your password: {{.URL}}", + Design: refs.NewStringRef("original design"), + } + + resp, err := ts.GraphQLProvider.AddEmailTemplate(ctx, addParams) + require.NoError(t, err) + require.NotNil(t, resp) + + // Get the created template to get its ID + template, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeForgotPassword) + require.NoError(t, err) + require.NotNil(t, template) + templateID = template.ID + }) + + t.Run("should update subject", func(t *testing.T) { + updateParams := &model.UpdateEmailTemplateRequest{ + ID: templateID, + Subject: refs.NewStringRef("Updated Reset Password Subject"), + } + + resp, err := ts.GraphQLProvider.UpdateEmailTemplate(ctx, updateParams) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "Email template updated successfully") + + // Verify the template was updated + template, err := ts.StorageProvider.GetEmailTemplateByID(ctx, templateID) + require.NoError(t, err) + require.NotNil(t, template) + assert.Equal(t, *updateParams.Subject, template.Subject) + assert.Equal(t, constants.VerificationTypeForgotPassword, template.EventName) // Event name unchanged + }) + + t.Run("should update template content", func(t *testing.T) { + updateParams := &model.UpdateEmailTemplateRequest{ + ID: templateID, + Template: refs.NewStringRef("New content for password reset: {{.URL}} - {{.AppName}}"), + } + + resp, err := ts.GraphQLProvider.UpdateEmailTemplate(ctx, updateParams) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "Email template updated successfully") + + // Verify the template was updated + template, err := ts.StorageProvider.GetEmailTemplateByID(ctx, templateID) + require.NoError(t, err) + require.NotNil(t, template) + assert.Equal(t, *updateParams.Template, template.Template) + }) + + t.Run("should update design", func(t *testing.T) { + updateParams := &model.UpdateEmailTemplateRequest{ + ID: templateID, + Design: refs.NewStringRef("updated design with new styles"), + } + + resp, err := ts.GraphQLProvider.UpdateEmailTemplate(ctx, updateParams) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "Email template updated successfully") + + // Verify the template was updated + template, err := ts.StorageProvider.GetEmailTemplateByID(ctx, templateID) + require.NoError(t, err) + require.NotNil(t, template) + assert.Equal(t, *updateParams.Design, template.Design) + }) + + t.Run("should update event name", func(t *testing.T) { + // First make sure the target event name doesn't exist yet + existingTemplate, err := ts.StorageProvider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeUpdateEmail) + if err == nil && existingTemplate != nil { + err = ts.StorageProvider.DeleteEmailTemplate(ctx, existingTemplate) + require.NoError(t, err) + } + + updateParams := &model.UpdateEmailTemplateRequest{ + ID: templateID, + EventName: refs.NewStringRef(constants.VerificationTypeUpdateEmail), + } + + resp, err := ts.GraphQLProvider.UpdateEmailTemplate(ctx, updateParams) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "Email template updated successfully") + + // Verify the template was updated + template, err := ts.StorageProvider.GetEmailTemplateByID(ctx, templateID) + require.NoError(t, err) + require.NotNil(t, template) + assert.Equal(t, constants.VerificationTypeUpdateEmail, template.EventName) + }) + + t.Run("should fail with invalid event name", func(t *testing.T) { + updateParams := &model.UpdateEmailTemplateRequest{ + ID: templateID, + EventName: refs.NewStringRef("invalid_event_name"), + } + + resp, err := ts.GraphQLProvider.UpdateEmailTemplate(ctx, updateParams) + require.Error(t, err) + require.Nil(t, resp) + assert.Contains(t, err.Error(), "invalid event name") + }) + + t.Run("should fail with whitespace-only subject", func(t *testing.T) { + updateParams := &model.UpdateEmailTemplateRequest{ + ID: templateID, + Subject: refs.NewStringRef(" "), + } + + resp, err := ts.GraphQLProvider.UpdateEmailTemplate(ctx, updateParams) + require.Error(t, err) + require.Nil(t, resp) + assert.Contains(t, err.Error(), "empty subject not allowed") + }) + + t.Run("should fail with whitespace-only template", func(t *testing.T) { + updateParams := &model.UpdateEmailTemplateRequest{ + ID: templateID, + Template: refs.NewStringRef(" "), + } + + resp, err := ts.GraphQLProvider.UpdateEmailTemplate(ctx, updateParams) + require.Error(t, err) + require.Nil(t, resp) + assert.Contains(t, err.Error(), "empty template not allowed") + }) + + t.Run("should fail with whitespace-only design", func(t *testing.T) { + updateParams := &model.UpdateEmailTemplateRequest{ + ID: templateID, + Design: refs.NewStringRef(" "), + } + + resp, err := ts.GraphQLProvider.UpdateEmailTemplate(ctx, updateParams) + require.Error(t, err) + require.Nil(t, resp) + assert.Contains(t, err.Error(), "empty design not allowed") + }) + + t.Run("should update multiple fields at once", func(t *testing.T) { + updateParams := &model.UpdateEmailTemplateRequest{ + ID: templateID, + Subject: refs.NewStringRef("Multi-Update Subject"), + Template: refs.NewStringRef("Multi-Update Template Content"), + Design: refs.NewStringRef("Multi-Update Design Content"), + } + + resp, err := ts.GraphQLProvider.UpdateEmailTemplate(ctx, updateParams) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Contains(t, resp.Message, "Email template updated successfully") + + // Verify the template was updated + template, err := ts.StorageProvider.GetEmailTemplateByID(ctx, templateID) + require.NoError(t, err) + require.NotNil(t, template) + assert.Equal(t, *updateParams.Subject, template.Subject) + assert.Equal(t, *updateParams.Template, template.Template) + assert.Equal(t, *updateParams.Design, template.Design) + }) +} diff --git a/internal/integration_tests/update_profile_test.go b/internal/integration_tests/update_profile_test.go new file mode 100644 index 000000000..c79cb47da --- /dev/null +++ b/internal/integration_tests/update_profile_test.go @@ -0,0 +1,171 @@ +package integration_tests + +import ( + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" +) + +// TestUpdateProfile tests the update profile functionality +// using the GraphQL API. +// It creates a user, updates the profile, and verifies +// the changes in the database. +func TestUpdateProfile(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + // Create a test user + email := "update_profile_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, signupRes) + assert.Equal(t, email, *signupRes.User.Email) + assert.NotEmpty(t, *signupRes.AccessToken) + + // Login to get fresh tokens + loginReq := &model.LoginRequest{ + Email: &email, + Password: password, + } + loginRes, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.NoError(t, err) + assert.NotNil(t, loginRes) + assert.NotEmpty(t, *loginRes.AccessToken) + + // Set the authorization header for authenticated requests + ts.GinContext.Request.Header.Set("Authorization", "Bearer "+*loginRes.AccessToken) + + // Test cases + t.Run("should fail update profile without authentication", func(t *testing.T) { + // Clear authorization header + ts.GinContext.Request.Header.Set("Authorization", "") + defer func() { + ts.GinContext.Request.Header.Set("Authorization", "Bearer "+*loginRes.AccessToken) + }() + + updateReq := &model.UpdateProfileRequest{ + GivenName: refs.NewStringRef("Test"), + } + updateRes, err := ts.GraphQLProvider.UpdateProfile(ctx, updateReq) + assert.Error(t, err) + assert.Nil(t, updateRes) + }) + + t.Run("should update basic profile information", func(t *testing.T) { + givenName := "John" + familyName := "Doe" + nickname := "Johnny" + phoneNumber := "+1234567890" + + updateReq := &model.UpdateProfileRequest{ + GivenName: refs.NewStringRef(givenName), + FamilyName: refs.NewStringRef(familyName), + Nickname: refs.NewStringRef(nickname), + PhoneNumber: refs.NewStringRef(phoneNumber), + } + + updateRes, err := ts.GraphQLProvider.UpdateProfile(ctx, updateReq) + assert.NoError(t, err) + assert.NotNil(t, updateRes) + + // Get the profile + profile, err := ts.GraphQLProvider.Profile(ctx) + assert.NoError(t, err) + assert.NotNil(t, profile) + assert.Equal(t, givenName, *profile.GivenName) + assert.Equal(t, familyName, *profile.FamilyName) + assert.Equal(t, nickname, *profile.Nickname) + assert.Equal(t, phoneNumber, *profile.PhoneNumber) + assert.Equal(t, email, *profile.Email) + }) + + t.Run("should update profile picture", func(t *testing.T) { + picture := "https://example.com/profile.jpg" + + updateReq := &model.UpdateProfileRequest{ + Picture: refs.NewStringRef(picture), + } + + updateRes, err := ts.GraphQLProvider.UpdateProfile(ctx, updateReq) + assert.NoError(t, err) + assert.NotNil(t, updateRes) + + // Get the profile + profile, err := ts.GraphQLProvider.Profile(ctx) + assert.NoError(t, err) + assert.NotNil(t, profile) + assert.Equal(t, picture, *profile.Picture) + }) + + t.Run("should update gender", func(t *testing.T) { + gender := "male" + + updateReq := &model.UpdateProfileRequest{ + Gender: refs.NewStringRef(gender), + } + + updateRes, err := ts.GraphQLProvider.UpdateProfile(ctx, updateReq) + assert.NoError(t, err) + assert.NotNil(t, updateRes) + + // Get the profile + profile, err := ts.GraphQLProvider.Profile(ctx) + assert.NoError(t, err) + assert.NotNil(t, profile) + }) + + t.Run("should update birthdate", func(t *testing.T) { + birthdate := "1990-01-01" + + updateReq := &model.UpdateProfileRequest{ + Birthdate: refs.NewStringRef(birthdate), + } + + updateRes, err := ts.GraphQLProvider.UpdateProfile(ctx, updateReq) + assert.NoError(t, err) + assert.NotNil(t, updateRes) + + // Get the profile + profile, err := ts.GraphQLProvider.Profile(ctx) + assert.NoError(t, err) + assert.NotNil(t, profile) + assert.Equal(t, birthdate, *profile.Birthdate) + }) + + t.Run("should update multiple fields at once", func(t *testing.T) { + givenName := "Updated" + familyName := "User" + picture := "https://example.com/new-profile.jpg" + + updateReq := &model.UpdateProfileRequest{ + GivenName: refs.NewStringRef(givenName), + FamilyName: refs.NewStringRef(familyName), + Picture: refs.NewStringRef(picture), + } + + updateRes, err := ts.GraphQLProvider.UpdateProfile(ctx, updateReq) + assert.NoError(t, err) + assert.NotNil(t, updateRes) + + // Get the profile + profile, err := ts.GraphQLProvider.Profile(ctx) + assert.NoError(t, err) + assert.NotNil(t, profile) + assert.Equal(t, givenName, *profile.GivenName) + assert.Equal(t, familyName, *profile.FamilyName) + assert.Equal(t, picture, *profile.Picture) + }) +} diff --git a/internal/integration_tests/update_user_test.go b/internal/integration_tests/update_user_test.go new file mode 100644 index 000000000..62126231b --- /dev/null +++ b/internal/integration_tests/update_user_test.go @@ -0,0 +1,57 @@ +package integration_tests + +import ( + "fmt" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestUpdateUser tests the update user functionality by the admin +func TestUpdateUser(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "update_user_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + require.NotNil(t, signupRes.User) + + userFirstName := "UpdatedFirstName" + updateReq := &model.UpdateUserRequest{ + ID: signupRes.User.ID, + GivenName: &userFirstName, + } + t.Run("should fail without admin cookie", func(t *testing.T) { + updateRes, err := ts.GraphQLProvider.UpdateUser(ctx, updateReq) + require.Error(t, err) + require.Nil(t, updateRes) + }) + + t.Run("should update user", func(t *testing.T) { + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + updateRes, err := ts.GraphQLProvider.UpdateUser(ctx, updateReq) + require.NoError(t, err) + require.NotNil(t, updateRes) + require.Equal(t, updateRes.ID, signupRes.User.ID) + require.Equal(t, userFirstName, *updateRes.GivenName) + }) +} diff --git a/internal/integration_tests/update_webhook_test.go b/internal/integration_tests/update_webhook_test.go new file mode 100644 index 000000000..b5cf63c88 --- /dev/null +++ b/internal/integration_tests/update_webhook_test.go @@ -0,0 +1,198 @@ +package integration_tests + +import ( + "fmt" + "strings" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestUpdateWebhookTest tests the update webhook functionality by the admin +func TestUpdateWebhookTest(t *testing.T) { + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + email := "update_webhook_user_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + require.NoError(t, err) + require.NotNil(t, signupRes) + require.NotNil(t, signupRes.User) + + // First add a webhook to update + h, err := crypto.EncryptPassword(cfg.AdminSecret) + assert.Nil(t, err) + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + + // Create a webhook with original event name + addedWebhook, err := ts.GraphQLProvider.AddWebhook(ctx, &model.AddWebhookRequest{ + EventName: constants.UserCreatedWebhookEvent, + EventDescription: refs.NewStringRef("original description"), + Endpoint: "http://original-endpoint.com", + Enabled: false, + Headers: map[string]any{ + "Content-Type": "application/json", + }, + }) + require.NoError(t, err) + assert.NotNil(t, addedWebhook) + + // Get the webhook to update + webhooks, err := ts.StorageProvider.GetWebhookByEventName(ctx, constants.UserCreatedWebhookEvent) + require.NoError(t, err) + require.NotEmpty(t, webhooks) + webhookID := webhooks[0].ID + + t.Run("should fail without admin cookie", func(t *testing.T) { + // Remove admin cookie + req.Header.Del("Cookie") + + updatedWebhook, err := ts.GraphQLProvider.UpdateWebhook(ctx, &model.UpdateWebhookRequest{ + ID: webhookID, + EventName: refs.NewStringRef(constants.UserCreatedWebhookEvent), + EventDescription: refs.NewStringRef("updated description"), + Endpoint: refs.NewStringRef("http://updated-endpoint.com"), + Enabled: refs.NewBoolRef(true), + Headers: map[string]any{ + "Content-Type": "application/json", + "Authorization": "Bearer token", + }, + }) + require.Error(t, err) + require.Nil(t, updatedWebhook) + }) + + // Re-add the admin cookie for the rest of the tests + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) + + t.Run("should fail with invalid webhook ID", func(t *testing.T) { + updatedWebhook, err := ts.GraphQLProvider.UpdateWebhook(ctx, &model.UpdateWebhookRequest{ + ID: uuid.NewString(), + EventName: refs.NewStringRef(constants.UserCreatedWebhookEvent), + EventDescription: refs.NewStringRef("updated description"), + Endpoint: refs.NewStringRef("http://updated-endpoint.com"), + Enabled: refs.NewBoolRef(true), + }) + require.Error(t, err) + require.Nil(t, updatedWebhook) + }) + + t.Run("should fail with blank webhook ID", func(t *testing.T) { + updatedWebhook, err := ts.GraphQLProvider.UpdateWebhook(ctx, &model.UpdateWebhookRequest{ + ID: "", + EventName: refs.NewStringRef(constants.UserCreatedWebhookEvent), + EventDescription: refs.NewStringRef("updated description"), + Endpoint: refs.NewStringRef("http://updated-endpoint.com"), + Enabled: refs.NewBoolRef(true), + }) + require.Error(t, err) + require.Nil(t, updatedWebhook) + }) + + t.Run("should fail with invalid event name", func(t *testing.T) { + updatedWebhook, err := ts.GraphQLProvider.UpdateWebhook(ctx, &model.UpdateWebhookRequest{ + ID: webhookID, + EventName: refs.NewStringRef("invalid_event_name"), + EventDescription: refs.NewStringRef("updated description"), + Endpoint: refs.NewStringRef("http://updated-endpoint.com"), + Enabled: refs.NewBoolRef(true), + }) + require.Error(t, err) + require.Nil(t, updatedWebhook) + }) + + t.Run("should fail with blank endpoint", func(t *testing.T) { + updatedWebhook, err := ts.GraphQLProvider.UpdateWebhook(ctx, &model.UpdateWebhookRequest{ + ID: webhookID, + EventName: refs.NewStringRef(constants.UserCreatedWebhookEvent), + EventDescription: refs.NewStringRef("updated description"), + Endpoint: refs.NewStringRef(""), + Enabled: refs.NewBoolRef(true), + }) + require.Error(t, err) + require.Nil(t, updatedWebhook) + }) + + t.Run("should update webhook successfully", func(t *testing.T) { + // Use a different event name for the update to avoid conflicts + newEventName := constants.UserLoginWebhookEvent + updatedEndpoint := "http://updated-endpoint.com" + + updatedWebhook, err := ts.GraphQLProvider.UpdateWebhook(ctx, &model.UpdateWebhookRequest{ + ID: webhookID, + EventName: refs.NewStringRef(newEventName), + EventDescription: refs.NewStringRef("updated description"), + Endpoint: refs.NewStringRef(updatedEndpoint), + Enabled: refs.NewBoolRef(true), + Headers: map[string]any{ + "Content-Type": "application/json", + "Authorization": "Bearer token", + }, + }) + require.NoError(t, err) + assert.NotNil(t, updatedWebhook) + + // Verify the webhook was updated correctly + updatedWebhooks, err := ts.StorageProvider.GetWebhookByID(ctx, webhookID) + require.NoError(t, err) + assert.NotNil(t, updatedWebhooks) + + // Use the same event name that we provided in the update request + assert.Contains(t, updatedWebhooks.EventName, newEventName) + assert.Equal(t, "updated description", updatedWebhooks.EventDescription) + assert.Equal(t, updatedEndpoint, updatedWebhooks.EndPoint) + assert.Equal(t, true, updatedWebhooks.Enabled) + }) + + t.Run("should partially update webhook", func(t *testing.T) { + // First get the current webhook state to verify what fields stay unchanged + currentWebhook, err := ts.StorageProvider.GetWebhookByID(ctx, webhookID) + require.NoError(t, err) + + // Store the current values for later verification + currentEventName := strings.Split(currentWebhook.EventName, "-")[0] + currentEndpoint := currentWebhook.EndPoint + + // Update only the description and enabled status + updatedWebhook, err := ts.GraphQLProvider.UpdateWebhook(ctx, &model.UpdateWebhookRequest{ + ID: webhookID, + EventDescription: refs.NewStringRef("new partial description"), + Enabled: refs.NewBoolRef(false), + // Don't update event name or endpoint + }) + require.NoError(t, err) + assert.NotNil(t, updatedWebhook) + + // Verify only specified fields were updated + afterPartialUpdate, err := ts.StorageProvider.GetWebhookByID(ctx, webhookID) + require.NoError(t, err) + assert.NotNil(t, afterPartialUpdate) + + // The event name should remain the same as before + assert.Contains(t, afterPartialUpdate.EventName, currentEventName) + + // Description should be updated + assert.Equal(t, "new partial description", afterPartialUpdate.EventDescription) + + // Endpoint should remain unchanged + assert.Equal(t, currentEndpoint, afterPartialUpdate.EndPoint) + + // Enabled should be updated + assert.Equal(t, false, afterPartialUpdate.Enabled) + }) +} diff --git a/internal/integration_tests/validate_jwt_token_test.go b/internal/integration_tests/validate_jwt_token_test.go new file mode 100644 index 000000000..3a8b709e9 --- /dev/null +++ b/internal/integration_tests/validate_jwt_token_test.go @@ -0,0 +1,91 @@ +package integration_tests + +import ( + "strings" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestValidateJWTToken add test cases for validating JWT tokens +func TestValidateJWTToken(t *testing.T) { + // Initialize test setup + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + // Test setup - create a test user + email := "validate_jwt_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, res) + + // Profile tests + t.Run("after login", func(t *testing.T) { + loginReq := &model.LoginRequest{ + Email: &email, + Password: password, + } + loginRes, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.NoError(t, err) + assert.NotNil(t, loginRes) + + // Verify response contains expected tokens + assert.NotEmpty(t, loginRes.AccessToken) + assert.NotNil(t, loginRes.User) + assert.Equal(t, email, *loginRes.User.Email) + assert.True(t, loginRes.User.EmailVerified) + + t.Run("should fail without token", func(t *testing.T) { + res, err := ts.GraphQLProvider.ValidateJWTToken(ctx, &model.ValidateJWTTokenRequest{}) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should fail without token type", func(t *testing.T) { + res, err := ts.GraphQLProvider.ValidateJWTToken(ctx, &model.ValidateJWTTokenRequest{ + Token: "invalid-token", + }) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should fail with invalid token", func(t *testing.T) { + res, err := ts.GraphQLProvider.ValidateJWTToken(ctx, &model.ValidateJWTTokenRequest{ + Token: "invalid-token", + TokenType: constants.TokenTypeAccessToken, + }) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should pass with valid input", func(t *testing.T) { + allData, err := ts.MemoryStoreProvider.GetAllData() + require.NoError(t, err) + accessToken := "" + for k, v := range allData { + if strings.Contains(k, constants.TokenTypeAccessToken) { + accessToken = v + break + } + } + res, err := ts.GraphQLProvider.ValidateJWTToken(ctx, &model.ValidateJWTTokenRequest{ + Token: accessToken, + TokenType: constants.TokenTypeAccessToken, + }) + require.NoError(t, err) + require.NotNil(t, res) + }) + }) +} diff --git a/internal/integration_tests/validate_session_test.go b/internal/integration_tests/validate_session_test.go new file mode 100644 index 000000000..a5cd959fa --- /dev/null +++ b/internal/integration_tests/validate_session_test.go @@ -0,0 +1,99 @@ +package integration_tests + +import ( + "strings" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestValidateSession add test cases for validating session tokens +func TestValidateSession(t *testing.T) { + // Initialize test setup + cfg := getTestConfig() + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + // Test setup - create a test user + email := "validate_session_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + res, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, res) + + // Profile tests + t.Run("after login", func(t *testing.T) { + loginReq := &model.LoginRequest{ + Email: &email, + Password: password, + } + loginRes, err := ts.GraphQLProvider.Login(ctx, loginReq) + assert.NoError(t, err) + assert.NotNil(t, loginRes) + + // Verify response contains expected tokens + assert.NotEmpty(t, loginRes.AccessToken) + assert.NotNil(t, loginRes.User) + assert.Equal(t, email, *loginRes.User.Email) + assert.True(t, loginRes.User.EmailVerified) + + t.Run("should fail without cookie", func(t *testing.T) { + res, err := ts.GraphQLProvider.ValidateSession(ctx, &model.ValidateSessionRequest{}) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should fail with invalid cookie", func(t *testing.T) { + res, err := ts.GraphQLProvider.ValidateSession(ctx, &model.ValidateSessionRequest{ + Cookie: "invalid-token", + }) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("should pass with valid input", func(t *testing.T) { + allData, err := ts.MemoryStoreProvider.GetAllData() + require.NoError(t, err) + sessionToken := "" + for k, v := range allData { + if strings.Contains(k, constants.TokenTypeSessionToken) { + sessionToken = v + break + } + } + res, err := ts.GraphQLProvider.ValidateSession(ctx, &model.ValidateSessionRequest{ + Cookie: sessionToken, + }) + require.NoError(t, err) + require.NotNil(t, res) + + t.Run("should fail with invalid roles", func(t *testing.T) { + res, err := ts.GraphQLProvider.ValidateSession(ctx, &model.ValidateSessionRequest{ + Cookie: sessionToken, + Roles: []string{"invalid-role"}, + }) + assert.Error(t, err) + assert.Nil(t, res) + }) + t.Run("should pass with valid roles", func(t *testing.T) { + res, err := ts.GraphQLProvider.ValidateSession(ctx, &model.ValidateSessionRequest{ + Cookie: sessionToken, + Roles: []string{"user"}, + }) + assert.NoError(t, err) + assert.NotNil(t, res) + assert.True(t, res.IsValid) + }) + }) + }) +} diff --git a/internal/integration_tests/verify_email_test.go b/internal/integration_tests/verify_email_test.go new file mode 100644 index 000000000..418375bc7 --- /dev/null +++ b/internal/integration_tests/verify_email_test.go @@ -0,0 +1,65 @@ +package integration_tests + +import ( + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +// TestVerifyEmail tests the verify email functionality +// using the GraphQL API. +// It creates a user, verifies the email, and checks +// the changes in the database. +func TestVerifyEmail(t *testing.T) { + cfg := getTestConfig() + cfg.IsEmailServiceEnabled = true + cfg.EnableEmailVerification = true + ts := initTestSetup(t, cfg) + _, ctx := createContext(ts) + + // Create a test user + email := "verify_email_test_" + uuid.New().String() + "@authorizer.dev" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + Email: &email, + Password: password, + ConfirmPassword: password, + } + + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, signupRes) + // Expect the user to be nil, as the email is not verified yet + assert.Nil(t, signupRes.User) + + t.Run("should fail for invalid token", func(t *testing.T) { + verificationReq := &model.VerifyEmailRequest{ + Token: "invalid-token", + } + verificationRes, err := ts.GraphQLProvider.VerifyEmail(ctx, verificationReq) + assert.Error(t, err) + assert.Nil(t, verificationRes) + }) + + t.Run("should verify email", func(t *testing.T) { + // Get the verification token from db + request, err := ts.StorageProvider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) + assert.NoError(t, err) + assert.NotNil(t, request) + assert.NotEmpty(t, request.Token) + + // Verify email with an invalid token + verificationReq := &model.VerifyEmailRequest{ + Token: request.Token, + } + + verificationRes, err := ts.GraphQLProvider.VerifyEmail(ctx, verificationReq) + assert.NoError(t, err) + assert.NotNil(t, verificationRes) + assert.NotEmpty(t, verificationRes.AccessToken) + }) +} diff --git a/internal/integration_tests/verify_otp_test.go b/internal/integration_tests/verify_otp_test.go new file mode 100644 index 000000000..a2ec958c7 --- /dev/null +++ b/internal/integration_tests/verify_otp_test.go @@ -0,0 +1,107 @@ +package integration_tests + +import ( + "fmt" + "strings" + "testing" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestVerifyOTP tests the resend verify OTP functionality +func TestVerifyOTP(t *testing.T) { + cfg := getTestConfig() + cfg.IsSMSServiceEnabled = true + cfg.EnableEmailOTP = true + cfg.EnableSMSOTP = true + cfg.SMTPHost = "localhost" + cfg.SMTPPort = 1025 + cfg.SMTPSenderEmail = "test@authorizer.dev" + cfg.SMTPSenderName = "Test" + cfg.SMTPLocalName = "Test" + cfg.SkipTLSVerification = true + cfg.IsEmailServiceEnabled = true + cfg.IsSMSServiceEnabled = true + cfg.EnableEmailVerification = true + cfg.TwilioAPISecret = "test-twilio-api-secret" + cfg.TwilioAPIKey = "test-twilio-api-key" + cfg.TwilioAccountSID = "test-twilio-account-sid" + cfg.TwilioSender = "test-twilio-sender" + cfg.EnableMobileBasicAuthentication = true + cfg.EnablePhoneVerification = true + ts := initTestSetup(t, cfg) + req, ctx := createContext(ts) + + // Create a test user + mobile := "+14155552671" + password := "Password@123" + // Signup the user + signupReq := &model.SignUpRequest{ + PhoneNumber: &mobile, + Password: password, + ConfirmPassword: password, + } + + signupRes, err := ts.GraphQLProvider.SignUp(ctx, signupReq) + assert.NoError(t, err) + assert.NotNil(t, signupRes) + // Expect the user to be nil, as the email is not verified yet + assert.Nil(t, signupRes.User) + + // Get the OTP from db + otpData, err := ts.StorageProvider.GetOTPByPhoneNumber(ctx, mobile) + require.NoError(t, err) + assert.NotNil(t, otpData) + // User + userData, err := ts.StorageProvider.GetUserByPhoneNumber(ctx, mobile) + require.NoError(t, err) + assert.NotNil(t, userData) + + t.Run("should fail for invalid cookie", func(t *testing.T) { + verificationReq := &model.VerifyOTPRequest{ + PhoneNumber: &mobile, + Otp: otpData.Otp, + } + verificationRes, err := ts.GraphQLProvider.VerifyOTP(ctx, verificationReq) + assert.Error(t, err) + assert.Nil(t, verificationRes) + }) + + t.Run("should fail for invalid OTP", func(t *testing.T) { + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.MfaCookieName+"_session", "test")) + verificationReq := &model.VerifyOTPRequest{ + PhoneNumber: &mobile, + Otp: "-----", + } + verificationRes, err := ts.GraphQLProvider.VerifyOTP(ctx, verificationReq) + assert.Error(t, err) + assert.Nil(t, verificationRes) + }) + + t.Run("should verify OTP", func(t *testing.T) { + // Get MFA session cookie + allData, err := ts.MemoryStoreProvider.GetAllData() + require.NoError(t, err) + sessionKey := "" + for k := range allData { + if strings.Contains(k, userData.ID) { + splitData := strings.Split(k, ":") + if len(splitData) > 1 { + sessionKey = splitData[1] + break + } + } + } + req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.MfaCookieName+"_session", sessionKey)) + verificationReq := &model.VerifyOTPRequest{ + PhoneNumber: &mobile, + Otp: otpData.Otp, + } + verificationRes, err := ts.GraphQLProvider.VerifyOTP(ctx, verificationReq) + require.NoError(t, err) + assert.NotNil(t, verificationRes) + }) +} diff --git a/internal/memory_store/in_memory/provider.go b/internal/memory_store/in_memory/provider.go new file mode 100644 index 000000000..d27e6077c --- /dev/null +++ b/internal/memory_store/in_memory/provider.go @@ -0,0 +1,36 @@ +package in_memory + +import ( + "sync" + + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/memory_store/in_memory/stores" +) + +// Dependencies struct for in_memory store provider +type Dependencies struct { + Log *zerolog.Logger +} + +type provider struct { + config *config.Config + dependencies *Dependencies + mutex sync.Mutex + sessionStore *stores.SessionStore + mfasessionStore *stores.SessionStore + stateStore *stores.StateStore +} + +// NewInMemoryStore returns a new in-memory store. +func NewInMemoryProvider(cfg *config.Config, deps *Dependencies) (*provider, error) { + return &provider{ + config: cfg, + dependencies: deps, + mutex: sync.Mutex{}, + sessionStore: stores.NewSessionStore(), + mfasessionStore: stores.NewSessionStore(), + stateStore: stores.NewStateStore(), + }, nil +} diff --git a/server/memorystore/providers/inmemory/store.go b/internal/memory_store/in_memory/store.go similarity index 53% rename from server/memorystore/providers/inmemory/store.go rename to internal/memory_store/in_memory/store.go index b20fb6221..83b73b2a3 100644 --- a/server/memorystore/providers/inmemory/store.go +++ b/internal/memory_store/in_memory/store.go @@ -1,10 +1,9 @@ -package inmemory +package in_memory import ( "fmt" - "os" - "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/internal/constants" ) // SetUserSession sets the user session for given user identifier in form recipe:user_id @@ -14,10 +13,10 @@ func (c *provider) SetUserSession(userId, key, token string, expiration int64) e } // GetUserSession returns value for given session token -func (c *provider) GetUserSession(userId, sessionToken string) (string, error) { - val := c.sessionStore.Get(userId, sessionToken) +func (c *provider) GetUserSession(userId, key string) (string, error) { + val := c.sessionStore.Get(userId, key) if val == "" { - return "", fmt.Errorf("Not found") + return "", fmt.Errorf("not found") } return val, nil } @@ -29,10 +28,16 @@ func (c *provider) DeleteAllUserSessions(userId string) error { } // DeleteUserSession deletes the user session from the in-memory store. -func (c *provider) DeleteUserSession(userId, sessionToken string) error { - c.sessionStore.Remove(userId, constants.TokenTypeSessionToken+"_"+sessionToken) - c.sessionStore.Remove(userId, constants.TokenTypeAccessToken+"_"+sessionToken) - c.sessionStore.Remove(userId, constants.TokenTypeRefreshToken+"_"+sessionToken) +func (c *provider) DeleteUserSession(userId, key string) error { + keys := []string{ + constants.TokenTypeSessionToken + "_" + key, + constants.TokenTypeAccessToken + "_" + key, + constants.TokenTypeRefreshToken + "_" + key, + } + + for _, k := range keys { + c.sessionStore.Remove(userId, k) + } return nil } @@ -52,11 +57,20 @@ func (c *provider) SetMfaSession(userId, key string, expiration int64) error { func (c *provider) GetMfaSession(userId, key string) (string, error) { val := c.mfasessionStore.Get(userId, key) if val == "" { - return "", fmt.Errorf("Not found") + return "", fmt.Errorf("not found") } return val, nil } +// GetAllMfaSessions returns all mfa sessions for given userId +func (p *provider) GetAllMfaSessions(userId string) ([]string, error) { + values := p.mfasessionStore.GetAll(userId) + if len(values) == 0 { + return nil, fmt.Errorf("not found") + } + return values, nil +} + // DeleteMfaSession deletes given mfa session from in-memory store. func (c *provider) DeleteMfaSession(userId, key string) error { c.mfasessionStore.Remove(userId, key) @@ -65,10 +79,9 @@ func (c *provider) DeleteMfaSession(userId, key string) error { // SetState sets the state in the in-memory store. func (c *provider) SetState(key, state string) error { - if os.Getenv("ENV") != constants.TestEnv { - c.mutex.Lock() - defer c.mutex.Unlock() - } + c.mutex.Lock() + defer c.mutex.Unlock() + c.stateStore.Set(key, state) return nil @@ -85,37 +98,17 @@ func (c *provider) RemoveState(key string) error { return nil } -// UpdateEnvStore to update the whole env store object -func (c *provider) UpdateEnvStore(store map[string]interface{}) error { - c.envStore.UpdateStore(store) - return nil -} - -// GetEnvStore returns the env store object -func (c *provider) GetEnvStore() (map[string]interface{}, error) { - return c.envStore.GetStore(), nil -} - -// UpdateEnvVariable to update the particular env variable -func (c *provider) UpdateEnvVariable(key string, value interface{}) error { - c.envStore.Set(key, value) - return nil -} - -// GetStringStoreEnvVariable to get the env variable from string store object -func (c *provider) GetStringStoreEnvVariable(key string) (string, error) { - res := c.envStore.Get(key) - if res == nil { - return "", nil +// GetAllData returns all the data from the in-memory store +// This is used for testing purposes only +func (c *provider) GetAllData() (map[string]string, error) { + // Get all data from the session store and mfa session store + // and merge them into a single map + data := make(map[string]string) + for k, v := range c.sessionStore.GetAllData() { + data[k] = v } - return fmt.Sprintf("%v", res), nil -} - -// GetBoolStoreEnvVariable to get the env variable from bool store object -func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) { - res := c.envStore.Get(key) - if res == nil { - return false, nil + for k, v := range c.mfasessionStore.GetAllData() { + data[k] = v } - return res.(bool), nil + return data, nil } diff --git a/internal/memory_store/in_memory/stores/env_store.go b/internal/memory_store/in_memory/stores/env_store.go new file mode 100644 index 000000000..c0b84b7aa --- /dev/null +++ b/internal/memory_store/in_memory/stores/env_store.go @@ -0,0 +1,48 @@ +package stores + +// EnvStore struct to store the env variables +// type EnvStore struct { +// mutex sync.Mutex +// store map[string]interface{} +// } + +// // NewEnvStore create a new env store +// func NewEnvStore() *EnvStore { +// return &EnvStore{ +// mutex: sync.Mutex{}, +// store: make(map[string]interface{}), +// } +// } + +// // UpdateEnvStore to update the whole env store object +// func (e *EnvStore) UpdateStore(store map[string]interface{}) { +// e.mutex.Lock() +// defer e.mutex.Unlock() + +// // just override the keys + new keys +// for key, value := range store { +// e.store[key] = value +// } +// } + +// // GetStore returns the env store +// func (e *EnvStore) GetStore() map[string]interface{} { +// e.mutex.Lock() +// defer e.mutex.Unlock() +// return e.store +// } + +// // Get returns the value of the key in evn store +// func (e *EnvStore) Get(key string) interface{} { +// e.mutex.Lock() +// defer e.mutex.Unlock() +// return e.store[key] +// } + +// // Set sets the value of the key in env store +// func (e *EnvStore) Set(key string, value interface{}) { +// e.mutex.Lock() +// defer e.mutex.Unlock() + +// e.store[key] = value +// } diff --git a/server/memorystore/providers/inmemory/stores/session_store.go b/internal/memory_store/in_memory/stores/session_store.go similarity index 81% rename from server/memorystore/providers/inmemory/stores/session_store.go rename to internal/memory_store/in_memory/stores/session_store.go index a92902264..dacce5860 100644 --- a/server/memorystore/providers/inmemory/stores/session_store.go +++ b/internal/memory_store/in_memory/stores/session_store.go @@ -85,6 +85,26 @@ func (s *SessionStore) Get(key, subKey string) string { return "" } +// Get returns the value of the key in state store +func (s *SessionStore) GetAll(key string) []string { + s.mutex.Lock() + defer s.mutex.Unlock() + currentTime := time.Now().Unix() + // Match all keys with the given key + var values []string + for k, v := range s.store { + if strings.HasPrefix(k, key) { + if v.ExpiresAt > currentTime { + values = append(values, v.Value) + } else { + // Delete expired items + delete(s.store, k) + } + } + } + return values +} + // Set sets the value of the key in state store func (s *SessionStore) Set(key string, subKey, value string, expiration int64) { s.mutex.Lock() @@ -142,3 +162,15 @@ func (s *SessionStore) RemoveByNamespace(namespace string) error { } return nil } + +// GetAllData returns all the data from the session store +// This is used for testing purposes only +func (s *SessionStore) GetAllData() map[string]string { + s.mutex.Lock() + defer s.mutex.Unlock() + data := make(map[string]string) + for k, v := range s.store { + data[k] = v.Value + } + return data +} diff --git a/server/memorystore/providers/inmemory/stores/state_store.go b/internal/memory_store/in_memory/stores/state_store.go similarity index 100% rename from server/memorystore/providers/inmemory/stores/state_store.go rename to internal/memory_store/in_memory/stores/state_store.go diff --git a/server/memorystore/providers/providers.go b/internal/memory_store/provider.go similarity index 58% rename from server/memorystore/providers/providers.go rename to internal/memory_store/provider.go index 331e34a50..1155c8b20 100644 --- a/server/memorystore/providers/providers.go +++ b/internal/memory_store/provider.go @@ -1,4 +1,29 @@ -package providers +package memory_store + +import ( + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/memory_store/in_memory" + "github.com/authorizerdev/authorizer/internal/memory_store/redis" +) + +// Dependencies struct for memory store provider +type Dependencies struct { + Log *zerolog.Logger +} + +// New returns a new memory store provider +func New(cfg *config.Config, deps *Dependencies) (Provider, error) { + if cfg.RedisURL != "" { + return redis.NewRedisProvider(cfg, &redis.Dependencies{ + Log: deps.Log, + }) + } + return in_memory.NewInMemoryProvider(cfg, &in_memory.Dependencies{ + Log: deps.Log, + }) +} // Provider defines current memory store provider type Provider interface { @@ -16,6 +41,8 @@ type Provider interface { SetMfaSession(userId, key string, expiration int64) error // GetMfaSession returns value of given mfa session GetMfaSession(userId, key string) (string, error) + // GetAllMfaSessions returns all mfa sessions for given userId + GetAllMfaSessions(userId string) ([]string, error) // DeleteMfaSession deletes given mfa session from in-memory store. DeleteMfaSession(userId, key string) error @@ -26,16 +53,7 @@ type Provider interface { // RemoveState removes the social login state from the session store RemoveState(key string) error - // methods for env store - - // UpdateEnvStore to update the whole env store object - UpdateEnvStore(store map[string]interface{}) error - // GetEnvStore() returns the env store object - GetEnvStore() (map[string]interface{}, error) - // UpdateEnvVariable to update the particular env variable - UpdateEnvVariable(key string, value interface{}) error - // GetStringStoreEnvVariable to get the string env variable from env store - GetStringStoreEnvVariable(key string) (string, error) - // GetBoolStoreEnvVariable to get the bool env variable from env store - GetBoolStoreEnvVariable(key string) (bool, error) + // GetAllData returns all the data from the session store + // This is used for testing purposes only + GetAllData() (map[string]string, error) } diff --git a/internal/memory_store/provider_test.go b/internal/memory_store/provider_test.go new file mode 100644 index 000000000..ea5b8aa8c --- /dev/null +++ b/internal/memory_store/provider_test.go @@ -0,0 +1,161 @@ +package memory_store + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/authorizerdev/authorizer/internal/config" +) + +const ( + memoryStoreTypeRedis = "redis" + memoryStoreTypeInMemory = "inmemory" +) + +var memoryStoreTypes = []string{ + memoryStoreTypeRedis, + memoryStoreTypeInMemory, +} + +func getTestMemoryStorageConfig(storageType string) *config.Config { + cfg := &config.Config{ + Env: "prod", + } + switch storageType { + case memoryStoreTypeRedis: + cfg.RedisURL = "redis://localhost:6380" + case memoryStoreTypeInMemory: + cfg.RedisURL = "" + default: + cfg.RedisURL = "" + } + return cfg +} + +// TestMemoryStoreProvider tests the memory store provider +func TestMemoryStoreProvider(t *testing.T) { + for _, storeType := range memoryStoreTypes { + t.Run("should test memory store provider for "+storeType, func(t *testing.T) { + cfg := getTestMemoryStorageConfig(storeType) + p, err := New(cfg, &Dependencies{}) + require.NoError(t, err) + require.NotNil(t, p) + err = p.SetUserSession("auth_provider:123", "session_token_key", "test_hash123", time.Now().Add(60*time.Second).Unix()) + assert.NoError(t, err) + err = p.SetUserSession("auth_provider:123", "access_token_key", "test_jwt123", time.Now().Add(60*time.Second).Unix()) + assert.NoError(t, err) + // Same user multiple session + err = p.SetUserSession("auth_provider:123", "session_token_key1", "test_hash1123", time.Now().Add(60*time.Second).Unix()) + assert.NoError(t, err) + err = p.SetUserSession("auth_provider:123", "access_token_key1", "test_jwt1123", time.Now().Add(60*time.Second).Unix()) + assert.NoError(t, err) + // Different user session + err = p.SetUserSession("auth_provider:124", "session_token_key", "test_hash124", time.Now().Add(5*time.Second).Unix()) + assert.NoError(t, err) + err = p.SetUserSession("auth_provider:124", "access_token_key", "test_jwt124", time.Now().Add(5*time.Second).Unix()) + assert.NoError(t, err) + // Different provider session + err = p.SetUserSession("auth_provider1:124", "session_token_key", "test_hash124", time.Now().Add(60*time.Second).Unix()) + assert.NoError(t, err) + err = p.SetUserSession("auth_provider1:124", "access_token_key", "test_jwt124", time.Now().Add(60*time.Second).Unix()) + assert.NoError(t, err) + // Different provider session + err = p.SetUserSession("auth_provider1:123", "session_token_key", "test_hash1123", time.Now().Add(60*time.Second).Unix()) + assert.NoError(t, err) + err = p.SetUserSession("auth_provider1:123", "access_token_key", "test_jwt1123", time.Now().Add(60*time.Second).Unix()) + assert.NoError(t, err) + // Get session + key, err := p.GetUserSession("auth_provider:123", "session_token_key") + assert.NoError(t, err) + assert.Equal(t, "test_hash123", key) + key, err = p.GetUserSession("auth_provider:123", "access_token_key") + assert.NoError(t, err) + assert.Equal(t, "test_jwt123", key) + key, err = p.GetUserSession("auth_provider:124", "session_token_key") + assert.NoError(t, err) + assert.Equal(t, "test_hash124", key) + key, err = p.GetUserSession("auth_provider:124", "access_token_key") + assert.NoError(t, err) + assert.Equal(t, "test_jwt124", key) + // Expire some tokens and make sure they are empty + time.Sleep(5 * time.Second) + key, err = p.GetUserSession("auth_provider:124", "session_token_key") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider:124", "access_token_key") + assert.Empty(t, key) + assert.Error(t, err) + // Delete user session + err = p.DeleteUserSession("auth_provider:123", "key") + assert.NoError(t, err) + err = p.DeleteUserSession("auth_provider:123", "key") + assert.NoError(t, err) + key, err = p.GetUserSession("auth_provider:123", "key") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider:123", "access_token_key") + assert.Empty(t, key) + assert.Error(t, err) + // Delete all user session + err = p.DeleteAllUserSessions("123") + assert.NoError(t, err) + err = p.DeleteAllUserSessions("123") + assert.NoError(t, err) + key, err = p.GetUserSession("auth_provider:123", "session_token_key1") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider:123", "access_token_key1") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider1:123", "session_token_key") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider1:123", "access_token_key") + assert.Empty(t, key) + assert.Error(t, err) + // Delete namespace + err = p.DeleteSessionForNamespace("auth_provider") + assert.NoError(t, err) + err = p.DeleteSessionForNamespace("auth_provider1") + assert.NoError(t, err) + key, err = p.GetUserSession("auth_provider:123", "session_token_key1") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider:123", "access_token_key1") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider1:123", "session_token_key") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider1:123", "access_token_key") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider:124", "session_token_key1") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider:124", "access_token_key1") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider1:124", "session_token_key") + assert.Empty(t, key) + assert.Error(t, err) + key, err = p.GetUserSession("auth_provider1:124", "access_token_key") + assert.Empty(t, key) + assert.Error(t, err) + + err = p.SetMfaSession("auth_provider:123", "session123", time.Now().Add(60*time.Second).Unix()) + assert.NoError(t, err) + key, err = p.GetMfaSession("auth_provider:123", "session123") + assert.NoError(t, err) + assert.Equal(t, "auth_provider:123", key) + err = p.DeleteMfaSession("auth_provider:123", "session123") + assert.NoError(t, err) + key, err = p.GetMfaSession("auth_provider:123", "session123") + assert.Error(t, err) + assert.Empty(t, key) + }) + } +} diff --git a/server/memorystore/providers/redis/provider.go b/internal/memory_store/redis/provider.go similarity index 69% rename from server/memorystore/providers/redis/provider.go rename to internal/memory_store/redis/provider.go index 17fb475dc..0e9142c65 100644 --- a/server/memorystore/providers/redis/provider.go +++ b/internal/memory_store/redis/provider.go @@ -6,13 +6,20 @@ import ( "time" "github.com/redis/go-redis/v9" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/config" ) const ( dialTimeout = 60 * time.Second ) +// Dependencies struct for redis provider +type Dependencies struct { + Log *zerolog.Logger +} + // RedisClient is the interface for redis client & redis cluster client type RedisClient interface { HMSet(ctx context.Context, key string, values ...interface{}) *redis.BoolCmd @@ -29,17 +36,20 @@ type RedisClient interface { } type provider struct { + config *config.Config + dependencies *Dependencies + ctx context.Context store RedisClient } // NewRedisProvider returns a new redis provider -func NewRedisProvider(redisURL string) (*provider, error) { - redisURLHostPortsList := strings.Split(redisURL, ",") +func NewRedisProvider(cfg *config.Config, deps *Dependencies) (*provider, error) { + redisURLHostPortsList := strings.Split(cfg.RedisURL, ",") if len(redisURLHostPortsList) > 1 { opt, err := redis.ParseURL(redisURLHostPortsList[0]) if err != nil { - log.Debug("error parsing redis url: ", err) + deps.Log.Debug().Err(err).Msg("error parsing redis url") return nil, err } urls := []string{opt.Addr} @@ -50,19 +60,21 @@ func NewRedisProvider(redisURL string) (*provider, error) { ctx := context.Background() _, err = rdb.Ping(ctx).Result() if err != nil { - log.Debug("error connecting to redis: ", err) + deps.Log.Debug().Err(err).Msg("error connecting to redis") return nil, err } return &provider{ - ctx: ctx, - store: rdb, + config: cfg, + dependencies: deps, + ctx: ctx, + store: rdb, }, nil } - opt, err := redis.ParseURL(redisURL) + opt, err := redis.ParseURL(cfg.RedisURL) if err != nil { - log.Debug("error parsing redis url: ", err) + deps.Log.Debug().Err(err).Msg("error parsing redis url") return nil, err } opt.DialTimeout = dialTimeout @@ -70,11 +82,13 @@ func NewRedisProvider(redisURL string) (*provider, error) { ctx := context.Background() _, err = rdb.Ping(ctx).Result() if err != nil { - log.Debug("error connecting to redis: ", err) + deps.Log.Debug().Err(err).Msg("error connecting to redis") return nil, err } return &provider{ - ctx: ctx, - store: rdb, + config: cfg, + dependencies: deps, + ctx: ctx, + store: rdb, }, nil } diff --git a/internal/memory_store/redis/store.go b/internal/memory_store/redis/store.go new file mode 100644 index 000000000..ae5ebc48d --- /dev/null +++ b/internal/memory_store/redis/store.go @@ -0,0 +1,189 @@ +package redis + +import ( + "fmt" + "time" + + "github.com/authorizerdev/authorizer/internal/constants" +) + +var ( + // state store prefix + stateStorePrefix = "authorizer_state:" +) + +const mfaSessionPrefix = "mfa_session_" + +// SetUserSession sets the user session for given user identifier in form recipe:user_id +func (p *provider) SetUserSession(userId, key, token string, expiration int64) error { + currentTime := time.Now() + expireTime := time.Unix(expiration, 0) + duration := expireTime.Sub(currentTime) + err := p.store.Set(p.ctx, fmt.Sprintf("%s:%s", userId, key), token, duration).Err() + if err != nil { + p.dependencies.Log.Debug().Err(err).Msg("Error saving user session to redis") + return err + } + return nil +} + +// GetUserSession returns the user session from redis store. +func (p *provider) GetUserSession(userId, key string) (string, error) { + data, err := p.store.Get(p.ctx, fmt.Sprintf("%s:%s", userId, key)).Result() + if err != nil { + return "", err + } + return data, nil +} + +// DeleteUserSession deletes the user session from redis store. +func (p *provider) DeleteUserSession(userId, key string) error { + keys := []string{ + constants.TokenTypeSessionToken + "_" + key, + constants.TokenTypeAccessToken + "_" + key, + constants.TokenTypeRefreshToken + "_" + key, + } + for _, k := range keys { + if err := p.store.Del(p.ctx, fmt.Sprintf("%s:%s", userId, k)).Err(); err != nil { + p.dependencies.Log.Debug().Err(err).Msg("Error deleting user session from redis") + // continue + } + } + + return nil +} + +// DeleteAllUserSessions deletes all the user session from redis +func (p *provider) DeleteAllUserSessions(userID string) error { + res := p.store.Keys(p.ctx, fmt.Sprintf("*%s*", userID)) + if res.Err() != nil { + p.dependencies.Log.Debug().Err(res.Err()).Msg("Error getting all user sessions from redis") + return res.Err() + } + keys := res.Val() + for _, key := range keys { + err := p.store.Del(p.ctx, key).Err() + if err != nil { + p.dependencies.Log.Debug().Err(err).Msg("Error deleting all user sessions from redis") + continue + } + } + return nil +} + +// DeleteSessionForNamespace to delete session for a given namespace example google,github +func (p *provider) DeleteSessionForNamespace(namespace string) error { + res := p.store.Keys(p.ctx, fmt.Sprintf("%s:*", namespace)) + if res.Err() != nil { + p.dependencies.Log.Debug().Err(res.Err()).Msg("Error getting all user sessions from redis") + return res.Err() + } + keys := res.Val() + for _, key := range keys { + err := p.store.Del(p.ctx, key).Err() + if err != nil { + p.dependencies.Log.Debug().Err(err).Msg("Error deleting all user sessions from redis") + continue + } + } + return nil +} + +// SetMfaSession sets the mfa session with key and value of userId +func (p *provider) SetMfaSession(userId, key string, expiration int64) error { + currentTime := time.Now() + expireTime := time.Unix(expiration, 0) + duration := expireTime.Sub(currentTime) + err := p.store.Set(p.ctx, fmt.Sprintf("%s%s:%s", mfaSessionPrefix, userId, key), userId, duration).Err() + if err != nil { + p.dependencies.Log.Debug().Err(err).Msg("Error saving mfa session to redis") + return err + } + return nil +} + +// GetMfaSession returns value of given mfa session +func (p *provider) GetMfaSession(userId, key string) (string, error) { + data, err := p.store.Get(p.ctx, fmt.Sprintf("%s%s:%s", mfaSessionPrefix, userId, key)).Result() + if err != nil { + return "", err + } + return data, nil +} + +// GetAllMfaSessions returns all mfa sessions for given userId +func (p *provider) GetAllMfaSessions(userId string) ([]string, error) { + res := p.store.Keys(p.ctx, fmt.Sprintf("%s%s:*", mfaSessionPrefix, userId)) + if res.Err() != nil { + p.dependencies.Log.Debug().Err(res.Err()).Msg("Error getting all mfa sessions from redis") + return nil, res.Err() + } + keys := res.Val() + for i := 0; i < len(keys); i++ { + keys[i] = keys[i][len(mfaSessionPrefix)+len(userId)+1:] + } + return keys, nil +} + +// DeleteMfaSession deletes given mfa session from in-memory store. +func (p *provider) DeleteMfaSession(userId, key string) error { + if err := p.store.Del(p.ctx, fmt.Sprintf("%s%s:%s", mfaSessionPrefix, userId, key)).Err(); err != nil { + p.dependencies.Log.Debug().Err(err).Msg("Error deleting mfa session from redis") + // continue + } + return nil +} + +// SetState sets the state in redis store. +func (p *provider) SetState(key, value string) error { + err := p.store.Set(p.ctx, stateStorePrefix+key, value, 0).Err() + if err != nil { + p.dependencies.Log.Debug().Err(err).Msg("Error saving state to redis") + return err + } + + return nil +} + +// GetState gets the state from redis store. +func (p *provider) GetState(key string) (string, error) { + data, err := p.store.Get(p.ctx, stateStorePrefix+key).Result() + if err != nil { + p.dependencies.Log.Debug().Err(err).Msg("Error getting state from redis") + return "", err + } + + return data, err +} + +// RemoveState removes the state from redis store. +func (p *provider) RemoveState(key string) error { + err := p.store.Del(p.ctx, stateStorePrefix+key).Err() + if err != nil { + p.dependencies.Log.Debug().Err(err).Msg("Error deleting state from redis") + return err + } + + return nil +} + +// GetAllData returns all the data from the session store +// This is used for testing purposes only +func (p *provider) GetAllData() (map[string]string, error) { + res := p.store.Keys(p.ctx, "*") + if res.Err() != nil { + p.dependencies.Log.Debug().Err(res.Err()).Msg("Error getting all data from redis") + return nil, res.Err() + } + keys := res.Val() + data := make(map[string]string) + for _, key := range keys { + val, err := p.store.Get(p.ctx, key).Result() + if err != nil { + p.dependencies.Log.Debug().Err(err).Msg("Error getting all data from redis") + continue + } + data[key] = val + } + return data, nil +} diff --git a/internal/oauth/get_oauth_config.go b/internal/oauth/get_oauth_config.go new file mode 100644 index 000000000..d4b39eb56 --- /dev/null +++ b/internal/oauth/get_oauth_config.go @@ -0,0 +1,109 @@ +package oauth + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "golang.org/x/oauth2" + "golang.org/x/oauth2/endpoints" + + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/parsers" +) + +// GetOAuthConfig returns the OAuth config for the given provider +func (o *oauthProvider) GetOAuthConfig(ctx *gin.Context, provider string) (*oauth2.Config, error) { + hostname := parsers.GetHost(ctx) + redirectURL := fmt.Sprintf("%s/oauth_callback/%s", hostname, provider) + var clientID, clientSecret string + var endPoint *oauth2.Endpoint + var scopes []string + switch provider { + case constants.AuthRecipeMethodGoogle: + if o.GoogleClientID != "" && o.GoogleClientSecret != "" { + clientID = o.GoogleClientID + clientSecret = o.GoogleClientSecret + endPoint = &endpoints.Google + scopes = o.GoogleScopes + } + case constants.AuthRecipeMethodGithub: + if o.GithubClientID != "" && o.GithubClientSecret != "" { + clientID = o.GithubClientID + clientSecret = o.GithubClientSecret + endPoint = &endpoints.GitHub + scopes = o.GithubScopes + } + case constants.AuthRecipeMethodFacebook: + if o.FacebookClientID != "" && o.FacebookClientSecret != "" { + clientID = o.FacebookClientID + clientSecret = o.FacebookClientSecret + endPoint = &endpoints.Facebook + scopes = o.FacebookScopes + } + case constants.AuthRecipeMethodLinkedIn: + if o.LinkedinClientID != "" && o.LinkedinClientSecret != "" { + clientID = o.LinkedinClientID + clientSecret = o.LinkedinClientSecret + endPoint = &endpoints.LinkedIn + scopes = o.LinkedinScopes + } + case constants.AuthRecipeMethodApple: + if o.AppleClientID != "" && o.AppleClientSecret != "" { + clientID = o.AppleClientID + clientSecret = o.AppleClientSecret + endPoint = &endpoints.Apple + scopes = o.AppleScopes + } + case constants.AuthRecipeMethodTwitter: + if o.TwitterClientID != "" && o.TwitterClientSecret != "" { + clientID = o.TwitterClientID + clientSecret = o.TwitterClientSecret + endPoint = &endpoints.X + scopes = o.TwitterScopes + } + case constants.AuthRecipeMethodDiscord: + if o.DiscordClientID != "" && o.DiscordClientSecret != "" { + clientID = o.DiscordClientID + clientSecret = o.DiscordClientSecret + endPoint = &endpoints.Discord + scopes = o.DiscordScopes + } + case constants.AuthRecipeMethodMicrosoft: + if o.MicrosoftClientID != "" && o.MicrosoftClientSecret != "" { + ep := endpoints.AzureAD(o.MicrosoftTenantID) + clientID = o.MicrosoftClientID + clientSecret = o.MicrosoftClientSecret + endPoint = &ep + scopes = o.MicrosoftScopes + } + case constants.AuthRecipeMethodTwitch: + if o.TwitchClientID != "" && o.TwitchClientSecret != "" { + clientID = o.TwitchClientID + clientSecret = o.TwitchClientSecret + endPoint = &endpoints.Twitch + scopes = o.TwitchScopes + } + case constants.AuthRecipeMethodRoblox: + if o.RobloxClientID != "" && o.RobloxClientSecret != "" { + clientID = o.RobloxClientID + clientSecret = o.RobloxClientSecret + endPoint = &oauth2.Endpoint{ + AuthURL: "https://apis.roblox.com/oauth/v1/authorize", + TokenURL: "https://apis.roblox.com/oauth/v1/token", + } + scopes = o.RobloxScopes + } + default: + return nil, fmt.Errorf("unsupported provider: %s", provider) + } + if clientID == "" || clientSecret == "" { + return nil, fmt.Errorf("client ID or client secret is empty for provider: %s", provider) + } + return &oauth2.Config{ + ClientID: clientID, + ClientSecret: clientSecret, + RedirectURL: redirectURL, + Endpoint: *endPoint, + Scopes: scopes, + }, nil +} diff --git a/internal/oauth/provider.go b/internal/oauth/provider.go new file mode 100644 index 000000000..928115c60 --- /dev/null +++ b/internal/oauth/provider.go @@ -0,0 +1,39 @@ +package oauth + +import ( + "github.com/gin-gonic/gin" + "github.com/rs/zerolog" + "golang.org/x/oauth2" + + "github.com/authorizerdev/authorizer/internal/config" +) + +// Dependencies struct for memory store provider +type Dependencies struct { + Log *zerolog.Logger +} + +// oauthProvider is a struct that contains reference to the config and dependencies +// It is used to initialize the OAuth providers +type oauthProvider struct { + *config.Config + *Dependencies +} + +// Ensure interface is implemented +var _ Provider = &oauthProvider{} + +// Provider is the interface that provides the methods to interact with the oauth providers. +type Provider interface { + // GetOAuthConfig returns the OAuth config for the given provider + GetOAuthConfig(ctx *gin.Context, provider string) (*oauth2.Config, error) +} + +// New constructs a new graphql provider with given arguments +func New(cfg *config.Config, deps *Dependencies) (Provider, error) { + g := &oauthProvider{ + Config: cfg, + Dependencies: deps, + } + return g, nil +} diff --git a/server/parsers/url.go b/internal/parsers/url.go similarity index 76% rename from server/parsers/url.go rename to internal/parsers/url.go index 4eb067d8f..9a05ed300 100644 --- a/server/parsers/url.go +++ b/internal/parsers/url.go @@ -5,9 +5,6 @@ import ( "strings" "github.com/gin-gonic/gin" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" ) // GetHost returns hostname from request context @@ -15,15 +12,16 @@ import ( // if X-Authorizer-URL header is set it is given second highest priority // if above 2 are not set the requesting host name is used func GetHost(c *gin.Context) string { - authorizerURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) - if err != nil { - authorizerURL = "" - } - if authorizerURL != "" { - return strings.TrimSuffix(authorizerURL, "/") - } - - authorizerURL = c.Request.Header.Get("X-Authorizer-URL") + // TODO see how we can do based on config + // authorizerURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) + // if err != nil { + // authorizerURL = "" + // } + // if authorizerURL != "" { + // return strings.TrimSuffix(authorizerURL, "/") + // } + + authorizerURL := c.Request.Header.Get("X-Authorizer-URL") if authorizerURL != "" { return strings.TrimSuffix(authorizerURL, "/") } @@ -93,9 +91,6 @@ func GetDomainName(uri string) string { // GetAppURL to get /app url if not configured by user func GetAppURL(gc *gin.Context) string { - envAppURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppURL) - if envAppURL == "" || err != nil { - envAppURL = GetHost(gc) + "/app" - } + envAppURL := GetHost(gc) + "/app" return envAppURL } diff --git a/server/refs/bool.go b/internal/refs/bool.go similarity index 100% rename from server/refs/bool.go rename to internal/refs/bool.go diff --git a/server/refs/int.go b/internal/refs/int.go similarity index 100% rename from server/refs/int.go rename to internal/refs/int.go diff --git a/server/refs/string.go b/internal/refs/string.go similarity index 100% rename from server/refs/string.go rename to internal/refs/string.go diff --git a/internal/server/http_routes.go b/internal/server/http_routes.go new file mode 100644 index 000000000..8ecd88228 --- /dev/null +++ b/internal/server/http_routes.go @@ -0,0 +1,63 @@ +package server + +import ( + "encoding/json" + "html/template" + + "github.com/gin-gonic/gin" +) + +// NewRouter creates new gin router +func (s *server) NewRouter() *gin.Engine { + router := gin.New() + + router.Use(s.Dependencies.HTTPProvider.LoggerMiddleware()) + router.Use(s.Dependencies.HTTPProvider.ContextMiddleware()) + router.Use(s.Dependencies.HTTPProvider.CORSMiddleware()) + router.Use(s.Dependencies.HTTPProvider.ClientCheckMiddleware()) + + router.GET("/", s.Dependencies.HTTPProvider.RootHandler()) + router.GET("/health", s.Dependencies.HTTPProvider.HealthHandler()) + router.POST("/graphql", s.Dependencies.HTTPProvider.GraphqlHandler()) + router.GET("/playground", s.Dependencies.HTTPProvider.PlaygroundHandler()) + router.GET("/oauth_login/:oauth_provider", s.Dependencies.HTTPProvider.OAuthLoginHandler()) + router.GET("/oauth_callback/:oauth_provider", s.Dependencies.HTTPProvider.OAuthCallbackHandler()) + router.POST("/oauth_callback/:oauth_provider", s.Dependencies.HTTPProvider.OAuthCallbackHandler()) + router.GET("/verify_email", s.Dependencies.HTTPProvider.VerifyEmailHandler()) + // OPEN ID routes + router.GET("/.well-known/openid-configuration", s.Dependencies.HTTPProvider.OpenIDConfigurationHandler()) + router.GET("/.well-known/jwks.json", s.Dependencies.HTTPProvider.JWKsHandler()) + router.GET("/authorize", s.Dependencies.HTTPProvider.AuthorizeHandler()) + router.GET("/userinfo", s.Dependencies.HTTPProvider.UserInfoHandler()) + router.GET("/logout", s.Dependencies.HTTPProvider.LogoutHandler()) + router.POST("/oauth/token", s.Dependencies.HTTPProvider.TokenHandler()) + router.POST("/oauth/revoke", s.Dependencies.HTTPProvider.RevokeRefreshTokenHandler()) + + // Set up template functions for JSON encoding + router.SetFuncMap(template.FuncMap{ + "json": func(v interface{}) template.JS { + a, _ := json.Marshal(v) + return template.JS(a) + }, + }) + router.LoadHTMLGlob("web/templates/*") + // // login page app related routes. + app := router.Group("/app") + { + app.Static("/favicon_io", "web/app/favicon_io") + app.Static("/build", "web/app/build") + app.GET("/", s.Dependencies.HTTPProvider.AppHandler()) + app.GET("/:page", s.Dependencies.HTTPProvider.AppHandler()) + } + + // // dashboard related routes + dashboard := router.Group("/dashboard") + { + dashboard.Static("/favicon_io", "web/dashboard/favicon_io") + dashboard.Static("/build", "web/dashboard/build") + dashboard.Static("/public", "web/dashboard/public") + dashboard.GET("/", s.Dependencies.HTTPProvider.DashboardHandler()) + dashboard.GET("/:page", s.Dependencies.HTTPProvider.DashboardHandler()) + } + return router +} diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 000000000..3c361a63d --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,60 @@ +package server + +import ( + "context" + "fmt" + + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/graphql" + "github.com/authorizerdev/authorizer/internal/http_handlers" +) + +// Configuration of a server. +type Config struct { + // Host address to accept requests on + Host string + // Port number to serve HTTP requests on + HTTPPort int + // Port number to serve Metrics requests on + MetricsPort int +} + +// Dependencies for a server +type Dependencies struct { + Log *zerolog.Logger + GraphQLProvider graphql.Provider + HTTPProvider http_handlers.Provider +} + +// New constructs a new server with given arguments +func New(cfg *Config, deps *Dependencies) (*server, error) { + s := &server{ + Config: cfg, + Dependencies: deps, + } + return s, nil +} + +// Network server +type server struct { + Config *Config + Dependencies *Dependencies +} + +// Run the server until the given context is canceled +func (s *server) Run(ctx context.Context) error { + // Create new router + ginRouter := s.NewRouter() + // Start the server + go func() { + s.Dependencies.Log.Info().Str("host", s.Config.Host).Int("port", s.Config.HTTPPort).Msg("Starting HTTP server") + err := ginRouter.Run(s.Config.Host + ":" + fmt.Sprintf("%d", s.Config.HTTPPort)) + if err != nil { + s.Dependencies.Log.Error().Err(err).Msg("HTTP server failed") + } + }() + // Wait until context closed + <-ctx.Done() + return nil +} diff --git a/internal/sms/provider.go b/internal/sms/provider.go new file mode 100644 index 000000000..b5d95aec8 --- /dev/null +++ b/internal/sms/provider.go @@ -0,0 +1,33 @@ +package sms + +import ( + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/sms/twilio" + "github.com/rs/zerolog" +) + +// Dependencies for sms provider +type Dependencies struct { + Log *zerolog.Logger +} + +// Provider interface to send sms +type Provider interface { + // SendSMS sends sms + SendSMS(sendTo, messageBody string) error +} + +// New returns a new sms provider +func New(cfg *config.Config, deps *Dependencies) (Provider, error) { + var provider Provider + var err error + if cfg.TwilioAPIKey != "" && cfg.TwilioAPISecret != "" && cfg.TwilioAccountSID != "" && cfg.TwilioSender != "" { + provider, err = twilio.NewTwilioProvider(cfg, &twilio.Dependencies{ + Log: deps.Log, + }) + if err != nil { + return nil, err + } + } + return provider, nil +} diff --git a/internal/sms/twilio/provider.go b/internal/sms/twilio/provider.go new file mode 100644 index 000000000..a91dcf189 --- /dev/null +++ b/internal/sms/twilio/provider.go @@ -0,0 +1,42 @@ +package twilio + +import ( + "fmt" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/rs/zerolog" +) + +// Dependencies struct for twilio provider +type Dependencies struct { + Log *zerolog.Logger +} + +type provider struct { + config *config.Config + dependencies *Dependencies +} + +// NewTwilioProvider returns a new twilio provider +func NewTwilioProvider(cfg *config.Config, deps *Dependencies) (*provider, error) { + if cfg.TwilioAPIKey == "" { + deps.Log.Debug().Msg("missing twilio api key") + return nil, fmt.Errorf("missing twilio api key") + } + if cfg.TwilioAPISecret == "" { + deps.Log.Debug().Msg("missing twilio api secret") + return nil, fmt.Errorf("missing twilio api secret") + } + if cfg.TwilioSender == "" { + deps.Log.Debug().Msg("missing twilio sender") + return nil, fmt.Errorf("missing twilio sender") + } + if cfg.TwilioAccountSID == "" { + deps.Log.Debug().Msg("missing twilio account sid") + return nil, fmt.Errorf("missing twilio account sid") + } + return &provider{ + config: cfg, + dependencies: deps, + }, nil +} diff --git a/internal/sms/twilio/sms.go b/internal/sms/twilio/sms.go new file mode 100644 index 000000000..caf8a99bc --- /dev/null +++ b/internal/sms/twilio/sms.go @@ -0,0 +1,26 @@ +package twilio + +import ( + twilio "github.com/twilio/twilio-go" + api "github.com/twilio/twilio-go/rest/api/v2010" +) + +// SendSMS util to send sms +func (p *provider) SendSMS(sendTo, messageBody string) error { + client := twilio.NewRestClientWithParams(twilio.ClientParams{ + Username: p.config.TwilioAPIKey, + Password: p.config.TwilioAPISecret, + AccountSid: p.config.TwilioAccountSID, + }) + message := &api.CreateMessageParams{} + message.SetBody(messageBody) + message.SetFrom(p.config.TwilioSender) + message.SetTo(sendTo) + _, err := client.Api.CreateMessage(message) + if err != nil { + p.dependencies.Log.Debug().Err(err).Msg("error sending sms") + return err + } + + return nil +} diff --git a/server/db/providers/arangodb/authenticator.go b/internal/storage/db/arangodb/authenticator.go similarity index 75% rename from server/db/providers/arangodb/authenticator.go rename to internal/storage/db/arangodb/authenticator.go index c701ebc73..c080fc02b 100644 --- a/server/db/providers/arangodb/authenticator.go +++ b/internal/storage/db/arangodb/authenticator.go @@ -5,14 +5,13 @@ import ( "fmt" "time" - "github.com/google/uuid" - arangoDriver "github.com/arangodb/go-driver" + "github.com/google/uuid" - "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) -func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) AddAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method) if exists != nil { return authenticators, nil @@ -25,7 +24,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models. authenticators.CreatedAt = time.Now().Unix() authenticators.UpdatedAt = time.Now().Unix() - authenticatorsCollection, _ := p.db.Collection(ctx, models.Collections.Authenticators) + authenticatorsCollection, _ := p.db.Collection(ctx, schemas.Collections.Authenticators) meta, err := authenticatorsCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), authenticators) if err != nil { return nil, err @@ -36,10 +35,10 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models. return authenticators, nil } -func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { authenticators.UpdatedAt = time.Now().Unix() - collection, _ := p.db.Collection(ctx, models.Collections.Authenticators) + collection, _ := p.db.Collection(ctx, schemas.Collections.Authenticators) meta, err := collection.UpdateDocument(ctx, authenticators.Key, authenticators) if err != nil { return nil, err @@ -50,9 +49,9 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode return authenticators, nil } -func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) { - var authenticators *models.Authenticator - query := fmt.Sprintf("FOR d in %s FILTER d.user_id == @user_id AND d.method == @method LIMIT 1 RETURN d", models.Collections.Authenticators) +func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*schemas.Authenticator, error) { + var authenticators *schemas.Authenticator + query := fmt.Sprintf("FOR d in %s FILTER d.user_id == @user_id AND d.method == @method LIMIT 1 RETURN d", schemas.Collections.Authenticators) bindVars := map[string]interface{}{ "user_id": userId, "method": authenticatorType, diff --git a/server/db/providers/arangodb/email_template.go b/internal/storage/db/arangodb/email_template.go similarity index 62% rename from server/db/providers/arangodb/email_template.go rename to internal/storage/db/arangodb/email_template.go index 30c0fd0b8..e5cded709 100644 --- a/server/db/providers/arangodb/email_template.go +++ b/internal/storage/db/arangodb/email_template.go @@ -6,13 +6,14 @@ import ( "time" arangoDriver "github.com/arangodb/go-driver" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() emailTemplate.Key = emailTemplate.ID @@ -20,63 +21,63 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.E emailTemplate.Key = emailTemplate.ID emailTemplate.CreatedAt = time.Now().Unix() emailTemplate.UpdatedAt = time.Now().Unix() - emailTemplateCollection, _ := p.db.Collection(ctx, models.Collections.EmailTemplate) - _, err := emailTemplateCollection.CreateDocument(ctx, emailTemplate) + emailTemplateCollection, _ := p.db.Collection(ctx, schemas.Collections.EmailTemplate) + meta, err := emailTemplateCollection.CreateDocument(ctx, emailTemplate) if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + + emailTemplate.Key = meta.Key + emailTemplate.ID = meta.ID.String() + return emailTemplate, nil } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { emailTemplate.UpdatedAt = time.Now().Unix() - emailTemplateCollection, _ := p.db.Collection(ctx, models.Collections.EmailTemplate) + emailTemplateCollection, _ := p.db.Collection(ctx, schemas.Collections.EmailTemplate) meta, err := emailTemplateCollection.UpdateDocument(ctx, emailTemplate.Key, emailTemplate) if err != nil { return nil, err } emailTemplate.Key = meta.Key emailTemplate.ID = meta.ID.String() - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { - emailTemplates := []*model.EmailTemplate{} - query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.EmailTemplate, pagination.Offset, pagination.Limit) +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) ([]*schemas.EmailTemplate, *model.Pagination, error) { + emailTemplates := []*schemas.EmailTemplate{} + query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", schemas.Collections.EmailTemplate, pagination.Offset, pagination.Limit) sctx := arangoDriver.WithQueryFullCount(ctx) cursor, err := p.db.Query(sctx, query, nil) if err != nil { - return nil, err + return nil, nil, err } defer cursor.Close() paginationClone := pagination paginationClone.Total = cursor.Statistics().FullCount() for { - var emailTemplate *models.EmailTemplate + var emailTemplate *schemas.EmailTemplate meta, err := cursor.ReadDocument(ctx, &emailTemplate) if arangoDriver.IsNoMoreDocuments(err) { break } else if err != nil { - return nil, err + return nil, nil, err } if meta.Key != "" { - emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate()) + emailTemplates = append(emailTemplates, emailTemplate) } } - return &model.EmailTemplates{ - Pagination: paginationClone, - EmailTemplates: emailTemplates, - }, nil + return emailTemplates, paginationClone, nil } // GetEmailTemplateByID to get EmailTemplate by id -func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { - var emailTemplate *models.EmailTemplate - query := fmt.Sprintf("FOR d in %s FILTER d._key == @email_template_id RETURN d", models.Collections.EmailTemplate) +func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*schemas.EmailTemplate, error) { + var emailTemplate *schemas.EmailTemplate + query := fmt.Sprintf("FOR d in %s FILTER d._id == @id RETURN d", schemas.Collections.EmailTemplate) bindVars := map[string]interface{}{ - "email_template_id": emailTemplateID, + "id": emailTemplateID, } cursor, err := p.db.Query(ctx, query, bindVars) if err != nil { @@ -95,13 +96,13 @@ func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID str return nil, err } } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // GetEmailTemplateByEventName to get EmailTemplate by event_name -func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { - var emailTemplate *models.EmailTemplate - query := fmt.Sprintf("FOR d in %s FILTER d.event_name == @event_name RETURN d", models.Collections.EmailTemplate) +func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*schemas.EmailTemplate, error) { + var emailTemplate *schemas.EmailTemplate + query := fmt.Sprintf("FOR d in %s FILTER d.event_name == @event_name RETURN d", schemas.Collections.EmailTemplate) bindVars := map[string]interface{}{ "event_name": eventName, } @@ -122,13 +123,13 @@ func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName st return nil, err } } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // DeleteEmailTemplate to delete EmailTemplate -func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error { - eventTemplateCollection, _ := p.db.Collection(ctx, models.Collections.EmailTemplate) - _, err := eventTemplateCollection.RemoveDocument(ctx, emailTemplate.ID) +func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) error { + eventTemplateCollection, _ := p.db.Collection(ctx, schemas.Collections.EmailTemplate) + _, err := eventTemplateCollection.RemoveDocument(ctx, emailTemplate.Key) if err != nil { return err } diff --git a/server/db/providers/arangodb/env.go b/internal/storage/db/arangodb/env.go similarity index 68% rename from server/db/providers/arangodb/env.go rename to internal/storage/db/arangodb/env.go index 27f7c25f5..bce36a19f 100644 --- a/server/db/providers/arangodb/env.go +++ b/internal/storage/db/arangodb/env.go @@ -8,11 +8,11 @@ import ( arangoDriver "github.com/arangodb/go-driver" "github.com/google/uuid" - "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *schemas.Env) (*schemas.Env, error) { if env.ID == "" { env.ID = uuid.New().String() env.Key = env.ID @@ -20,7 +20,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er env.CreatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix() - configCollection, _ := p.db.Collection(ctx, models.Collections.Env) + configCollection, _ := p.db.Collection(ctx, schemas.Collections.Env) meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), env) if err != nil { return nil, err @@ -31,9 +31,9 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er } // 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 *schemas.Env) (*schemas.Env, error) { env.UpdatedAt = time.Now().Unix() - collection, _ := p.db.Collection(ctx, models.Collections.Env) + collection, _ := p.db.Collection(ctx, schemas.Collections.Env) meta, err := collection.UpdateDocument(ctx, env.Key, env) if err != nil { return nil, err @@ -45,9 +45,9 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { - var env *models.Env - query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.Env) +func (p *provider) GetEnv(ctx context.Context) (*schemas.Env, error) { + var env *schemas.Env + query := fmt.Sprintf("FOR d in %s RETURN d", schemas.Collections.Env) cursor, err := p.db.Query(ctx, query, nil) if err != nil { return nil, err diff --git a/server/db/providers/arangodb/otp.go b/internal/storage/db/arangodb/otp.go similarity index 75% rename from server/db/providers/arangodb/otp.go rename to internal/storage/db/arangodb/otp.go index 3f8f46497..dec00b86e 100644 --- a/server/db/providers/arangodb/otp.go +++ b/internal/storage/db/arangodb/otp.go @@ -7,22 +7,23 @@ import ( "time" "github.com/arangodb/go-driver" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // UpsertOTP to add or update otp -func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { +func (p *provider) UpsertOTP(ctx context.Context, otpParam *schemas.OTP) (*schemas.OTP, error) { // check if email or phone number is present if otpParam.Email == "" && otpParam.PhoneNumber == "" { return nil, errors.New("email or phone_number is required") } - uniqueField := models.FieldNameEmail + uniqueField := schemas.FieldNameEmail if otpParam.Email == "" && otpParam.PhoneNumber != "" { - uniqueField = models.FieldNamePhoneNumber + uniqueField = schemas.FieldNamePhoneNumber } - var otp *models.OTP - if uniqueField == models.FieldNameEmail { + var otp *schemas.OTP + if uniqueField == schemas.FieldNameEmail { otp, _ = p.GetOTPByEmail(ctx, otpParam.Email) } else { otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber) @@ -30,7 +31,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models shouldCreate := false if otp == nil { id := uuid.NewString() - otp = &models.OTP{ + otp = &schemas.OTP{ ID: id, Key: id, Otp: otpParam.Otp, @@ -45,7 +46,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models otp.ExpiresAt = otpParam.ExpiresAt } otp.UpdatedAt = time.Now().Unix() - otpCollection, _ := p.db.Collection(ctx, models.Collections.OTP) + otpCollection, _ := p.db.Collection(ctx, schemas.Collections.OTP) var meta driver.DocumentMeta var err error if shouldCreate { @@ -56,15 +57,16 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models if err != nil { return nil, err } + otp.Key = meta.Key otp.ID = meta.ID.String() return otp, nil } // GetOTPByEmail to get otp for a given email address -func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { - var otp *models.OTP - query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.OTP) +func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*schemas.OTP, error) { + var otp *schemas.OTP + query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", schemas.Collections.OTP) bindVars := map[string]interface{}{ "email": emailAddress, } @@ -89,9 +91,9 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod } // GetOTPByPhoneNumber to get otp for a given phone number -func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { - var otp *models.OTP - query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.OTP) +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.OTP, error) { + var otp *schemas.OTP + query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", schemas.Collections.OTP) bindVars := map[string]interface{}{ "phone_number": phoneNumber, } @@ -116,9 +118,9 @@ func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) } // DeleteOTP to delete otp -func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { - otpCollection, _ := p.db.Collection(ctx, models.Collections.OTP) - _, err := otpCollection.RemoveDocument(ctx, otp.ID) +func (p *provider) DeleteOTP(ctx context.Context, otp *schemas.OTP) error { + otpCollection, _ := p.db.Collection(ctx, schemas.Collections.OTP) + _, err := otpCollection.RemoveDocument(ctx, otp.Key) if err != nil { return err } diff --git a/server/db/providers/arangodb/provider.go b/internal/storage/db/arangodb/provider.go similarity index 64% rename from server/db/providers/arangodb/provider.go rename to internal/storage/db/arangodb/provider.go index f78712333..ec73503ee 100644 --- a/server/db/providers/arangodb/provider.go +++ b/internal/storage/db/arangodb/provider.go @@ -9,12 +9,21 @@ import ( arangoDriver "github.com/arangodb/go-driver" "github.com/arangodb/go-driver/http" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) +// Dependencies struct the arangodb data store provider +type Dependencies struct { + Log *zerolog.Logger +} + type provider struct { - db arangoDriver.Database + config *config.Config + dependencies *Dependencies + db arangoDriver.Database } // for this we need arangodb instance up and running @@ -22,12 +31,12 @@ type provider struct { // docker run -p 8529:8529 -e ARANGO_ROOT_PASSWORD=root arangodb/arangodb:3.8.4 // NewProvider to initialize arangodb connection -func NewProvider() (*provider, error) { +func NewProvider(cfg *config.Config, deps *Dependencies) (*provider, error) { ctx := context.Background() - dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL - dbUsername := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseUsername - dbPassword := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePassword - dbCACertificate := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseCACert + dbURL := cfg.DatabaseURL + dbUsername := cfg.DatabaseUsername + dbPassword := cfg.DatabasePassword + dbCACertificate := cfg.DatabaseCACert httpConfig := http.ConnectionConfig{ Endpoints: []string{dbURL}, } @@ -62,7 +71,10 @@ func NewProvider() (*provider, error) { return nil, err } var arangodb arangoDriver.Database - dbName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName + dbName := cfg.DatabaseName + if dbName == "" { + return nil, fmt.Errorf("database name is required") + } arangodb_exists, err := arangoClient.DatabaseExists(ctx, dbName) if err != nil { return nil, err @@ -78,17 +90,17 @@ func NewProvider() (*provider, error) { return nil, err } } - userCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.User) + userCollectionExists, err := arangodb.CollectionExists(ctx, schemas.Collections.User) if err != nil { return nil, err } if !userCollectionExists { - _, err = arangodb.CreateCollection(ctx, models.Collections.User, nil) + _, err = arangodb.CreateCollection(ctx, schemas.Collections.User, nil) if err != nil { return nil, err } } - userCollection, err := arangodb.Collection(ctx, models.Collections.User) + userCollection, err := arangodb.Collection(ctx, schemas.Collections.User) if err != nil { return nil, err } @@ -101,17 +113,17 @@ func NewProvider() (*provider, error) { Sparse: true, }) - verificationRequestCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.VerificationRequest) + verificationRequestCollectionExists, err := arangodb.CollectionExists(ctx, schemas.Collections.VerificationRequest) if err != nil { return nil, err } if !verificationRequestCollectionExists { - _, err = arangodb.CreateCollection(ctx, models.Collections.VerificationRequest, nil) + _, err = arangodb.CreateCollection(ctx, schemas.Collections.VerificationRequest, nil) if err != nil { return nil, err } } - verificationRequestCollection, err := arangodb.Collection(ctx, models.Collections.VerificationRequest) + verificationRequestCollection, err := arangodb.Collection(ctx, schemas.Collections.VerificationRequest) if err != nil { return nil, err } @@ -123,44 +135,44 @@ func NewProvider() (*provider, error) { Sparse: true, }) - sessionCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Session) + sessionCollectionExists, err := arangodb.CollectionExists(ctx, schemas.Collections.Session) if err != nil { return nil, err } if !sessionCollectionExists { - _, err = arangodb.CreateCollection(ctx, models.Collections.Session, nil) + _, err = arangodb.CreateCollection(ctx, schemas.Collections.Session, nil) if err != nil { return nil, err } } - sessionCollection, err := arangodb.Collection(ctx, models.Collections.Session) + sessionCollection, err := arangodb.Collection(ctx, schemas.Collections.Session) if err != nil { return nil, err } sessionCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{ Sparse: true, }) - envCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Env) + envCollectionExists, err := arangodb.CollectionExists(ctx, schemas.Collections.Env) if err != nil { return nil, err } if !envCollectionExists { - _, err = arangodb.CreateCollection(ctx, models.Collections.Env, nil) + _, err = arangodb.CreateCollection(ctx, schemas.Collections.Env, nil) if err != nil { return nil, err } } - webhookCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Webhook) + webhookCollectionExists, err := arangodb.CollectionExists(ctx, schemas.Collections.Webhook) if err != nil { return nil, err } if !webhookCollectionExists { - _, err = arangodb.CreateCollection(ctx, models.Collections.Webhook, nil) + _, err = arangodb.CreateCollection(ctx, schemas.Collections.Webhook, nil) if err != nil { return nil, err } } - webhookCollection, err := arangodb.Collection(ctx, models.Collections.Webhook) + webhookCollection, err := arangodb.Collection(ctx, schemas.Collections.Webhook) if err != nil { return nil, err } @@ -169,17 +181,17 @@ func NewProvider() (*provider, error) { Sparse: true, }) - webhookLogCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.WebhookLog) + webhookLogCollectionExists, err := arangodb.CollectionExists(ctx, schemas.Collections.WebhookLog) if err != nil { return nil, err } if !webhookLogCollectionExists { - _, err = arangodb.CreateCollection(ctx, models.Collections.WebhookLog, nil) + _, err = arangodb.CreateCollection(ctx, schemas.Collections.WebhookLog, nil) if err != nil { return nil, err } } - webhookLogCollection, err := arangodb.Collection(ctx, models.Collections.WebhookLog) + webhookLogCollection, err := arangodb.Collection(ctx, schemas.Collections.WebhookLog) if err != nil { return nil, err } @@ -187,17 +199,17 @@ func NewProvider() (*provider, error) { Sparse: true, }) - emailTemplateCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.EmailTemplate) + emailTemplateCollectionExists, err := arangodb.CollectionExists(ctx, schemas.Collections.EmailTemplate) if err != nil { return nil, err } if !emailTemplateCollectionExists { - _, err = arangodb.CreateCollection(ctx, models.Collections.EmailTemplate, nil) + _, err = arangodb.CreateCollection(ctx, schemas.Collections.EmailTemplate, nil) if err != nil { return nil, err } } - emailTemplateCollection, err := arangodb.Collection(ctx, models.Collections.EmailTemplate) + emailTemplateCollection, err := arangodb.Collection(ctx, schemas.Collections.EmailTemplate) if err != nil { return nil, err } @@ -206,37 +218,37 @@ func NewProvider() (*provider, error) { Sparse: true, }) - otpCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.OTP) + otpCollectionExists, err := arangodb.CollectionExists(ctx, schemas.Collections.OTP) if err != nil { return nil, err } if !otpCollectionExists { - _, err = arangodb.CreateCollection(ctx, models.Collections.OTP, nil) + _, err = arangodb.CreateCollection(ctx, schemas.Collections.OTP, nil) if err != nil { return nil, err } } - otpCollection, err := arangodb.Collection(ctx, models.Collections.OTP) + otpCollection, err := arangodb.Collection(ctx, schemas.Collections.OTP) if err != nil { return nil, err } - otpCollection.EnsureHashIndex(ctx, []string{models.FieldNameEmail, models.FieldNamePhoneNumber}, &arangoDriver.EnsureHashIndexOptions{ + otpCollection.EnsureHashIndex(ctx, []string{schemas.FieldNameEmail, schemas.FieldNamePhoneNumber}, &arangoDriver.EnsureHashIndexOptions{ Unique: true, Sparse: true, }) //authenticators table define - authenticatorsCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Authenticators) + authenticatorsCollectionExists, err := arangodb.CollectionExists(ctx, schemas.Collections.Authenticators) if err != nil { return nil, err } if !authenticatorsCollectionExists { - _, err = arangodb.CreateCollection(ctx, models.Collections.Authenticators, nil) + _, err = arangodb.CreateCollection(ctx, schemas.Collections.Authenticators, nil) if err != nil { return nil, err } } - authenticatorsCollection, err := arangodb.Collection(ctx, models.Collections.Authenticators) + authenticatorsCollection, err := arangodb.Collection(ctx, schemas.Collections.Authenticators) if err != nil { return nil, err } @@ -245,6 +257,8 @@ func NewProvider() (*provider, error) { }) return &provider{ - db: arangodb, + config: cfg, + dependencies: deps, + db: arangodb, }, err } diff --git a/server/db/providers/arangodb/session.go b/internal/storage/db/arangodb/session.go similarity index 64% rename from server/db/providers/arangodb/session.go rename to internal/storage/db/arangodb/session.go index 5dc981d38..b3a9eeccb 100644 --- a/server/db/providers/arangodb/session.go +++ b/internal/storage/db/arangodb/session.go @@ -4,19 +4,17 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/google/uuid" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session *models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *schemas.Session) error { if session.ID == "" { - session.ID = uuid.New().String() session.Key = session.ID } session.CreatedAt = time.Now().Unix() session.UpdatedAt = time.Now().Unix() - sessionCollection, _ := p.db.Collection(ctx, models.Collections.Session) + sessionCollection, _ := p.db.Collection(ctx, schemas.Collections.Session) _, err := sessionCollection.CreateDocument(ctx, session) if err != nil { return err @@ -25,6 +23,7 @@ func (p *provider) AddSession(ctx context.Context, session *models.Session) erro } // DeleteSession to delete session information from database +// TODO: Implement this function func (p *provider) DeleteSession(ctx context.Context, userId string) error { return nil } diff --git a/server/db/providers/arangodb/user.go b/internal/storage/db/arangodb/user.go similarity index 73% rename from server/db/providers/arangodb/user.go rename to internal/storage/db/arangodb/user.go index 5caca74a2..0477e1c58 100644 --- a/server/db/providers/arangodb/user.go +++ b/internal/storage/db/arangodb/user.go @@ -10,26 +10,20 @@ import ( arangoDriver "github.com/arangodb/go-driver" "github.com/google/uuid" - "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/authorizerdev/authorizer/server/refs" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { if user.ID == "" { user.ID = uuid.New().String() user.Key = user.ID } if user.Roles == "" { - defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - return nil, err - } - user.Roles = defaultRoles + user.Roles = strings.Join(p.config.DefaultRoles, ",") } if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" { @@ -44,7 +38,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User user.CreatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix() - userCollection, _ := p.db.Collection(ctx, models.Collections.User) + userCollection, _ := p.db.Collection(ctx, schemas.Collections.User) meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), user) if err != nil { return nil, err @@ -56,10 +50,10 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User } // UpdateUser to update user information in database -func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) UpdateUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { user.UpdatedAt = time.Now().Unix() - collection, _ := p.db.Collection(ctx, models.Collections.User) + collection, _ := p.db.Collection(ctx, schemas.Collections.User) meta, err := collection.UpdateDocument(ctx, user.Key, user) if err != nil { return nil, err @@ -71,13 +65,13 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { - collection, _ := p.db.Collection(ctx, models.Collections.User) +func (p *provider) DeleteUser(ctx context.Context, user *schemas.User) error { + collection, _ := p.db.Collection(ctx, schemas.Collections.User) _, err := collection.RemoveDocument(ctx, user.Key) if err != nil { return err } - query := fmt.Sprintf(`FOR d IN %s FILTER d.user_id == @user_id REMOVE { _key: d._key } IN %s`, models.Collections.Session, models.Collections.Session) + query := fmt.Sprintf(`FOR d IN %s FILTER d.user_id == @user_id REMOVE { _key: d._key } IN %s`, schemas.Collections.Session, schemas.Collections.Session) bindVars := map[string]interface{}{ "user_id": user.Key, } @@ -90,40 +84,37 @@ func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { - var users []*model.User +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) ([]*schemas.User, *model.Pagination, error) { + var users []*schemas.User sctx := arangoDriver.WithQueryFullCount(ctx) - query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.User, pagination.Offset, pagination.Limit) + query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", schemas.Collections.User, pagination.Offset, pagination.Limit) cursor, err := p.db.Query(sctx, query, nil) if err != nil { - return nil, err + return nil, nil, err } defer cursor.Close() paginationClone := pagination paginationClone.Total = cursor.Statistics().FullCount() for { - var user *models.User + var user *schemas.User meta, err := cursor.ReadDocument(ctx, &user) if arangoDriver.IsNoMoreDocuments(err) { break } else if err != nil { - return nil, err + return nil, nil, err } if meta.Key != "" { - users = append(users, user.AsAPIUser()) + users = append(users, user) } } - return &model.Users{ - Pagination: paginationClone, - Users: users, - }, nil + return users, paginationClone, 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 - query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.User) +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*schemas.User, error) { + var user *schemas.User + query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", schemas.Collections.User) bindVars := map[string]interface{}{ "email": email, } @@ -148,9 +139,9 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us } // 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 - query := fmt.Sprintf("FOR d in %s FILTER d._id == @id LIMIT 1 RETURN d", models.Collections.User) +func (p *provider) GetUserByID(ctx context.Context, id string) (*schemas.User, error) { + var user *schemas.User + query := fmt.Sprintf("FOR d in %s FILTER d._id == @id LIMIT 1 RETURN d", schemas.Collections.User) bindVars := map[string]interface{}{ "id": id, } @@ -191,9 +182,9 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } keysArray = strings.Trim(keysArray, " ") keysArray = strings.TrimSuffix(keysArray, ",") - query = fmt.Sprintf("FOR u IN %s FILTER u._id IN [%s] UPDATE u._key with %s IN %s", models.Collections.User, keysArray, string(userInfoBytes), models.Collections.User) + query = fmt.Sprintf("FOR u IN %s FILTER u._id IN [%s] UPDATE u._key with %s IN %s", schemas.Collections.User, keysArray, string(userInfoBytes), schemas.Collections.User) } else { - query = fmt.Sprintf("FOR u IN %s UPDATE u._key with %s IN %s", models.Collections.User, string(userInfoBytes), models.Collections.User) + query = fmt.Sprintf("FOR u IN %s UPDATE u._key with %s IN %s", schemas.Collections.User, string(userInfoBytes), schemas.Collections.User) } _, err = p.db.Query(ctx, query, nil) if err != nil { @@ -203,9 +194,9 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } // GetUserByPhoneNumber to get user information from database using phone number -func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) { - var user *models.User - query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.User) +func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.User, error) { + var user *schemas.User + query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", schemas.Collections.User) bindVars := map[string]interface{}{ "phone_number": phoneNumber, } diff --git a/server/db/providers/arangodb/verification_requests.go b/internal/storage/db/arangodb/verification_requests.go similarity index 71% rename from server/db/providers/arangodb/verification_requests.go rename to internal/storage/db/arangodb/verification_requests.go index 2b12a994d..00a4a59a1 100644 --- a/server/db/providers/arangodb/verification_requests.go +++ b/internal/storage/db/arangodb/verification_requests.go @@ -6,20 +6,21 @@ import ( "time" arangoDriver "github.com/arangodb/go-driver" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) (*schemas.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() verificationRequest.Key = verificationRequest.ID } verificationRequest.CreatedAt = time.Now().Unix() verificationRequest.UpdatedAt = time.Now().Unix() - verificationRequestRequestCollection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest) + verificationRequestRequestCollection, _ := p.db.Collection(ctx, schemas.Collections.VerificationRequest) meta, err := verificationRequestRequestCollection.CreateDocument(ctx, verificationRequest) if err != nil { return nil, err @@ -30,9 +31,9 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { - var verificationRequest *models.VerificationRequest - query := fmt.Sprintf("FOR d in %s FILTER d.token == @token LIMIT 1 RETURN d", models.Collections.VerificationRequest) +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*schemas.VerificationRequest, error) { + var verificationRequest *schemas.VerificationRequest + query := fmt.Sprintf("FOR d in %s FILTER d.token == @token LIMIT 1 RETURN d", schemas.Collections.VerificationRequest) bindVars := map[string]interface{}{ "token": token, } @@ -57,9 +58,9 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { - var verificationRequest *models.VerificationRequest - query := fmt.Sprintf("FOR d in %s FILTER d.email == @email FILTER d.identifier == @identifier LIMIT 1 RETURN d", models.Collections.VerificationRequest) +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*schemas.VerificationRequest, error) { + var verificationRequest *schemas.VerificationRequest + query := fmt.Sprintf("FOR d in %s FILTER d.email == @email FILTER d.identifier == @identifier LIMIT 1 RETURN d", schemas.Collections.VerificationRequest) bindVars := map[string]interface{}{ "email": email, "identifier": identifier, @@ -85,41 +86,38 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { - var verificationRequests []*model.VerificationRequest +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) ([]*schemas.VerificationRequest, *model.Pagination, error) { + var verificationRequests []*schemas.VerificationRequest sctx := arangoDriver.WithQueryFullCount(ctx) - query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.VerificationRequest, pagination.Offset, pagination.Limit) + query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", schemas.Collections.VerificationRequest, pagination.Offset, pagination.Limit) cursor, err := p.db.Query(sctx, query, nil) if err != nil { - return nil, err + return nil, nil, err } defer cursor.Close() paginationClone := pagination paginationClone.Total = cursor.Statistics().FullCount() for { - var verificationRequest *models.VerificationRequest + var verificationRequest *schemas.VerificationRequest meta, err := cursor.ReadDocument(ctx, &verificationRequest) if arangoDriver.IsNoMoreDocuments(err) { break } else if err != nil { - return nil, err + return nil, nil, err } if meta.Key != "" { - verificationRequests = append(verificationRequests, verificationRequest.AsAPIVerificationRequest()) + verificationRequests = append(verificationRequests, verificationRequest) } } - return &model.VerificationRequests{ - VerificationRequests: verificationRequests, - Pagination: paginationClone, - }, nil + return verificationRequests, paginationClone, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { - collection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest) +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) error { + collection, _ := p.db.Collection(ctx, schemas.Collections.VerificationRequest) _, err := collection.RemoveDocument(ctx, verificationRequest.Key) if err != nil { return err diff --git a/server/db/providers/arangodb/webhook.go b/internal/storage/db/arangodb/webhook.go similarity index 59% rename from server/db/providers/arangodb/webhook.go rename to internal/storage/db/arangodb/webhook.go index dbdc9e4c4..5f348dff6 100644 --- a/server/db/providers/arangodb/webhook.go +++ b/internal/storage/db/arangodb/webhook.go @@ -6,15 +6,15 @@ import ( "strings" "time" - "github.com/arangodb/go-driver" arangoDriver "github.com/arangodb/go-driver" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // 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 *schemas.Webhook) (*schemas.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() webhook.Key = webhook.ID @@ -24,69 +24,67 @@ func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*mo webhook.EventName = fmt.Sprintf("%s-%d", webhook.EventName, time.Now().Unix()) webhook.CreatedAt = time.Now().Unix() webhook.UpdatedAt = time.Now().Unix() - webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook) - _, err := webhookCollection.CreateDocument(ctx, webhook) + webhookCollection, _ := p.db.Collection(ctx, schemas.Collections.Webhook) + meta, err := webhookCollection.CreateDocument(ctx, webhook) if err != nil { return nil, err } - return webhook.AsAPIWebhook(), nil + webhook.Key = meta.Key + webhook.ID = meta.ID.String() + return webhook, nil } // 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 *schemas.Webhook) (*schemas.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()) } - webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook) + webhookCollection, _ := p.db.Collection(ctx, schemas.Collections.Webhook) meta, err := webhookCollection.UpdateDocument(ctx, webhook.Key, webhook) if err != nil { return nil, err } webhook.Key = meta.Key webhook.ID = meta.ID.String() - return webhook.AsAPIWebhook(), nil + return webhook, nil } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { - webhooks := []*model.Webhook{} - query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.Webhook, pagination.Offset, pagination.Limit) +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) ([]*schemas.Webhook, *model.Pagination, error) { + webhooks := []*schemas.Webhook{} + query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", schemas.Collections.Webhook, pagination.Offset, pagination.Limit) sctx := arangoDriver.WithQueryFullCount(ctx) cursor, err := p.db.Query(sctx, query, nil) if err != nil { - return nil, err + return nil, nil, err } defer cursor.Close() paginationClone := pagination paginationClone.Total = cursor.Statistics().FullCount() for { - var webhook *models.Webhook + var webhook *schemas.Webhook meta, err := cursor.ReadDocument(ctx, &webhook) if arangoDriver.IsNoMoreDocuments(err) { break } else if err != nil { - return nil, err + return nil, nil, err } if meta.Key != "" { - webhooks = append(webhooks, webhook.AsAPIWebhook()) + webhooks = append(webhooks, webhook) } } - - return &model.Webhooks{ - Pagination: paginationClone, - Webhooks: webhooks, - }, nil + return webhooks, paginationClone, nil } // GetWebhookByID to get webhook by id -func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) { - var webhook *models.Webhook - query := fmt.Sprintf("FOR d in %s FILTER d._key == @webhook_id RETURN d", models.Collections.Webhook) +func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*schemas.Webhook, error) { + var webhook *schemas.Webhook + query := fmt.Sprintf("FOR d in %s FILTER d._id == @id RETURN d", schemas.Collections.Webhook) bindVars := map[string]interface{}{ - "webhook_id": webhookID, + "id": webhookID, } cursor, err := p.db.Query(ctx, query, bindVars) if err != nil { @@ -105,12 +103,12 @@ func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model return nil, err } } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // GetWebhookByEventName to get webhook by event_name -func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*model.Webhook, error) { - query := fmt.Sprintf("FOR d in %s FILTER d.event_name LIKE @event_name RETURN d", models.Collections.Webhook) +func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*schemas.Webhook, error) { + query := fmt.Sprintf("FOR d in %s FILTER d.event_name LIKE @event_name RETURN d", schemas.Collections.Webhook) bindVars := map[string]interface{}{ "event_name": eventName + "%", } @@ -119,30 +117,30 @@ func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) return nil, err } defer cursor.Close() - webhooks := []*model.Webhook{} + webhooks := []*schemas.Webhook{} for { - var webhook *models.Webhook - if _, err := cursor.ReadDocument(ctx, &webhook); driver.IsNoMoreDocuments(err) { + var webhook *schemas.Webhook + if _, err := cursor.ReadDocument(ctx, &webhook); arangoDriver.IsNoMoreDocuments(err) { // We're done break } else if err != nil { return nil, err } - webhooks = append(webhooks, webhook.AsAPIWebhook()) + webhooks = append(webhooks, webhook) } return webhooks, nil } // DeleteWebhook to delete webhook -func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error { - webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook) - _, err := webhookCollection.RemoveDocument(ctx, webhook.ID) +func (p *provider) DeleteWebhook(ctx context.Context, webhook *schemas.Webhook) error { + webhookCollection, _ := p.db.Collection(ctx, schemas.Collections.Webhook) + _, err := webhookCollection.RemoveDocument(ctx, webhook.Key) if err != nil { return err } - query := fmt.Sprintf("FOR d IN %s FILTER d.webhook_id == @webhook_id REMOVE { _key: d._key } IN %s", models.Collections.WebhookLog, models.Collections.WebhookLog) + query := fmt.Sprintf("FOR d IN %s FILTER d.webhook_id == @webhook_id REMOVE { _key: d._key } IN %s", schemas.Collections.WebhookLog, schemas.Collections.WebhookLog) bindVars := map[string]interface{}{ - "webhook_id": webhook.ID, + "webhook_id": webhook.Key, } cursor, err := p.db.Query(ctx, query, bindVars) if err != nil { diff --git a/server/db/providers/arangodb/webhook_log.go b/internal/storage/db/arangodb/webhook_log.go similarity index 61% rename from server/db/providers/arangodb/webhook_log.go rename to internal/storage/db/arangodb/webhook_log.go index 64db2cb28..27bd5ba35 100644 --- a/server/db/providers/arangodb/webhook_log.go +++ b/internal/storage/db/arangodb/webhook_log.go @@ -6,13 +6,14 @@ import ( "time" arangoDriver "github.com/arangodb/go-driver" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *schemas.WebhookLog) (*schemas.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() webhookLog.Key = webhookLog.ID @@ -20,21 +21,21 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.Webhook webhookLog.Key = webhookLog.ID webhookLog.CreatedAt = time.Now().Unix() webhookLog.UpdatedAt = time.Now().Unix() - webhookLogCollection, _ := p.db.Collection(ctx, models.Collections.WebhookLog) + webhookLogCollection, _ := p.db.Collection(ctx, schemas.Collections.WebhookLog) _, err := webhookLogCollection.CreateDocument(ctx, webhookLog) if err != nil { return nil, err } - return webhookLog.AsAPIWebhookLog(), nil + return webhookLog, nil } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { - webhookLogs := []*model.WebhookLog{} +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) ([]*schemas.WebhookLog, *model.Pagination, error) { + webhookLogs := []*schemas.WebhookLog{} bindVariables := map[string]interface{}{} - query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.WebhookLog, pagination.Offset, pagination.Limit) + query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", schemas.Collections.WebhookLog, pagination.Offset, pagination.Limit) if webhookID != "" { - query = fmt.Sprintf("FOR d in %s FILTER d.webhook_id == @webhook_id SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.WebhookLog, pagination.Offset, pagination.Limit) + query = fmt.Sprintf("FOR d in %s FILTER d.webhook_id == @webhook_id SORT d.created_at DESC LIMIT %d, %d RETURN d", schemas.Collections.WebhookLog, pagination.Offset, pagination.Limit) bindVariables = map[string]interface{}{ "webhook_id": webhookID, } @@ -42,25 +43,22 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagina sctx := arangoDriver.WithQueryFullCount(ctx) cursor, err := p.db.Query(sctx, query, bindVariables) if err != nil { - return nil, err + return nil, nil, err } defer cursor.Close() paginationClone := pagination paginationClone.Total = cursor.Statistics().FullCount() for { - var webhookLog *models.WebhookLog + var webhookLog *schemas.WebhookLog meta, err := cursor.ReadDocument(ctx, &webhookLog) if arangoDriver.IsNoMoreDocuments(err) { break } else if err != nil { - return nil, err + return nil, nil, err } if meta.Key != "" { - webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog()) + webhookLogs = append(webhookLogs, webhookLog) } } - return &model.WebhookLogs{ - Pagination: paginationClone, - WebhookLogs: webhookLogs, - }, nil + return webhookLogs, paginationClone, nil } diff --git a/server/db/providers/cassandradb/authenticator.go b/internal/storage/db/cassandradb/authenticator.go similarity index 86% rename from server/db/providers/cassandradb/authenticator.go rename to internal/storage/db/cassandradb/authenticator.go index 369a75aa6..6feca9dac 100644 --- a/server/db/providers/cassandradb/authenticator.go +++ b/internal/storage/db/cassandradb/authenticator.go @@ -11,10 +11,10 @@ import ( "github.com/gocql/gocql" "github.com/google/uuid" - "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) -func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) AddAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method) if exists != nil { return authenticators, nil @@ -63,7 +63,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models. fields = fields[:len(fields)-1] + ")" values = values[:len(values)-1] + ")" - query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.Authenticators, fields, values) + query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+schemas.Collections.Authenticators, fields, values) err = p.db.Query(query).Exec() if err != nil { return nil, err @@ -72,7 +72,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models. return authenticators, nil } -func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { authenticators.UpdatedAt = time.Now().Unix() bytes, err := json.Marshal(authenticators) @@ -113,7 +113,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode updateFields = strings.Trim(updateFields, " ") updateFields = strings.TrimSuffix(updateFields, ",") - query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Authenticators, updateFields, authenticators.ID) + query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+schemas.Collections.Authenticators, updateFields, authenticators.ID) err = p.db.Query(query).Exec() if err != nil { return nil, err @@ -122,9 +122,9 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode return authenticators, nil } -func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) { - var authenticators models.Authenticator - query := fmt.Sprintf("SELECT id, user_id, method, secret, recovery_codes, verified_at, created_at, updated_at FROM %s WHERE user_id = '%s' AND method = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.Authenticators, userId, authenticatorType) +func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*schemas.Authenticator, error) { + var authenticators schemas.Authenticator + query := fmt.Sprintf("SELECT id, user_id, method, secret, recovery_codes, verified_at, created_at, updated_at FROM %s WHERE user_id = '%s' AND method = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+schemas.Collections.Authenticators, userId, authenticatorType) err := p.db.Query(query).Consistency(gocql.One).Scan(&authenticators.ID, &authenticators.UserID, &authenticators.Method, &authenticators.Secret, &authenticators.RecoveryCodes, &authenticators.VerifiedAt, &authenticators.CreatedAt, &authenticators.UpdatedAt) if err != nil { return nil, err diff --git a/server/db/providers/cassandradb/email_template.go b/internal/storage/db/cassandradb/email_template.go similarity index 71% rename from server/db/providers/cassandradb/email_template.go rename to internal/storage/db/cassandradb/email_template.go index 9adb7687d..908dc1ff0 100644 --- a/server/db/providers/cassandradb/email_template.go +++ b/internal/storage/db/cassandradb/email_template.go @@ -8,14 +8,15 @@ import ( "strings" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/gocql/gocql" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() } @@ -24,18 +25,18 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.E emailTemplate.UpdatedAt = time.Now().Unix() existingEmailTemplate, _ := p.GetEmailTemplateByEventName(ctx, emailTemplate.EventName) if existingEmailTemplate != nil { - return nil, fmt.Errorf("Email template with %s event_name already exists", emailTemplate.EventName) + return nil, fmt.Errorf("email template with %s event_name already exists", emailTemplate.EventName) } - insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_name, subject, design, template, created_at, updated_at) VALUES ('%s', '%s', '%s','%s','%s', %d, %d)", KeySpace+"."+models.Collections.EmailTemplate, emailTemplate.ID, emailTemplate.EventName, emailTemplate.Subject, emailTemplate.Design, emailTemplate.Template, emailTemplate.CreatedAt, emailTemplate.UpdatedAt) + insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_name, subject, design, template, created_at, updated_at) VALUES ('%s', '%s', '%s','%s','%s', %d, %d)", KeySpace+"."+schemas.Collections.EmailTemplate, emailTemplate.ID, emailTemplate.EventName, emailTemplate.Subject, emailTemplate.Design, emailTemplate.Template, emailTemplate.CreatedAt, emailTemplate.UpdatedAt) err := p.db.Query(insertQuery).Exec() if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { emailTemplate.UpdatedAt = time.Now().Unix() bytes, err := json.Marshal(emailTemplate) if err != nil { @@ -71,76 +72,72 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *model updateFields = strings.Trim(updateFields, " ") updateFields = strings.TrimSuffix(updateFields, ",") - query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.EmailTemplate, updateFields, emailTemplate.ID) + query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+schemas.Collections.EmailTemplate, updateFields, emailTemplate.ID) err = p.db.Query(query).Exec() if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { - emailTemplates := []*model.EmailTemplate{} +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) ([]*schemas.EmailTemplate, *model.Pagination, error) { + emailTemplates := []*schemas.EmailTemplate{} paginationClone := pagination - totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.EmailTemplate) + totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+schemas.Collections.EmailTemplate) err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total) if err != nil { - return nil, err + return nil, nil, err } // there is no offset in cassandra // so we fetch till limit + offset // and return the results from offset to limit - query := fmt.Sprintf("SELECT id, event_name, subject, design, template, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.EmailTemplate, pagination.Limit+pagination.Offset) + query := fmt.Sprintf("SELECT id, event_name, subject, design, template, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+schemas.Collections.EmailTemplate, pagination.Limit+pagination.Offset) scanner := p.db.Query(query).Iter().Scanner() counter := int64(0) for scanner.Next() { if counter >= pagination.Offset { - var emailTemplate models.EmailTemplate + var emailTemplate schemas.EmailTemplate err := scanner.Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Subject, &emailTemplate.Design, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt) if err != nil { - return nil, err + return nil, nil, err } - emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate()) + emailTemplates = append(emailTemplates, &emailTemplate) } counter++ } - - return &model.EmailTemplates{ - Pagination: paginationClone, - EmailTemplates: emailTemplates, - }, nil + return emailTemplates, paginationClone, nil } // GetEmailTemplateByID to get EmailTemplate by id -func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { - var emailTemplate models.EmailTemplate - query := fmt.Sprintf(`SELECT id, event_name, subject, design, template, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1`, KeySpace+"."+models.Collections.EmailTemplate, emailTemplateID) +func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*schemas.EmailTemplate, error) { + var emailTemplate schemas.EmailTemplate + query := fmt.Sprintf(`SELECT id, event_name, subject, design, template, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1`, KeySpace+"."+schemas.Collections.EmailTemplate, emailTemplateID) err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Subject, &emailTemplate.Design, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt) if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return &emailTemplate, nil } // GetEmailTemplateByEventName to get EmailTemplate by event_name -func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { - var emailTemplate models.EmailTemplate - query := fmt.Sprintf(`SELECT id, event_name, subject, design, template, created_at, updated_at FROM %s WHERE event_name = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.EmailTemplate, eventName) +func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*schemas.EmailTemplate, error) { + var emailTemplate schemas.EmailTemplate + query := fmt.Sprintf(`SELECT id, event_name, subject, design, template, created_at, updated_at FROM %s WHERE event_name = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+schemas.Collections.EmailTemplate, eventName) err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Subject, &emailTemplate.Design, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt) if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return &emailTemplate, nil } // DeleteEmailTemplate to delete EmailTemplate -func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error { - query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.EmailTemplate, emailTemplate.ID) +func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) error { + query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+schemas.Collections.EmailTemplate, emailTemplate.ID) err := p.db.Query(query).Exec() if err != nil { return err diff --git a/server/db/providers/cassandradb/env.go b/internal/storage/db/cassandradb/env.go similarity index 64% rename from server/db/providers/cassandradb/env.go rename to internal/storage/db/cassandradb/env.go index 627403dcc..b8acdc469 100644 --- a/server/db/providers/cassandradb/env.go +++ b/internal/storage/db/cassandradb/env.go @@ -5,19 +5,20 @@ import ( "fmt" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/gocql/gocql" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *schemas.Env) (*schemas.Env, error) { if env.ID == "" { env.ID = uuid.New().String() } env.CreatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix() - insertEnvQuery := fmt.Sprintf("INSERT INTO %s (id, env, hash, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.Env, env.ID, env.EnvData, env.Hash, env.CreatedAt, env.UpdatedAt) + insertEnvQuery := fmt.Sprintf("INSERT INTO %s (id, env, hash, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d)", KeySpace+"."+schemas.Collections.Env, env.ID, env.EnvData, env.Hash, env.CreatedAt, env.UpdatedAt) err := p.db.Query(insertEnvQuery).Exec() if err != nil { return nil, err @@ -27,9 +28,9 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er } // 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 *schemas.Env) (*schemas.Env, error) { env.UpdatedAt = time.Now().Unix() - updateEnvQuery := fmt.Sprintf("UPDATE %s SET env = '%s', updated_at = %d WHERE id = '%s'", KeySpace+"."+models.Collections.Env, env.EnvData, env.UpdatedAt, env.ID) + updateEnvQuery := fmt.Sprintf("UPDATE %s SET env = '%s', updated_at = %d WHERE id = '%s'", KeySpace+"."+schemas.Collections.Env, env.EnvData, env.UpdatedAt, env.ID) err := p.db.Query(updateEnvQuery).Exec() if err != nil { return nil, err @@ -38,9 +39,9 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { - var env models.Env - query := fmt.Sprintf("SELECT id, env, hash, created_at, updated_at FROM %s LIMIT 1", KeySpace+"."+models.Collections.Env) +func (p *provider) GetEnv(ctx context.Context) (*schemas.Env, error) { + var env schemas.Env + query := fmt.Sprintf("SELECT id, env, hash, created_at, updated_at FROM %s LIMIT 1", KeySpace+"."+schemas.Collections.Env) err := p.db.Query(query).Consistency(gocql.One).Scan(&env.ID, &env.EnvData, &env.Hash, &env.CreatedAt, &env.UpdatedAt) if err != nil { return nil, err diff --git a/server/db/providers/cassandradb/otp.go b/internal/storage/db/cassandradb/otp.go similarity index 70% rename from server/db/providers/cassandradb/otp.go rename to internal/storage/db/cassandradb/otp.go index e4532426c..aa3a6f219 100644 --- a/server/db/providers/cassandradb/otp.go +++ b/internal/storage/db/cassandradb/otp.go @@ -6,23 +6,24 @@ import ( "fmt" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/gocql/gocql" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // UpsertOTP to add or update otp -func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { +func (p *provider) UpsertOTP(ctx context.Context, otpParam *schemas.OTP) (*schemas.OTP, error) { // check if email or phone number is present if otpParam.Email == "" && otpParam.PhoneNumber == "" { return nil, errors.New("email or phone_number is required") } - uniqueField := models.FieldNameEmail + uniqueField := schemas.FieldNameEmail if otpParam.Email == "" && otpParam.PhoneNumber != "" { - uniqueField = models.FieldNamePhoneNumber + uniqueField = schemas.FieldNamePhoneNumber } - var otp *models.OTP - if uniqueField == models.FieldNameEmail { + var otp *schemas.OTP + if uniqueField == schemas.FieldNameEmail { otp, _ = p.GetOTPByEmail(ctx, otpParam.Email) } else { otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber) @@ -30,7 +31,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models shouldCreate := false if otp == nil { shouldCreate = true - otp = &models.OTP{ + otp = &schemas.OTP{ ID: uuid.NewString(), Otp: otpParam.Otp, Email: otpParam.Email, @@ -47,9 +48,9 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models otp.UpdatedAt = time.Now().Unix() query := "" if shouldCreate { - query = fmt.Sprintf(`INSERT INTO %s (id, email, phone_number, otp, expires_at, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)`, KeySpace+"."+models.Collections.OTP, otp.ID, otp.Email, otp.PhoneNumber, otp.Otp, otp.ExpiresAt, otp.CreatedAt, otp.UpdatedAt) + query = fmt.Sprintf(`INSERT INTO %s (id, email, phone_number, otp, expires_at, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)`, KeySpace+"."+schemas.Collections.OTP, otp.ID, otp.Email, otp.PhoneNumber, otp.Otp, otp.ExpiresAt, otp.CreatedAt, otp.UpdatedAt) } else { - query = fmt.Sprintf(`UPDATE %s SET otp = '%s', expires_at = %d, updated_at = %d WHERE id = '%s'`, KeySpace+"."+models.Collections.OTP, otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID) + query = fmt.Sprintf(`UPDATE %s SET otp = '%s', expires_at = %d, updated_at = %d WHERE id = '%s'`, KeySpace+"."+schemas.Collections.OTP, otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID) } err := p.db.Query(query).Exec() @@ -61,9 +62,9 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models } // GetOTPByEmail to get otp for a given email address -func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { - var otp models.OTP - query := fmt.Sprintf(`SELECT id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.OTP, emailAddress) +func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*schemas.OTP, error) { + var otp schemas.OTP + query := fmt.Sprintf(`SELECT id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+schemas.Collections.OTP, emailAddress) err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.PhoneNumber, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt) if err != nil { return nil, err @@ -72,9 +73,9 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod } // GetOTPByPhoneNumber to get otp for a given phone number -func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { - var otp models.OTP - query := fmt.Sprintf(`SELECT id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.OTP, phoneNumber) +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.OTP, error) { + var otp schemas.OTP + query := fmt.Sprintf(`SELECT id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+schemas.Collections.OTP, phoneNumber) err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.PhoneNumber, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt) if err != nil { return nil, err @@ -83,8 +84,8 @@ func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) } // DeleteOTP to delete otp -func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { - query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.OTP, otp.ID) +func (p *provider) DeleteOTP(ctx context.Context, otp *schemas.OTP) error { + query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+schemas.Collections.OTP, otp.ID) err := p.db.Query(query).Exec() if err != nil { return err diff --git a/server/db/providers/cassandradb/provider.go b/internal/storage/db/cassandradb/provider.go similarity index 72% rename from server/db/providers/cassandradb/provider.go rename to internal/storage/db/cassandradb/provider.go index 431b8fe72..e1a142e76 100644 --- a/server/db/providers/cassandradb/provider.go +++ b/internal/storage/db/cassandradb/provider.go @@ -7,38 +7,44 @@ import ( "strings" "time" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/gocql/gocql" cansandraDriver "github.com/gocql/gocql" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) +// Dependencies struct the cassandradb data store provider +type Dependencies struct { + Log *zerolog.Logger +} + type provider struct { - db *cansandraDriver.Session + config *config.Config + dependencies *Dependencies + db *cansandraDriver.Session } // KeySpace for the cassandra database var KeySpace string // NewProvider to initialize arangodb connection -func NewProvider() (*provider, error) { - dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL +func NewProvider(cfg *config.Config, deps *Dependencies) (*provider, error) { + dbURL := cfg.DatabaseURL if dbURL == "" { - dbHost := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseHost - dbPort := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePort - if dbPort != "" && dbHost != "" { - dbURL = fmt.Sprintf("%s:%s", dbHost, dbPort) + dbHost := cfg.DatabaseHost + dbPort := cfg.DatabasePort + if dbPort != 0 && dbHost != "" { + dbURL = fmt.Sprintf("%s:%d", dbHost, dbPort) } else if dbHost != "" { dbURL = dbHost } } - KeySpace = memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName + KeySpace = cfg.DatabaseName if KeySpace == "" { - KeySpace = constants.EnvKeyDatabaseName + return nil, fmt.Errorf("database name is required for cassandra. It is used as keyspace in case of cassandra") } clusterURL := []string{} if strings.Contains(dbURL, ",") { @@ -47,8 +53,8 @@ func NewProvider() (*provider, error) { clusterURL = append(clusterURL, dbURL) } cassandraClient := cansandraDriver.NewCluster(clusterURL...) - dbUsername := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseUsername - dbPassword := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePassword + dbUsername := cfg.DatabaseUsername + dbPassword := cfg.DatabasePassword if dbUsername != "" && dbPassword != "" { cassandraClient.Authenticator = &cansandraDriver.PasswordAuthenticator{ @@ -57,9 +63,9 @@ func NewProvider() (*provider, error) { } } - dbCert := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseCert - dbCACert := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseCACert - dbCertKey := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseCertKey + dbCert := cfg.DatabaseCert + dbCACert := cfg.DatabaseCACert + dbCertKey := cfg.DatabaseCertKey if dbCert != "" && dbCACert != "" && dbCertKey != "" { certString, err := crypto.DecryptB64(dbCert) if err != nil { @@ -97,7 +103,7 @@ func NewProvider() (*provider, error) { cassandraClient.RetryPolicy = &cansandraDriver.SimpleRetryPolicy{ NumRetries: 3, } - cassandraClient.Consistency = gocql.LocalQuorum + cassandraClient.Consistency = cansandraDriver.LocalQuorum cassandraClient.ConnectTimeout = 10 * time.Second cassandraClient.ProtoVersion = 4 cassandraClient.Timeout = 30 * time.Minute // for large data @@ -109,7 +115,7 @@ func NewProvider() (*provider, error) { // Note for astra keyspaces can only be created from there console // https://docs.datastax.com/en/astra/docs/datastax-astra-faq.html#_i_am_trying_to_create_a_keyspace_in_the_cql_shell_and_i_am_running_into_an_error_how_do_i_fix_this - getKeyspaceQuery := fmt.Sprintf("SELECT keyspace_name FROM system_schema.keyspaces;") + getKeyspaceQuery := "SELECT keyspace_name FROM system_schema.keyspaces;" scanner := session.Query(getKeyspaceQuery).Iter().Scanner() hasAuthorizerKeySpace := false for scanner.Next() { @@ -134,154 +140,156 @@ func NewProvider() (*provider, error) { // make sure collections are present envCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, env text, hash text, updated_at bigint, created_at bigint, PRIMARY KEY (id))", - KeySpace, models.Collections.Env) + KeySpace, schemas.Collections.Env) err = session.Query(envCollectionQuery).Exec() if err != nil { return nil, err } - sessionCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, user_id text, user_agent text, ip text, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.Session) + sessionCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, user_id text, user_agent text, ip text, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, schemas.Collections.Session) err = session.Query(sessionCollectionQuery).Exec() if err != nil { return nil, err } - sessionIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_session_user_id ON %s.%s (user_id)", KeySpace, models.Collections.Session) + sessionIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_session_user_id ON %s.%s (user_id)", KeySpace, schemas.Collections.Session) err = session.Query(sessionIndexQuery).Exec() if err != nil { return nil, err } - userCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, email text, email_verified_at bigint, password text, signup_methods text, given_name text, family_name text, middle_name text, nickname text, gender text, birthdate text, phone_number text, phone_number_verified_at bigint, picture text, roles text, updated_at bigint, created_at bigint, revoked_timestamp bigint, PRIMARY KEY (id))", KeySpace, models.Collections.User) + userCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, email text, email_verified_at bigint, password text, signup_methods text, given_name text, family_name text, middle_name text, nickname text, gender text, birthdate text, phone_number text, phone_number_verified_at bigint, picture text, roles text, updated_at bigint, created_at bigint, revoked_timestamp bigint, PRIMARY KEY (id))", KeySpace, schemas.Collections.User) err = session.Query(userCollectionQuery).Exec() if err != nil { return nil, err } - userIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_user_email ON %s.%s (email)", KeySpace, models.Collections.User) + userIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_user_email ON %s.%s (email)", KeySpace, schemas.Collections.User) err = session.Query(userIndexQuery).Exec() if err != nil { return nil, err } - userPhoneNumberIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_user_phone_number ON %s.%s (phone_number)", KeySpace, models.Collections.User) + userPhoneNumberIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_user_phone_number ON %s.%s (phone_number)", KeySpace, schemas.Collections.User) err = session.Query(userPhoneNumberIndexQuery).Exec() if err != nil { return nil, err } // 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, schemas.Collections.User) err = session.Query(userTableAlterQuery).Exec() if err != nil { - log.Debug("Failed to alter table as column exists: ", err) - // return nil, err + deps.Log.Debug().Err(err).Msg("Failed to alter table as is_multi_factor_auth_enabled column exists") + // continue } // token is reserved keyword in cassandra, hence we need to use jwt_token - verificationRequestCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, jwt_token text, identifier text, expires_at bigint, email text, nonce text, redirect_uri text, created_at bigint, updated_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.VerificationRequest) + verificationRequestCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, jwt_token text, identifier text, expires_at bigint, email text, nonce text, redirect_uri text, created_at bigint, updated_at bigint, PRIMARY KEY (id))", KeySpace, schemas.Collections.VerificationRequest) err = session.Query(verificationRequestCollectionQuery).Exec() if err != nil { return nil, err } - verificationRequestIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_verification_request_email ON %s.%s (email)", KeySpace, models.Collections.VerificationRequest) + verificationRequestIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_verification_request_email ON %s.%s (email)", KeySpace, schemas.Collections.VerificationRequest) err = session.Query(verificationRequestIndexQuery).Exec() if err != nil { return nil, err } - verificationRequestIndexQuery = fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_verification_request_identifier ON %s.%s (identifier)", KeySpace, models.Collections.VerificationRequest) + verificationRequestIndexQuery = fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_verification_request_identifier ON %s.%s (identifier)", KeySpace, schemas.Collections.VerificationRequest) err = session.Query(verificationRequestIndexQuery).Exec() if err != nil { return nil, err } - verificationRequestIndexQuery = fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_verification_request_jwt_token ON %s.%s (jwt_token)", KeySpace, models.Collections.VerificationRequest) + verificationRequestIndexQuery = fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_verification_request_jwt_token ON %s.%s (jwt_token)", KeySpace, schemas.Collections.VerificationRequest) err = session.Query(verificationRequestIndexQuery).Exec() if err != nil { return nil, err } - webhookCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, event_name text, endpoint text, enabled boolean, headers text, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.Webhook) + webhookCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, event_name text, endpoint text, enabled boolean, headers text, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, schemas.Collections.Webhook) err = session.Query(webhookCollectionQuery).Exec() if err != nil { return nil, err } - webhookIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_webhook_event_name ON %s.%s (event_name)", KeySpace, models.Collections.Webhook) + webhookIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_webhook_event_name ON %s.%s (event_name)", KeySpace, schemas.Collections.Webhook) err = session.Query(webhookIndexQuery).Exec() if err != nil { return nil, err } // add event_description to webhook table - webhookAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (event_description text);`, KeySpace, models.Collections.Webhook) + webhookAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (event_description text);`, KeySpace, schemas.Collections.Webhook) err = session.Query(webhookAlterQuery).Exec() if err != nil { - log.Debug("Failed to alter table as column exists: ", err) + deps.Log.Debug().Err(err).Msg("Failed to alter table as event_description column exists") // 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, schemas.Collections.WebhookLog) err = session.Query(webhookLogCollectionQuery).Exec() if err != nil { return nil, err } - webhookLogIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_webhook_log_webhook_id ON %s.%s (webhook_id)", KeySpace, models.Collections.WebhookLog) + webhookLogIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_webhook_log_webhook_id ON %s.%s (webhook_id)", KeySpace, schemas.Collections.WebhookLog) err = session.Query(webhookLogIndexQuery).Exec() if err != nil { return nil, err } - emailTemplateCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, event_name text, template text, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.EmailTemplate) + emailTemplateCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, event_name text, template text, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, schemas.Collections.EmailTemplate) err = session.Query(emailTemplateCollectionQuery).Exec() if err != nil { return nil, err } - emailTemplateIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_email_template_event_name ON %s.%s (event_name)", KeySpace, models.Collections.EmailTemplate) + emailTemplateIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_email_template_event_name ON %s.%s (event_name)", KeySpace, schemas.Collections.EmailTemplate) err = session.Query(emailTemplateIndexQuery).Exec() if err != nil { return nil, err } // add subject on email_templates table - emailTemplateAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (subject text, design text);`, KeySpace, models.Collections.EmailTemplate) + emailTemplateAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (subject text, design text);`, KeySpace, schemas.Collections.EmailTemplate) err = session.Query(emailTemplateAlterQuery).Exec() if err != nil { - log.Debug("Failed to alter table as column exists: ", err) + deps.Log.Debug().Err(err).Msg("Failed to alter table as subject & design column exists") // continue } - otpCollection := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, email text, otp text, expires_at bigint, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.OTP) + otpCollection := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, email text, otp text, expires_at bigint, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, schemas.Collections.OTP) err = session.Query(otpCollection).Exec() if err != nil { return nil, err } - otpIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_otp_email ON %s.%s (email)", KeySpace, models.Collections.OTP) + otpIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_otp_email ON %s.%s (email)", KeySpace, schemas.Collections.OTP) err = session.Query(otpIndexQuery).Exec() if err != nil { return nil, err } // Add phone_number column to otp table - otpAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (phone_number text);`, KeySpace, models.Collections.OTP) + otpAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (phone_number text);`, KeySpace, schemas.Collections.OTP) err = session.Query(otpAlterQuery).Exec() if err != nil { - log.Debug("Failed to alter table as column exists: ", err) + deps.Log.Debug().Err(err).Msg("Failed to alter table as phone_number column exists") // continue } // Add app_data column to users table - appDataAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (app_data text);`, KeySpace, models.Collections.User) + appDataAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (app_data text);`, KeySpace, schemas.Collections.User) err = session.Query(appDataAlterQuery).Exec() if err != nil { - log.Debug("Failed to alter user table as app_data column exists: ", err) + deps.Log.Debug().Err(err).Msg("Failed to alter table as app_data column exists") // continue } // Add phone number index - otpIndexQueryPhoneNumber := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_otp_phone_number ON %s.%s (phone_number)", KeySpace, models.Collections.OTP) + otpIndexQueryPhoneNumber := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_otp_phone_number ON %s.%s (phone_number)", KeySpace, schemas.Collections.OTP) err = session.Query(otpIndexQueryPhoneNumber).Exec() if err != nil { return nil, err } // add authenticators table - totpCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, user_id text, method text, secret text, recovery_codes text, verified_at bigint, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.Authenticators) + totpCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, user_id text, method text, secret text, recovery_codes text, verified_at bigint, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, schemas.Collections.Authenticators) err = session.Query(totpCollectionQuery).Exec() if err != nil { return nil, err } return &provider{ - db: session, + config: cfg, + dependencies: deps, + db: session, }, err } diff --git a/server/db/providers/cassandradb/session.go b/internal/storage/db/cassandradb/session.go similarity index 67% rename from server/db/providers/cassandradb/session.go rename to internal/storage/db/cassandradb/session.go index bdf205ce2..d2226a3f8 100644 --- a/server/db/providers/cassandradb/session.go +++ b/internal/storage/db/cassandradb/session.go @@ -5,18 +5,19 @@ import ( "fmt" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session *models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *schemas.Session) error { if session.ID == "" { session.ID = uuid.New().String() } session.CreatedAt = time.Now().Unix() session.UpdatedAt = time.Now().Unix() - insertSessionQuery := fmt.Sprintf("INSERT INTO %s (id, user_id, user_agent, ip, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.Session, session.ID, session.UserID, session.UserAgent, session.IP, session.CreatedAt, session.UpdatedAt) + insertSessionQuery := fmt.Sprintf("INSERT INTO %s (id, user_id, user_agent, ip, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %d, %d)", KeySpace+"."+schemas.Collections.Session, session.ID, session.UserID, session.UserAgent, session.IP, session.CreatedAt, session.UpdatedAt) err := p.db.Query(insertSessionQuery).Exec() if err != nil { return err diff --git a/server/db/providers/cassandradb/user.go b/internal/storage/db/cassandradb/user.go similarity index 84% rename from server/db/providers/cassandradb/user.go rename to internal/storage/db/cassandradb/user.go index 7fb252981..d1e0ba22d 100644 --- a/server/db/providers/cassandradb/user.go +++ b/internal/storage/db/cassandradb/user.go @@ -8,27 +8,22 @@ import ( "strings" "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/authorizerdev/authorizer/server/refs" "github.com/gocql/gocql" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { if user.ID == "" { user.ID = uuid.New().String() } if user.Roles == "" { - defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - return nil, err - } - user.Roles = defaultRoles + user.Roles = strings.Join(p.config.DefaultRoles, ",") } if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" { @@ -80,7 +75,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User fields = fields[:len(fields)-1] + ")" values = values[:len(values)-1] + ")" - query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.User, fields, values) + query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+schemas.Collections.User, fields, values) err = p.db.Query(query).Exec() if err != nil { @@ -91,7 +86,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User } // UpdateUser to update user information in database -func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) UpdateUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { user.UpdatedAt = time.Now().Unix() bytes, err := json.Marshal(user) @@ -132,7 +127,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U updateFields = strings.Trim(updateFields, " ") updateFields = strings.TrimSuffix(updateFields, ",") - query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, updateFields, user.ID) + query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+schemas.Collections.User, updateFields, user.ID) err = p.db.Query(query).Exec() if err != nil { return nil, err @@ -142,13 +137,13 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { - query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, user.ID) +func (p *provider) DeleteUser(ctx context.Context, user *schemas.User) error { + query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+schemas.Collections.User, user.ID) err := p.db.Query(query).Exec() if err != nil { return err } - getSessionsQuery := fmt.Sprintf("SELECT id FROM %s WHERE user_id = '%s' ALLOW FILTERING", KeySpace+"."+models.Collections.Session, user.ID) + getSessionsQuery := fmt.Sprintf("SELECT id FROM %s WHERE user_id = '%s' ALLOW FILTERING", KeySpace+"."+schemas.Collections.Session, user.ID) scanner := p.db.Query(getSessionsQuery).Iter().Scanner() sessionIDs := "" for scanner.Next() { @@ -160,7 +155,7 @@ func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { sessionIDs += fmt.Sprintf("'%s',", wlID) } sessionIDs = strings.TrimSuffix(sessionIDs, ",") - deleteSessionQuery := fmt.Sprintf("DELETE FROM %s WHERE id IN (%s)", KeySpace+"."+models.Collections.Session, sessionIDs) + deleteSessionQuery := fmt.Sprintf("DELETE FROM %s WHERE id IN (%s)", KeySpace+"."+schemas.Collections.Session, sessionIDs) err = p.db.Query(deleteSessionQuery).Exec() if err != nil { return err @@ -170,46 +165,43 @@ func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { - responseUsers := []*model.User{} +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) ([]*schemas.User, *model.Pagination, error) { + responseUsers := []*schemas.User{} paginationClone := pagination - totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.User) + totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+schemas.Collections.User) err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total) if err != nil { - return nil, err + return nil, nil, err } // there is no offset in cassandra // so we fetch till limit + offset // and return the results from offset to limit - query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.User, + query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+schemas.Collections.User, pagination.Limit+pagination.Offset) scanner := p.db.Query(query).Iter().Scanner() counter := int64(0) for scanner.Next() { if counter >= pagination.Offset { - var user models.User + var user schemas.User err := scanner.Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.AppData, &user.CreatedAt, &user.UpdatedAt) if err != nil { - return nil, err + return nil, nil, err } - responseUsers = append(responseUsers, user.AsAPIUser()) + responseUsers = append(responseUsers, &user) } counter++ } - return &model.Users{ - Pagination: paginationClone, - Users: responseUsers, - }, nil + return responseUsers, paginationClone, 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 - query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, email) +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*schemas.User, error) { + var user schemas.User + query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+schemas.Collections.User, email) err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.AppData, &user.CreatedAt, &user.UpdatedAt) if err != nil { return nil, err @@ -218,9 +210,9 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us } // 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 - query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1", KeySpace+"."+models.Collections.User, id) +func (p *provider) GetUserByID(ctx context.Context, id string) (*schemas.User, error) { + var user schemas.User + query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1", KeySpace+"."+schemas.Collections.User, id) err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.AppData, &user.CreatedAt, &user.UpdatedAt) if err != nil { return nil, err @@ -266,14 +258,14 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } idsString = strings.Trim(idsString, " ") idsString = strings.TrimSuffix(idsString, ",") - query = fmt.Sprintf("UPDATE %s SET %s WHERE id IN (%s)", KeySpace+"."+models.Collections.User, updateFields, idsString) + query = fmt.Sprintf("UPDATE %s SET %s WHERE id IN (%s)", KeySpace+"."+schemas.Collections.User, updateFields, idsString) err := p.db.Query(query).Exec() if err != nil { return err } } else { // get all ids - getUserIDsQuery := fmt.Sprintf(`SELECT id FROM %s`, KeySpace+"."+models.Collections.User) + getUserIDsQuery := fmt.Sprintf(`SELECT id FROM %s`, KeySpace+"."+schemas.Collections.User) scanner := p.db.Query(getUserIDsQuery).Iter().Scanner() // only 100 ids are allowed in 1 query // hence we need create multiple update queries @@ -300,7 +292,7 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, for _, idStr := range idsStringArray { idStr = strings.Trim(idStr, " ") idStr = strings.TrimSuffix(idStr, ",") - query = fmt.Sprintf("UPDATE %s SET %s WHERE id IN (%s)", KeySpace+"."+models.Collections.User, updateFields, idStr) + query = fmt.Sprintf("UPDATE %s SET %s WHERE id IN (%s)", KeySpace+"."+schemas.Collections.User, updateFields, idStr) err := p.db.Query(query).Exec() if err != nil { return err @@ -311,9 +303,9 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } // GetUserByPhoneNumber to get user information from database using phone number -func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) { - var user models.User - query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, phoneNumber) +func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.User, error) { + var user schemas.User + query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+schemas.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.AppData, &user.CreatedAt, &user.UpdatedAt) if err != nil { return nil, err diff --git a/server/db/providers/cassandradb/verification_requests.go b/internal/storage/db/cassandradb/verification_requests.go similarity index 67% rename from server/db/providers/cassandradb/verification_requests.go rename to internal/storage/db/cassandradb/verification_requests.go index e741c5dd8..7516fe958 100644 --- a/server/db/providers/cassandradb/verification_requests.go +++ b/internal/storage/db/cassandradb/verification_requests.go @@ -5,14 +5,15 @@ import ( "fmt" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/gocql/gocql" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) (*schemas.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() } @@ -20,7 +21,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque verificationRequest.CreatedAt = time.Now().Unix() verificationRequest.UpdatedAt = time.Now().Unix() - query := fmt.Sprintf("INSERT INTO %s (id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, '%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.VerificationRequest, verificationRequest.ID, verificationRequest.Token, verificationRequest.Identifier, verificationRequest.ExpiresAt, verificationRequest.Email, verificationRequest.Nonce, verificationRequest.RedirectURI, verificationRequest.CreatedAt, verificationRequest.UpdatedAt) + query := fmt.Sprintf("INSERT INTO %s (id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, '%s', '%s', '%s', %d, %d)", KeySpace+"."+schemas.Collections.VerificationRequest, verificationRequest.ID, verificationRequest.Token, verificationRequest.Identifier, verificationRequest.ExpiresAt, verificationRequest.Email, verificationRequest.Nonce, verificationRequest.RedirectURI, verificationRequest.CreatedAt, verificationRequest.UpdatedAt) err := p.db.Query(query).Exec() if err != nil { return nil, err @@ -29,9 +30,9 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest - query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE jwt_token = '%s' LIMIT 1`, KeySpace+"."+models.Collections.VerificationRequest, token) +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*schemas.VerificationRequest, error) { + var verificationRequest schemas.VerificationRequest + query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE jwt_token = '%s' LIMIT 1`, KeySpace+"."+schemas.Collections.VerificationRequest, token) err := p.db.Query(query).Consistency(gocql.One).Scan(&verificationRequest.ID, &verificationRequest.Token, &verificationRequest.Identifier, &verificationRequest.ExpiresAt, &verificationRequest.Email, &verificationRequest.Nonce, &verificationRequest.RedirectURI, &verificationRequest.CreatedAt, &verificationRequest.UpdatedAt) if err != nil { @@ -41,9 +42,9 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest - query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE email = '%s' AND identifier = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.VerificationRequest, email, identifier) +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*schemas.VerificationRequest, error) { + var verificationRequest schemas.VerificationRequest + query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE email = '%s' AND identifier = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+schemas.Collections.VerificationRequest, email, identifier) err := p.db.Query(query).Consistency(gocql.One).Scan(&verificationRequest.ID, &verificationRequest.Token, &verificationRequest.Identifier, &verificationRequest.ExpiresAt, &verificationRequest.Email, &verificationRequest.Nonce, &verificationRequest.RedirectURI, &verificationRequest.CreatedAt, &verificationRequest.UpdatedAt) if err != nil { @@ -54,42 +55,39 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { - var verificationRequests []*model.VerificationRequest +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) ([]*schemas.VerificationRequest, *model.Pagination, error) { + var verificationRequests []*schemas.VerificationRequest paginationClone := pagination - totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.VerificationRequest) + totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+schemas.Collections.VerificationRequest) err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total) if err != nil { - return nil, err + return nil, nil, err } // there is no offset in cassandra // so we fetch till limit + offset // and return the results from offset to limit - query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s LIMIT %d`, KeySpace+"."+models.Collections.VerificationRequest, pagination.Limit+pagination.Offset) + query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s LIMIT %d`, KeySpace+"."+schemas.Collections.VerificationRequest, pagination.Limit+pagination.Offset) scanner := p.db.Query(query).Iter().Scanner() counter := int64(0) for scanner.Next() { if counter >= pagination.Offset { - var verificationRequest models.VerificationRequest + var verificationRequest schemas.VerificationRequest err := scanner.Scan(&verificationRequest.ID, &verificationRequest.Token, &verificationRequest.Identifier, &verificationRequest.ExpiresAt, &verificationRequest.Email, &verificationRequest.Nonce, &verificationRequest.RedirectURI, &verificationRequest.CreatedAt, &verificationRequest.UpdatedAt) if err != nil { - return nil, err + return nil, nil, err } - verificationRequests = append(verificationRequests, verificationRequest.AsAPIVerificationRequest()) + verificationRequests = append(verificationRequests, &verificationRequest) } counter++ } - return &model.VerificationRequests{ - VerificationRequests: verificationRequests, - Pagination: paginationClone, - }, nil + return verificationRequests, paginationClone, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { - query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.VerificationRequest, verificationRequest.ID) +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) error { + query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+schemas.Collections.VerificationRequest, verificationRequest.ID) err := p.db.Query(query).Exec() if err != nil { return err diff --git a/server/db/providers/cassandradb/webhook.go b/internal/storage/db/cassandradb/webhook.go similarity index 72% rename from server/db/providers/cassandradb/webhook.go rename to internal/storage/db/cassandradb/webhook.go index e80dfdd4b..0fe828be5 100644 --- a/server/db/providers/cassandradb/webhook.go +++ b/internal/storage/db/cassandradb/webhook.go @@ -8,14 +8,15 @@ import ( "strings" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/gocql/gocql" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // 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 *schemas.Webhook) (*schemas.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() } @@ -24,16 +25,16 @@ func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*mo 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()) - 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) + 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+"."+schemas.Collections.Webhook, webhook.ID, webhook.EventDescription, webhook.EventName, webhook.EndPoint, webhook.Headers, webhook.Enabled, webhook.CreatedAt, webhook.UpdatedAt) err := p.db.Query(insertQuery).Exec() if err != nil { return nil, err } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // 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 *schemas.Webhook) (*schemas.Webhook, error) { webhook.UpdatedAt = time.Now().Unix() // Event is changed if !strings.Contains(webhook.EventName, "-") { @@ -72,83 +73,80 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) ( } updateFields = strings.Trim(updateFields, " ") updateFields = strings.TrimSuffix(updateFields, ",") - query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Webhook, updateFields, webhook.ID) + query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+schemas.Collections.Webhook, updateFields, webhook.ID) err = p.db.Query(query).Exec() if err != nil { return nil, err } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { - webhooks := []*model.Webhook{} +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) ([]*schemas.Webhook, *model.Pagination, error) { + webhooks := []*schemas.Webhook{} paginationClone := pagination - totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.Webhook) + totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+schemas.Collections.Webhook) err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total) if err != nil { - return nil, err + return nil, nil, err } // there is no offset in cassandra // so we fetch till limit + offset // and return the results from offset to limit - query := fmt.Sprintf("SELECT id, event_description, 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+"."+schemas.Collections.Webhook, pagination.Limit+pagination.Offset) scanner := p.db.Query(query).Iter().Scanner() counter := int64(0) for scanner.Next() { if counter >= pagination.Offset { - var webhook models.Webhook + var webhook schemas.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 + return nil, nil, err } - webhooks = append(webhooks, webhook.AsAPIWebhook()) + webhooks = append(webhooks, &webhook) } counter++ } - return &model.Webhooks{ - Pagination: paginationClone, - Webhooks: webhooks, - }, nil + return webhooks, paginationClone, nil } // GetWebhookByID to get webhook by id -func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) { - var webhook models.Webhook - query := fmt.Sprintf(`SELECT id, event_description, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1`, KeySpace+"."+models.Collections.Webhook, webhookID) +func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*schemas.Webhook, error) { + var webhook schemas.Webhook + query := fmt.Sprintf(`SELECT id, event_description, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1`, KeySpace+"."+schemas.Collections.Webhook, webhookID) 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 { return nil, err } - return webhook.AsAPIWebhook(), nil + return &webhook, nil } // GetWebhookByEventName to get webhook by event_name -func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*model.Webhook, error) { - query := fmt.Sprintf(`SELECT id, event_description, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s WHERE event_name LIKE '%s' ALLOW FILTERING`, KeySpace+"."+models.Collections.Webhook, eventName+"%") +func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*schemas.Webhook, error) { + query := fmt.Sprintf(`SELECT id, event_description, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s WHERE event_name LIKE '%s' ALLOW FILTERING`, KeySpace+"."+schemas.Collections.Webhook, eventName+"%") scanner := p.db.Query(query).Iter().Scanner() - webhooks := []*model.Webhook{} + webhooks := []*schemas.Webhook{} for scanner.Next() { - var webhook models.Webhook + var webhook schemas.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()) + webhooks = append(webhooks, &webhook) } return webhooks, nil } // DeleteWebhook to delete webhook -func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error { - query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.Webhook, webhook.ID) +func (p *provider) DeleteWebhook(ctx context.Context, webhook *schemas.Webhook) error { + query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+schemas.Collections.Webhook, webhook.ID) err := p.db.Query(query).Exec() if err != nil { return err } - getWebhookLogQuery := fmt.Sprintf("SELECT id FROM %s WHERE webhook_id = '%s' ALLOW FILTERING", KeySpace+"."+models.Collections.WebhookLog, webhook.ID) + getWebhookLogQuery := fmt.Sprintf("SELECT id FROM %s WHERE webhook_id = '%s' ALLOW FILTERING", KeySpace+"."+schemas.Collections.WebhookLog, webhook.ID) scanner := p.db.Query(getWebhookLogQuery).Iter().Scanner() webhookLogIDs := "" for scanner.Next() { @@ -160,7 +158,7 @@ func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) er webhookLogIDs += fmt.Sprintf("'%s',", wlID) } webhookLogIDs = strings.TrimSuffix(webhookLogIDs, ",") - query = fmt.Sprintf("DELETE FROM %s WHERE id IN (%s)", KeySpace+"."+models.Collections.WebhookLog, webhookLogIDs) + query = fmt.Sprintf("DELETE FROM %s WHERE id IN (%s)", KeySpace+"."+schemas.Collections.WebhookLog, webhookLogIDs) err = p.db.Query(query).Exec() return err } diff --git a/server/db/providers/cassandradb/webhook_log.go b/internal/storage/db/cassandradb/webhook_log.go similarity index 61% rename from server/db/providers/cassandradb/webhook_log.go rename to internal/storage/db/cassandradb/webhook_log.go index d587e026a..d01d4b323 100644 --- a/server/db/providers/cassandradb/webhook_log.go +++ b/internal/storage/db/cassandradb/webhook_log.go @@ -5,14 +5,15 @@ import ( "fmt" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/gocql/gocql" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *schemas.WebhookLog) (*schemas.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } @@ -21,49 +22,46 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.Webhook webhookLog.CreatedAt = time.Now().Unix() webhookLog.UpdatedAt = time.Now().Unix() - insertQuery := fmt.Sprintf("INSERT INTO %s (id, http_status, response, request, webhook_id, created_at, updated_at) VALUES ('%s', %d,'%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.WebhookLog, webhookLog.ID, webhookLog.HttpStatus, webhookLog.Response, webhookLog.Request, webhookLog.WebhookID, webhookLog.CreatedAt, webhookLog.UpdatedAt) + insertQuery := fmt.Sprintf("INSERT INTO %s (id, http_status, response, request, webhook_id, created_at, updated_at) VALUES ('%s', %d,'%s', '%s', '%s', %d, %d)", KeySpace+"."+schemas.Collections.WebhookLog, webhookLog.ID, webhookLog.HttpStatus, webhookLog.Response, webhookLog.Request, webhookLog.WebhookID, webhookLog.CreatedAt, webhookLog.UpdatedAt) err := p.db.Query(insertQuery).Exec() if err != nil { return nil, err } - return webhookLog.AsAPIWebhookLog(), nil + return webhookLog, nil } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { - webhookLogs := []*model.WebhookLog{} +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) ([]*schemas.WebhookLog, *model.Pagination, error) { + webhookLogs := []*schemas.WebhookLog{} paginationClone := pagination - totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.WebhookLog) + totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+schemas.Collections.WebhookLog) // there is no offset in cassandra // so we fetch till limit + offset // and return the results from offset to limit - query := fmt.Sprintf("SELECT id, http_status, response, request, webhook_id, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.WebhookLog, pagination.Limit+pagination.Offset) + query := fmt.Sprintf("SELECT id, http_status, response, request, webhook_id, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+schemas.Collections.WebhookLog, pagination.Limit+pagination.Offset) if webhookID != "" { - totalCountQuery = fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE webhook_id='%s' ALLOW FILTERING`, KeySpace+"."+models.Collections.WebhookLog, webhookID) - query = fmt.Sprintf("SELECT id, http_status, response, request, webhook_id, created_at, updated_at FROM %s WHERE webhook_id = '%s' LIMIT %d ALLOW FILTERING", KeySpace+"."+models.Collections.WebhookLog, webhookID, pagination.Limit+pagination.Offset) + totalCountQuery = fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE webhook_id='%s' ALLOW FILTERING`, KeySpace+"."+schemas.Collections.WebhookLog, webhookID) + query = fmt.Sprintf("SELECT id, http_status, response, request, webhook_id, created_at, updated_at FROM %s WHERE webhook_id = '%s' LIMIT %d ALLOW FILTERING", KeySpace+"."+schemas.Collections.WebhookLog, webhookID, pagination.Limit+pagination.Offset) } err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total) if err != nil { - return nil, err + return nil, nil, err } scanner := p.db.Query(query).Iter().Scanner() counter := int64(0) for scanner.Next() { if counter >= pagination.Offset { - var webhookLog models.WebhookLog + var webhookLog schemas.WebhookLog err := scanner.Scan(&webhookLog.ID, &webhookLog.HttpStatus, &webhookLog.Response, &webhookLog.Request, &webhookLog.WebhookID, &webhookLog.CreatedAt, &webhookLog.UpdatedAt) if err != nil { - return nil, err + return nil, nil, err } - webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog()) + webhookLogs = append(webhookLogs, &webhookLog) } counter++ } - return &model.WebhookLogs{ - Pagination: paginationClone, - WebhookLogs: webhookLogs, - }, nil + return webhookLogs, paginationClone, nil } diff --git a/server/db/providers/couchbase/authenticator.go b/internal/storage/db/couchbase/authenticator.go similarity index 77% rename from server/db/providers/couchbase/authenticator.go rename to internal/storage/db/couchbase/authenticator.go index dc81cb9da..9662679da 100644 --- a/server/db/providers/couchbase/authenticator.go +++ b/internal/storage/db/couchbase/authenticator.go @@ -10,10 +10,10 @@ import ( "github.com/couchbase/gocb/v2" "github.com/google/uuid" - "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) -func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) AddAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method) if exists != nil { return authenticators, nil @@ -28,14 +28,14 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models. insertOpt := gocb.InsertOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.Authenticators).Insert(authenticators.ID, authenticators, &insertOpt) + _, err := p.db.Collection(schemas.Collections.Authenticators).Insert(authenticators.ID, authenticators, &insertOpt) if err != nil { return nil, err } return authenticators, nil } -func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { authenticators.UpdatedAt = time.Now().Unix() bytes, err := json.Marshal(authenticators) if err != nil { @@ -50,7 +50,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode return nil, err } updateFields, params := GetSetFields(authenticator) - query := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = '%s'", p.scopeName, models.Collections.Authenticators, updateFields, authenticators.ID) + query := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = '%s'", p.scopeName, schemas.Collections.Authenticators, updateFields, authenticators.ID) _, err = p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, @@ -62,9 +62,9 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode return authenticators, nil } -func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) { - var authenticators *models.Authenticator - query := fmt.Sprintf("SELECT _id, user_id, method, secret, recovery_code, verified_at, created_at, updated_at FROM %s.%s WHERE user_id = $1 AND method = $2 LIMIT 1", p.scopeName, models.Collections.Authenticators) +func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*schemas.Authenticator, error) { + var authenticators *schemas.Authenticator + query := fmt.Sprintf("SELECT _id, user_id, method, secret, recovery_code, verified_at, created_at, updated_at FROM %s.%s WHERE user_id = $1 AND method = $2 LIMIT 1", p.scopeName, schemas.Collections.Authenticators) q, err := p.db.Query(query, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, Context: ctx, diff --git a/server/db/providers/couchbase/email_template.go b/internal/storage/db/couchbase/email_template.go similarity index 68% rename from server/db/providers/couchbase/email_template.go rename to internal/storage/db/couchbase/email_template.go index 14f5ba940..deebfac15 100644 --- a/server/db/providers/couchbase/email_template.go +++ b/internal/storage/db/couchbase/email_template.go @@ -8,14 +8,15 @@ import ( "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" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() @@ -28,16 +29,16 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.E Context: ctx, } - _, err := p.db.Collection(models.Collections.EmailTemplate).Insert(emailTemplate.ID, emailTemplate, &insertOpt) + _, err := p.db.Collection(schemas.Collections.EmailTemplate).Insert(emailTemplate.ID, emailTemplate, &insertOpt) if err != nil { - return emailTemplate.AsAPIEmailTemplate(), err + return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { bytes, err := json.Marshal(emailTemplate) if err != nil { return nil, err @@ -54,7 +55,7 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *model 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) + query := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = $emailId", p.scopeName, schemas.Collections.EmailTemplate, updateFields) _, err = p.db.Query(query, &gocb.QueryOptions{ Context: ctx, @@ -63,19 +64,19 @@ func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *model if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { - emailTemplates := []*model.EmailTemplate{} +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) ([]*schemas.EmailTemplate, *model.Pagination, error) { + emailTemplates := []*schemas.EmailTemplate{} paginationClone := pagination - total, err := p.GetTotalDocs(ctx, models.Collections.EmailTemplate) + total, err := p.GetTotalDocs(ctx, schemas.Collections.EmailTemplate) if err != nil { - return nil, err + return nil, 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) + 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, schemas.Collections.EmailTemplate) queryResult, err := p.db.Query(userQuery, &gocb.QueryOptions{ Context: ctx, @@ -84,33 +85,30 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagi }) if err != nil { - return nil, err + return nil, nil, err } for queryResult.Next() { - var emailTemplate *models.EmailTemplate + var emailTemplate *schemas.EmailTemplate err := queryResult.Row(&emailTemplate) if err != nil { log.Fatal(err) } - emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate()) + emailTemplates = append(emailTemplates, emailTemplate) } if err := queryResult.Err(); err != nil { - return nil, err + return nil, nil, err } - return &model.EmailTemplates{ - Pagination: paginationClone, - EmailTemplates: emailTemplates, - }, nil + return emailTemplates, paginationClone, nil } // GetEmailTemplateByID to get EmailTemplate by id -func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { - var emailTemplate *models.EmailTemplate - query := fmt.Sprintf(`SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1`, p.scopeName, models.Collections.EmailTemplate) +func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*schemas.EmailTemplate, error) { + var emailTemplate *schemas.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, schemas.Collections.EmailTemplate) q, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, @@ -123,13 +121,13 @@ func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID str if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // GetEmailTemplateByEventName to get EmailTemplate by event_name -func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { - var emailTemplate models.EmailTemplate - query := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE event_name=$1 LIMIT 1", p.scopeName, models.Collections.EmailTemplate) +func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*schemas.EmailTemplate, error) { + var emailTemplate schemas.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, schemas.Collections.EmailTemplate) q, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, @@ -142,15 +140,15 @@ func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName st if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return &emailTemplate, nil } // DeleteEmailTemplate to delete EmailTemplate -func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error { +func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) error { removeOpt := gocb.RemoveOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.EmailTemplate).Remove(emailTemplate.ID, &removeOpt) + _, err := p.db.Collection(schemas.Collections.EmailTemplate).Remove(emailTemplate.ID, &removeOpt) if err != nil { return err } diff --git a/server/db/providers/couchbase/env.go b/internal/storage/db/couchbase/env.go similarity index 69% rename from server/db/providers/couchbase/env.go rename to internal/storage/db/couchbase/env.go index 7c08e7f4f..14b20ef2a 100644 --- a/server/db/providers/couchbase/env.go +++ b/internal/storage/db/couchbase/env.go @@ -5,13 +5,14 @@ import ( "fmt" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/couchbase/gocb/v2" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *schemas.Env) (*schemas.Env, error) { if env.ID == "" { env.ID = uuid.New().String() } @@ -22,7 +23,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er insertOpt := gocb.InsertOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.Env).Insert(env.ID, env, &insertOpt) + _, err := p.db.Collection(schemas.Collections.Env).Insert(env.ID, env, &insertOpt) if err != nil { return nil, err } @@ -30,11 +31,11 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er } // 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 *schemas.Env) (*schemas.Env, error) { env.UpdatedAt = time.Now().Unix() env.EncryptionKey = env.Hash - updateEnvQuery := fmt.Sprintf("UPDATE %s.%s SET env = $1, updated_at = $2 WHERE _id = $3", p.scopeName, models.Collections.Env) + updateEnvQuery := fmt.Sprintf("UPDATE %s.%s SET env = $1, updated_at = $2 WHERE _id = $3", p.scopeName, schemas.Collections.Env) _, err := p.db.Query(updateEnvQuery, &gocb.QueryOptions{ Context: ctx, PositionalParameters: []interface{}{env.EnvData, env.UpdatedAt, env.UpdatedAt, env.ID}, @@ -46,10 +47,10 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { - var env *models.Env +func (p *provider) GetEnv(ctx context.Context) (*schemas.Env, error) { + var env *schemas.Env - query := fmt.Sprintf("SELECT _id, env, encryption_key, created_at, updated_at FROM %s.%s LIMIT 1", p.scopeName, models.Collections.Env) + query := fmt.Sprintf("SELECT _id, env, encryption_key, created_at, updated_at FROM %s.%s LIMIT 1", p.scopeName, schemas.Collections.Env) q, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, diff --git a/server/db/providers/couchbase/otp.go b/internal/storage/db/couchbase/otp.go similarity index 74% rename from server/db/providers/couchbase/otp.go rename to internal/storage/db/couchbase/otp.go index 2980b94e0..1e9261043 100644 --- a/server/db/providers/couchbase/otp.go +++ b/internal/storage/db/couchbase/otp.go @@ -6,23 +6,24 @@ import ( "fmt" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/couchbase/gocb/v2" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // UpsertOTP to add or update otp -func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { +func (p *provider) UpsertOTP(ctx context.Context, otpParam *schemas.OTP) (*schemas.OTP, error) { // check if email or phone number is present if otpParam.Email == "" && otpParam.PhoneNumber == "" { return nil, errors.New("email or phone_number is required") } - uniqueField := models.FieldNameEmail + uniqueField := schemas.FieldNameEmail if otpParam.Email == "" && otpParam.PhoneNumber != "" { - uniqueField = models.FieldNamePhoneNumber + uniqueField = schemas.FieldNamePhoneNumber } - var otp *models.OTP - if uniqueField == models.FieldNameEmail { + var otp *schemas.OTP + if uniqueField == schemas.FieldNameEmail { otp, _ = p.GetOTPByEmail(ctx, otpParam.Email) } else { otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber) @@ -30,7 +31,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models shouldCreate := false if otp == nil { shouldCreate = true - otp = &models.OTP{ + otp = &schemas.OTP{ ID: uuid.NewString(), Otp: otpParam.Otp, Email: otpParam.Email, @@ -48,12 +49,12 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models insertOpt := gocb.InsertOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.OTP).Insert(otp.ID, otp, &insertOpt) + _, err := p.db.Collection(schemas.Collections.OTP).Insert(otp.ID, otp, &insertOpt) if err != nil { return nil, 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) + query := fmt.Sprintf(`UPDATE %s.%s SET otp=$1, expires_at=$2, updated_at=$3 WHERE _id=$4`, p.scopeName, schemas.Collections.OTP) _, err := p.db.Query(query, &gocb.QueryOptions{ PositionalParameters: []interface{}{otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID}, }) @@ -65,9 +66,9 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models } // GetOTPByEmail to get otp for a given email address -func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { - otp := models.OTP{} - query := fmt.Sprintf(`SELECT _id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1`, p.scopeName, models.Collections.OTP) +func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*schemas.OTP, error) { + otp := schemas.OTP{} + query := fmt.Sprintf(`SELECT _id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1`, p.scopeName, schemas.Collections.OTP) q, err := p.db.Query(query, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, PositionalParameters: []interface{}{emailAddress}, @@ -83,9 +84,9 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod } // GetOTPByPhoneNumber to get otp for a given phone number -func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { - otp := models.OTP{} - query := fmt.Sprintf(`SELECT _id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1`, p.scopeName, models.Collections.OTP) +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.OTP, error) { + otp := schemas.OTP{} + query := fmt.Sprintf(`SELECT _id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1`, p.scopeName, schemas.Collections.OTP) q, err := p.db.Query(query, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, PositionalParameters: []interface{}{phoneNumber}, @@ -101,11 +102,11 @@ func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) } // DeleteOTP to delete otp -func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { +func (p *provider) DeleteOTP(ctx context.Context, otp *schemas.OTP) error { removeOpt := gocb.RemoveOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.OTP).Remove(otp.ID, &removeOpt) + _, err := p.db.Collection(schemas.Collections.OTP).Remove(otp.ID, &removeOpt) if err != nil { return err } diff --git a/server/db/providers/couchbase/provider.go b/internal/storage/db/couchbase/provider.go similarity index 58% rename from server/db/providers/couchbase/provider.go rename to internal/storage/db/couchbase/provider.go index 7eef85da0..270893c2f 100644 --- a/server/db/providers/couchbase/provider.go +++ b/internal/storage/db/couchbase/provider.go @@ -10,28 +10,38 @@ import ( "time" "github.com/couchbase/gocb/v2" + "github.com/rs/zerolog" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) +// Dependencies struct the couchbase data store provider +type Dependencies struct { + Log *zerolog.Logger +} + const ( defaultBucketName = "authorizer" defaultScope = "_default" ) type provider struct { + config *config.Config + dependencies *Dependencies + 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 +func NewProvider(config *config.Config, deps *Dependencies) (*provider, error) { + bucketName := config.CouchBaseBucket + ramQuota := config.CouchBaseRamQuota + scopeName := config.CouchBaseScope + dbURL := config.DatabaseURL + userName := config.DatabaseUsername + password := config.DatabasePassword opts := gocb.ClusterOptions{ Username: userName, Password: password, @@ -46,14 +56,19 @@ func NewProvider() (*provider, error) { if err != nil { return nil, err } + // Wait until the cluster is ready + err = cluster.WaitUntilReady(30*time.Second, nil) + if err != nil { + return nil, err + } // To create the bucket and scope if not exist - bucket, err := CreateBucketAndScope(cluster, bucketName, scopeName) + bucket, err := createBucketAndScope(cluster, bucketName, scopeName, ramQuota) if err != nil { return nil, err } scope := bucket.Scope(scopeName) scopeIdentifier := fmt.Sprintf("%s.%s", bucketName, scopeName) - v := reflect.ValueOf(models.Collections) + v := reflect.ValueOf(schemas.Collections) for i := 0; i < v.NumField(); i++ { collectionName := v.Field(i) user := gocb.CollectionSpec{ @@ -77,7 +92,7 @@ func NewProvider() (*provider, error) { } } - indices := GetIndex(scopeIdentifier) + indices := getIndex(scopeIdentifier) for i := 0; i < v.NumField(); i++ { field := v.Field(i) for _, indexQuery := range indices[field.String()] { @@ -85,17 +100,18 @@ func NewProvider() (*provider, error) { } } return &provider{ - db: scope, - scopeName: scopeIdentifier, + config: config, + dependencies: deps, + 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" +func createBucketAndScope(cluster *gocb.Cluster, bucketName string, scopeName string, ramQuota string) (*gocb.Bucket, error) { + if ramQuota == "" { + ramQuota = "1000" } - bucketRAMQuota, err := strconv.ParseInt(bucketRAMQuotaMB, 10, 64) + bucketRAMQuota, err := strconv.ParseInt(ramQuota, 10, 64) if err != nil { return nil, err } @@ -124,6 +140,11 @@ func CreateBucketAndScope(cluster *gocb.Cluster, bucketName string, scopeName st } } bucket := cluster.Bucket(bucketName) + // Wait until bucket is ready + err = bucket.WaitUntilReady(30*time.Second, nil) + if err != nil { + return nil, err + } if scopeName != defaultScope { err = bucket.Collections().CreateScope(scopeName, nil) if err != nil && !errors.Is(err, gocb.ErrScopeExists) { @@ -133,42 +154,42 @@ func CreateBucketAndScope(cluster *gocb.Cluster, bucketName string, scopeName st return bucket, nil } -func GetIndex(scopeName string) map[string][]string { +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} + userIndex1 := fmt.Sprintf("CREATE INDEX userEmailIndex ON %s.%s(email)", scopeName, schemas.Collections.User) + userIndex2 := fmt.Sprintf("CREATE INDEX userPhoneIndex ON %s.%s(phone_number)", scopeName, schemas.Collections.User) + indices[schemas.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} + verificationIndex1 := fmt.Sprintf("CREATE INDEX verificationRequestTokenIndex ON %s.%s(token)", scopeName, schemas.Collections.VerificationRequest) + verificationIndex2 := fmt.Sprintf("CREATE INDEX verificationRequestEmailAndIdentifierIndex ON %s.%s(email,identifier)", scopeName, schemas.Collections.VerificationRequest) + indices[schemas.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} + sessionIndex1 := fmt.Sprintf("CREATE INDEX SessionUserIdIndex ON %s.%s(user_id)", scopeName, schemas.Collections.Session) + indices[schemas.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} + webhookIndex1 := fmt.Sprintf("CREATE INDEX webhookEventNameIndex ON %s.%s(event_name)", scopeName, schemas.Collections.Webhook) + indices[schemas.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} + webhookLogIndex1 := fmt.Sprintf("CREATE INDEX webhookLogIdIndex ON %s.%s(webhook_id)", scopeName, schemas.Collections.WebhookLog) + indices[schemas.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} + emailTempIndex1 := fmt.Sprintf("CREATE INDEX EmailTemplateEventNameIndex ON %s.%s(event_name)", scopeName, schemas.Collections.EmailTemplate) + indices[schemas.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} + otpIndex1 := fmt.Sprintf("CREATE INDEX OTPEmailIndex ON %s.%s(email)", scopeName, schemas.Collections.OTP) + indices[schemas.Collections.OTP] = []string{otpIndex1} // OTP index - otpIndex2 := fmt.Sprintf("CREATE INDEX OTPPhoneNumberIndex ON %s.%s(phone_number)", scopeName, models.Collections.OTP) - indices[models.Collections.OTP] = []string{otpIndex2} + otpIndex2 := fmt.Sprintf("CREATE INDEX OTPPhoneNumberIndex ON %s.%s(phone_number)", scopeName, schemas.Collections.OTP) + indices[schemas.Collections.OTP] = []string{otpIndex2} return indices } diff --git a/server/db/providers/couchbase/session.go b/internal/storage/db/couchbase/session.go similarity index 59% rename from server/db/providers/couchbase/session.go rename to internal/storage/db/couchbase/session.go index a3b991576..74531a34c 100644 --- a/server/db/providers/couchbase/session.go +++ b/internal/storage/db/couchbase/session.go @@ -4,22 +4,24 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/couchbase/gocb/v2" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session *models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *schemas.Session) error { if session.ID == "" { session.ID = uuid.New().String() + session.CreatedAt = time.Now().Unix() + + session.UpdatedAt = time.Now().Unix() } - session.CreatedAt = 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) + _, err := p.db.Collection(schemas.Collections.Session).Insert(session.ID, session, &insertOpt) if err != nil { return err } diff --git a/server/db/providers/couchbase/shared.go b/internal/storage/db/couchbase/shared.go similarity index 93% rename from server/db/providers/couchbase/shared.go rename to internal/storage/db/couchbase/shared.go index a97ac6d97..cc770c9b7 100644 --- a/server/db/providers/couchbase/shared.go +++ b/internal/storage/db/couchbase/shared.go @@ -9,6 +9,7 @@ import ( "github.com/couchbase/gocb/v2" ) +// GetSetFields to get set fields func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interface{}) { params := make(map[string]interface{}, 1) updateFields := "" @@ -39,6 +40,7 @@ func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interfa return updateFields, params } +// GetTotalDocs to get total documents in a collection 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) diff --git a/server/db/providers/couchbase/user.go b/internal/storage/db/couchbase/user.go similarity index 76% rename from server/db/providers/couchbase/user.go rename to internal/storage/db/couchbase/user.go index ec80b7d66..84e6a2101 100644 --- a/server/db/providers/couchbase/user.go +++ b/internal/storage/db/couchbase/user.go @@ -7,27 +7,22 @@ import ( "strings" "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/authorizerdev/authorizer/server/refs" "github.com/couchbase/gocb/v2" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { if user.ID == "" { user.ID = uuid.New().String() } if user.Roles == "" { - defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - return nil, err - } - user.Roles = defaultRoles + user.Roles = strings.Join(p.config.DefaultRoles, ",") } if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" { @@ -45,7 +40,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User insertOpt := gocb.InsertOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.User).Insert(user.ID, user, &insertOpt) + _, err := p.db.Collection(schemas.Collections.User).Insert(user.ID, user, &insertOpt) if err != nil { return nil, err } @@ -53,12 +48,12 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User } // UpdateUser to update user information in database -func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) UpdateUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { user.UpdatedAt = time.Now().Unix() upsertOpt := gocb.UpsertOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &upsertOpt) + _, err := p.db.Collection(schemas.Collections.User).Upsert(user.ID, user, &upsertOpt) if err != nil { return nil, err } @@ -66,11 +61,11 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U } // 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 *schemas.User) error { removeOpt := gocb.RemoveOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.User).Remove(user.ID, &removeOpt) + _, err := p.db.Collection(schemas.Collections.User).Remove(user.ID, &removeOpt) if err != nil { return err } @@ -78,44 +73,41 @@ func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { - users := []*model.User{} +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) ([]*schemas.User, *model.Pagination, error) { + users := []*schemas.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, app_data, created_at, updated_at FROM %s.%s ORDER BY id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.User) + userQuery := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s ORDER BY id OFFSET $1 LIMIT $2", p.scopeName, schemas.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 + return nil, nil, err } - total, err := p.GetTotalDocs(ctx, models.Collections.User) + total, err := p.GetTotalDocs(ctx, schemas.Collections.User) if err != nil { - return nil, err + return nil, nil, err } paginationClone.Total = total for queryResult.Next() { - var user models.User + var user schemas.User err := queryResult.Row(&user) if err != nil { log.Fatal(err) } - users = append(users, user.AsAPIUser()) + users = append(users, &user) } if err := queryResult.Err(); err != nil { - return nil, err + return nil, nil, err } - return &model.Users{ - Pagination: paginationClone, - Users: users, - }, nil + return users, paginationClone, 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 - query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1", p.scopeName, models.Collections.User) +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*schemas.User, error) { + var user *schemas.User + query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1", p.scopeName, schemas.Collections.User) q, err := p.db.Query(query, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, Context: ctx, @@ -132,9 +124,9 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us } // 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 - query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1", p.scopeName, models.Collections.User) +func (p *provider) GetUserByID(ctx context.Context, id string) (*schemas.User, error) { + var user *schemas.User + query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1", p.scopeName, schemas.Collections.User) q, err := p.db.Query(query, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, Context: ctx, @@ -159,7 +151,7 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, 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) + userQuery := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = $id", p.scopeName, schemas.Collections.User, updateFields) _, err := p.db.Query(userQuery, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, @@ -171,7 +163,7 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } } } else { - userQuery := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id IS NOT NULL", p.scopeName, models.Collections.User, updateFields) + userQuery := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id IS NOT NULL", p.scopeName, schemas.Collections.User, updateFields) _, err := p.db.Query(userQuery, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, Context: ctx, @@ -185,9 +177,9 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } // GetUserByPhoneNumber to get user information from database using phone number -func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) { - var user *models.User - query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1", p.scopeName, models.Collections.User) +func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.User, error) { + var user *schemas.User + query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1", p.scopeName, schemas.Collections.User) q, err := p.db.Query(query, &gocb.QueryOptions{ ScanConsistency: gocb.QueryScanConsistencyRequestPlus, Context: ctx, diff --git a/server/db/providers/couchbase/verification_requests.go b/internal/storage/db/couchbase/verification_requests.go similarity index 65% rename from server/db/providers/couchbase/verification_requests.go rename to internal/storage/db/couchbase/verification_requests.go index 4448eab74..582af178b 100644 --- a/server/db/providers/couchbase/verification_requests.go +++ b/internal/storage/db/couchbase/verification_requests.go @@ -6,14 +6,15 @@ import ( "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" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) (*schemas.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() } @@ -23,7 +24,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque insertOpt := gocb.InsertOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.VerificationRequest).Insert(verificationRequest.ID, verificationRequest, &insertOpt) + _, err := p.db.Collection(schemas.Collections.VerificationRequest).Insert(verificationRequest.ID, verificationRequest, &insertOpt) if err != nil { return nil, err } @@ -31,11 +32,11 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { - var verificationRequest *models.VerificationRequest +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*schemas.VerificationRequest, error) { + var verificationRequest *schemas.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) + 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, schemas.Collections.VerificationRequest) queryResult, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, @@ -55,9 +56,9 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*schemas.VerificationRequest, error) { - query := fmt.Sprintf("SELECT _id, identifier, token, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE email=$1 AND identifier=$2 LIMIT 1", p.scopeName, models.Collections.VerificationRequest) + query := fmt.Sprintf("SELECT _id, identifier, token, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE email=$1 AND identifier=$2 LIMIT 1", p.scopeName, schemas.Collections.VerificationRequest) queryResult, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, PositionalParameters: []interface{}{email, identifier}, @@ -66,7 +67,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri if err != nil { return nil, err } - var verificationRequest *models.VerificationRequest + var verificationRequest *schemas.VerificationRequest err = queryResult.One(&verificationRequest) if err != nil { return nil, err @@ -75,47 +76,44 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { - var verificationRequests []*model.VerificationRequest +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) ([]*schemas.VerificationRequest, *model.Pagination, error) { + var verificationRequests []*schemas.VerificationRequest paginationClone := pagination - total, err := p.GetTotalDocs(ctx, models.Collections.VerificationRequest) + total, err := p.GetTotalDocs(ctx, schemas.Collections.VerificationRequest) if err != nil { - return nil, err + return nil, 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) + query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM %s.%s OFFSET $1 LIMIT $2", p.scopeName, schemas.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 + return nil, nil, err } for queryResult.Next() { - var verificationRequest models.VerificationRequest + var verificationRequest schemas.VerificationRequest err := queryResult.Row(&verificationRequest) if err != nil { log.Fatal(err) } - verificationRequests = append(verificationRequests, verificationRequest.AsAPIVerificationRequest()) + verificationRequests = append(verificationRequests, &verificationRequest) } if err := queryResult.Err(); err != nil { - return nil, err + return nil, nil, err } - return &model.VerificationRequests{ - VerificationRequests: verificationRequests, - Pagination: paginationClone, - }, nil + return verificationRequests, paginationClone, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) error { removeOpt := gocb.RemoveOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.VerificationRequest).Remove(verificationRequest.ID, &removeOpt) + _, err := p.db.Collection(schemas.Collections.VerificationRequest).Remove(verificationRequest.ID, &removeOpt) if err != nil { return err } diff --git a/server/db/providers/couchbase/webhook.go b/internal/storage/db/couchbase/webhook.go similarity index 71% rename from server/db/providers/couchbase/webhook.go rename to internal/storage/db/couchbase/webhook.go index 23dea5e9e..14d12aa54 100644 --- a/server/db/providers/couchbase/webhook.go +++ b/internal/storage/db/couchbase/webhook.go @@ -8,14 +8,15 @@ import ( "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" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // 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 *schemas.Webhook) (*schemas.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() } @@ -27,15 +28,15 @@ func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*mo insertOpt := gocb.InsertOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.Webhook).Insert(webhook.ID, webhook, &insertOpt) + _, err := p.db.Collection(schemas.Collections.Webhook).Insert(webhook.ID, webhook, &insertOpt) if err != nil { return nil, err } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // 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 *schemas.Webhook) (*schemas.Webhook, error) { webhook.UpdatedAt = time.Now().Unix() // Event is changed if !strings.Contains(webhook.EventName, "-") { @@ -54,7 +55,7 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) ( 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) + query := fmt.Sprintf(`UPDATE %s.%s SET %s WHERE _id='%s'`, p.scopeName, schemas.Collections.Webhook, updateFields, webhook.ID) _, err = p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, @@ -64,53 +65,50 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) ( return nil, err } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { - webhooks := []*model.Webhook{} +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) ([]*schemas.Webhook, *model.Pagination, error) { + webhooks := []*schemas.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) + total, err := p.GetTotalDocs(ctx, schemas.Collections.Webhook) if err != nil { - return nil, err + return nil, 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) + 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, schemas.Collections.Webhook) queryResult, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, NamedParameters: params, }) if err != nil { - return nil, err + return nil, nil, err } for queryResult.Next() { - var webhook models.Webhook + var webhook schemas.Webhook err := queryResult.Row(&webhook) if err != nil { log.Fatal(err) } - webhooks = append(webhooks, webhook.AsAPIWebhook()) + webhooks = append(webhooks, &webhook) } if err := queryResult.Err(); err != nil { - return nil, err + return nil, nil, err } - return &model.Webhooks{ - Pagination: paginationClone, - Webhooks: webhooks, - }, nil + return webhooks, paginationClone, nil } // GetWebhookByID to get webhook by id -func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) { - var webhook *models.Webhook +func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*schemas.Webhook, error) { + var webhook *schemas.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) + 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, schemas.Collections.Webhook) q, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, @@ -123,14 +121,14 @@ func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model if err != nil { return nil, err } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // 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) ([]*schemas.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+"%") + 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, schemas.Collections.Webhook, eventName+"%") queryResult, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, @@ -139,14 +137,14 @@ func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) if err != nil { return nil, err } - webhooks := []*model.Webhook{} + webhooks := []*schemas.Webhook{} for queryResult.Next() { - var webhook *models.Webhook + var webhook *schemas.Webhook err := queryResult.Row(&webhook) if err != nil { log.Fatal(err) } - webhooks = append(webhooks, webhook.AsAPIWebhook()) + webhooks = append(webhooks, webhook) } if err := queryResult.Err(); err != nil { return nil, err @@ -155,17 +153,17 @@ func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) } // DeleteWebhook to delete webhook -func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error { +func (p *provider) DeleteWebhook(ctx context.Context, webhook *schemas.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) + _, err := p.db.Collection(schemas.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) + query := fmt.Sprintf(`DELETE FROM %s.%s WHERE webhook_id=$webhook_id`, p.scopeName, schemas.Collections.WebhookLog) _, err = p.db.Query(query, &gocb.QueryOptions{ Context: ctx, ScanConsistency: gocb.QueryScanConsistencyRequestPlus, diff --git a/server/db/providers/couchbase/webhook_log.go b/internal/storage/db/couchbase/webhook_log.go similarity index 64% rename from server/db/providers/couchbase/webhook_log.go rename to internal/storage/db/couchbase/webhook_log.go index fb1d08a92..883347c34 100644 --- a/server/db/providers/couchbase/webhook_log.go +++ b/internal/storage/db/couchbase/webhook_log.go @@ -6,14 +6,15 @@ import ( "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" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *schemas.WebhookLog) (*schemas.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } @@ -23,32 +24,32 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.Webhook insertOpt := gocb.InsertOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.WebhookLog).Insert(webhookLog.ID, webhookLog, &insertOpt) + _, err := p.db.Collection(schemas.Collections.WebhookLog).Insert(webhookLog.ID, webhookLog, &insertOpt) if err != nil { return nil, err } - return webhookLog.AsAPIWebhookLog(), nil + return webhookLog, nil } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) ([]*schemas.WebhookLog, *model.Pagination, error) { var query string var err error - webhookLogs := []*model.WebhookLog{} + webhookLogs := []*schemas.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) + total, err := p.GetTotalDocs(ctx, schemas.Collections.WebhookLog) if err != nil { - return nil, err + return nil, 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) + query = fmt.Sprintf(`SELECT _id, http_status, response, request, webhook_id, created_at, updated_at FROM %s.%s WHERE webhook_id=$webhookID`, p.scopeName, schemas.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) + query = fmt.Sprintf("SELECT _id, http_status, response, request, webhook_id, created_at, updated_at FROM %s.%s OFFSET $offset LIMIT $limit", p.scopeName, schemas.Collections.WebhookLog) } queryResult, err := p.db.Query(query, &gocb.QueryOptions{ Context: ctx, @@ -56,22 +57,19 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagina NamedParameters: params, }) if err != nil { - return nil, err + return nil, nil, err } for queryResult.Next() { - var webhookLog models.WebhookLog + var webhookLog schemas.WebhookLog err := queryResult.Row(&webhookLog) if err != nil { log.Fatal(err) } - webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog()) + webhookLogs = append(webhookLogs, &webhookLog) } if err := queryResult.Err(); err != nil { - return nil, err + return nil, nil, err } - return &model.WebhookLogs{ - Pagination: paginationClone, - WebhookLogs: webhookLogs, - }, nil + return webhookLogs, paginationClone, nil } diff --git a/server/db/providers/dynamodb/authenticator.go b/internal/storage/db/dynamodb/authenticator.go similarity index 70% rename from server/db/providers/dynamodb/authenticator.go rename to internal/storage/db/dynamodb/authenticator.go index 56ffea156..88e349ade 100644 --- a/server/db/providers/dynamodb/authenticator.go +++ b/internal/storage/db/dynamodb/authenticator.go @@ -6,16 +6,16 @@ import ( "github.com/google/uuid" - "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) -func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) AddAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method) if exists != nil { return authenticators, nil } - collection := p.db.Table(models.Collections.Authenticators) + collection := p.db.Table(schemas.Collections.Authenticators) if authenticators.ID == "" { authenticators.ID = uuid.New().String() } @@ -29,8 +29,8 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models. return authenticators, nil } -func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { - collection := p.db.Table(models.Collections.Authenticators) +func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { + collection := p.db.Table(schemas.Collections.Authenticators) if authenticators.ID != "" { authenticators.UpdatedAt = time.Now().Unix() err := UpdateByHashKey(collection, "id", authenticators.ID, authenticators) @@ -42,9 +42,9 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode } -func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) { - var authenticators *models.Authenticator - collection := p.db.Table(models.Collections.Authenticators) +func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*schemas.Authenticator, error) { + var authenticators *schemas.Authenticator + collection := p.db.Table(schemas.Collections.Authenticators) iter := collection.Scan().Filter("'user_id' = ?", userId).Filter("'method' = ?", authenticatorType).Iter() for iter.NextWithContext(ctx, &authenticators) { return authenticators, nil diff --git a/server/db/providers/dynamodb/email_template.go b/internal/storage/db/dynamodb/email_template.go similarity index 58% rename from server/db/providers/dynamodb/email_template.go rename to internal/storage/db/dynamodb/email_template.go index 7355bbb82..4dfe25e1c 100644 --- a/server/db/providers/dynamodb/email_template.go +++ b/internal/storage/db/dynamodb/email_template.go @@ -5,15 +5,16 @@ import ( "errors" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" "github.com/guregu/dynamo" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { - collection := p.db.Table(models.Collections.EmailTemplate) +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { + collection := p.db.Table(schemas.Collections.EmailTemplate) if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() } @@ -24,86 +25,82 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.E err := collection.Put(emailTemplate).RunWithContext(ctx) if err != nil { - return emailTemplate.AsAPIEmailTemplate(), err + return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { - collection := p.db.Table(models.Collections.EmailTemplate) +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { + collection := p.db.Table(schemas.Collections.EmailTemplate) emailTemplate.UpdatedAt = time.Now().Unix() err := UpdateByHashKey(collection, "id", emailTemplate.ID, emailTemplate) if err != nil { - return emailTemplate.AsAPIEmailTemplate(), err + return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { - var emailTemplate *models.EmailTemplate +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) ([]*schemas.EmailTemplate, *model.Pagination, error) { + var emailTemplate *schemas.EmailTemplate var iter dynamo.PagingIter var lastEval dynamo.PagingKey var iteration int64 = 0 - collection := p.db.Table(models.Collections.EmailTemplate) - emailTemplates := []*model.EmailTemplate{} + collection := p.db.Table(schemas.Collections.EmailTemplate) + emailTemplates := []*schemas.EmailTemplate{} paginationClone := pagination scanner := collection.Scan() count, err := scanner.Count() if err != nil { - return nil, err + return nil, nil, err } for (paginationClone.Offset + paginationClone.Limit) > iteration { iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter() for iter.NextWithContext(ctx, &emailTemplate) { if paginationClone.Offset == iteration { - emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate()) + emailTemplates = append(emailTemplates, emailTemplate) } } lastEval = iter.LastEvaluatedKey() iteration += paginationClone.Limit } paginationClone.Total = count - return &model.EmailTemplates{ - Pagination: paginationClone, - EmailTemplates: emailTemplates, - }, nil + return emailTemplates, paginationClone, nil } // GetEmailTemplateByID to get EmailTemplate by id -func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { - collection := p.db.Table(models.Collections.EmailTemplate) - var emailTemplate *models.EmailTemplate +func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*schemas.EmailTemplate, error) { + collection := p.db.Table(schemas.Collections.EmailTemplate) + var emailTemplate *schemas.EmailTemplate err := collection.Get("id", emailTemplateID).OneWithContext(ctx, &emailTemplate) if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // GetEmailTemplateByEventName to get EmailTemplate by event_name -func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { - collection := p.db.Table(models.Collections.EmailTemplate) - var emailTemplates []*models.EmailTemplate - var emailTemplate *models.EmailTemplate +func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*schemas.EmailTemplate, error) { + collection := p.db.Table(schemas.Collections.EmailTemplate) + var emailTemplates []*schemas.EmailTemplate + var emailTemplate *schemas.EmailTemplate err := collection.Scan().Index("event_name").Filter("'event_name' = ?", eventName).Limit(1).AllWithContext(ctx, &emailTemplates) if err != nil { return nil, err } - if len(emailTemplates) > 0 { - emailTemplate = emailTemplates[0] - return emailTemplate.AsAPIEmailTemplate(), nil - } else { + if len(emailTemplates) == 0 { return nil, errors.New("no record found") - } + } + emailTemplate = emailTemplates[0] + return emailTemplate, nil } // DeleteEmailTemplate to delete EmailTemplate -func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error { - collection := p.db.Table(models.Collections.EmailTemplate) +func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) error { + collection := p.db.Table(schemas.Collections.EmailTemplate) err := collection.Delete("id", emailTemplate.ID).RunWithContext(ctx) if err != nil { return err diff --git a/server/db/providers/dynamodb/env.go b/internal/storage/db/dynamodb/env.go similarity index 63% rename from server/db/providers/dynamodb/env.go rename to internal/storage/db/dynamodb/env.go index 2c788a799..7d0318c1b 100644 --- a/server/db/providers/dynamodb/env.go +++ b/internal/storage/db/dynamodb/env.go @@ -6,13 +6,14 @@ import ( "fmt" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { - collection := p.db.Table(models.Collections.Env) +func (p *provider) AddEnv(ctx context.Context, env *schemas.Env) (*schemas.Env, error) { + collection := p.db.Table(schemas.Collections.Env) if env.ID == "" { env.ID = uuid.New().String() } @@ -27,8 +28,8 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er } // UpdateEnv to update environment information in database -func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) { - collection := p.db.Table(models.Collections.Env) +func (p *provider) UpdateEnv(ctx context.Context, env *schemas.Env) (*schemas.Env, error) { + collection := p.db.Table(schemas.Collections.Env) env.UpdatedAt = time.Now().Unix() err := UpdateByHashKey(collection, "id", env.ID, env) if err != nil { @@ -38,10 +39,10 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { - var env *models.Env - collection := p.db.Table(models.Collections.Env) - // As there is no Findone supported. +func (p *provider) GetEnv(ctx context.Context) (*schemas.Env, error) { + var env *schemas.Env + collection := p.db.Table(schemas.Collections.Env) + // As there is no Find one supported. iter := collection.Scan().Limit(1).Iter() for iter.NextWithContext(ctx, &env) { if env == nil { diff --git a/server/db/providers/dynamodb/otp.go b/internal/storage/db/dynamodb/otp.go similarity index 71% rename from server/db/providers/dynamodb/otp.go rename to internal/storage/db/dynamodb/otp.go index 23273e26e..5e82eaf02 100644 --- a/server/db/providers/dynamodb/otp.go +++ b/internal/storage/db/dynamodb/otp.go @@ -5,22 +5,23 @@ import ( "errors" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // UpsertOTP to add or update otp -func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { +func (p *provider) UpsertOTP(ctx context.Context, otpParam *schemas.OTP) (*schemas.OTP, error) { // check if email or phone number is present if otpParam.Email == "" && otpParam.PhoneNumber == "" { return nil, errors.New("email or phone_number is required") } - uniqueField := models.FieldNameEmail + uniqueField := schemas.FieldNameEmail if otpParam.Email == "" && otpParam.PhoneNumber != "" { - uniqueField = models.FieldNamePhoneNumber + uniqueField = schemas.FieldNamePhoneNumber } - var otp *models.OTP - if uniqueField == models.FieldNameEmail { + var otp *schemas.OTP + if uniqueField == schemas.FieldNameEmail { otp, _ = p.GetOTPByEmail(ctx, otpParam.Email) } else { otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber) @@ -28,7 +29,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models shouldCreate := false if otp == nil { id := uuid.NewString() - otp = &models.OTP{ + otp = &schemas.OTP{ ID: id, Key: id, Otp: otpParam.Otp, @@ -42,7 +43,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models otp.Otp = otpParam.Otp otp.ExpiresAt = otpParam.ExpiresAt } - collection := p.db.Table(models.Collections.OTP) + collection := p.db.Table(schemas.Collections.OTP) otp.UpdatedAt = time.Now().Unix() var err error if shouldCreate { @@ -57,10 +58,10 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models } // GetOTPByEmail to get otp for a given email address -func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { - var otps []models.OTP - var otp models.OTP - collection := p.db.Table(models.Collections.OTP) +func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*schemas.OTP, error) { + var otps []schemas.OTP + var otp schemas.OTP + collection := p.db.Table(schemas.Collections.OTP) err := collection.Scan().Index("email").Filter("'email' = ?", emailAddress).Limit(1).AllWithContext(ctx, &otps) if err != nil { return nil, err @@ -73,10 +74,10 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod } // GetOTPByPhoneNumber to get otp for a given phone number -func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { - var otps []models.OTP - var otp models.OTP - collection := p.db.Table(models.Collections.OTP) +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.OTP, error) { + var otps []schemas.OTP + var otp schemas.OTP + collection := p.db.Table(schemas.Collections.OTP) err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).Limit(1).AllWithContext(ctx, &otps) if err != nil { return nil, err @@ -89,8 +90,8 @@ func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) } // DeleteOTP to delete otp -func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { - collection := p.db.Table(models.Collections.OTP) +func (p *provider) DeleteOTP(ctx context.Context, otp *schemas.OTP) error { + collection := p.db.Table(schemas.Collections.OTP) if otp.ID != "" { err := collection.Delete("id", otp.ID).RunWithContext(ctx) if err != nil { diff --git a/internal/storage/db/dynamodb/provider.go b/internal/storage/db/dynamodb/provider.go new file mode 100644 index 000000000..ac4a00bd7 --- /dev/null +++ b/internal/storage/db/dynamodb/provider.go @@ -0,0 +1,67 @@ +package dynamodb + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/guregu/dynamo" + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/storage/schemas" +) + +// Dependencies struct the dynamodb data store provider +type Dependencies struct { + Log *zerolog.Logger +} + +type provider struct { + config *config.Config + dependencies *Dependencies + db *dynamo.DB +} + +// NewProvider returns a new Dynamo provider +func NewProvider(cfg *config.Config, deps *Dependencies) (*provider, error) { + dbURL := cfg.DatabaseURL + awsRegion := cfg.AWSRegion + awsAccessKeyID := cfg.AWSAccessKeyID + awsSecretAccessKey := cfg.AWSSecretAccessKey + + config := aws.Config{ + MaxRetries: aws.Int(3), + CredentialsChainVerboseErrors: aws.Bool(true), // for full error logs + } + + if awsRegion != "" { + config.Region = aws.String(awsRegion) + } + // custom awsAccessKeyID, awsSecretAccessKey took first priority, if not then fetch config from aws credentials + if awsAccessKeyID != "" && awsSecretAccessKey != "" { + config.Credentials = credentials.NewStaticCredentials(awsAccessKeyID, awsSecretAccessKey, "") + } else if dbURL != "" { + deps.Log.Info().Msg("Using DB URL for dynamodb") + // static config in case of testing or local-setup + config.Credentials = credentials.NewStaticCredentials("key", "key", "") + config.Endpoint = aws.String(dbURL) + } else { + deps.Log.Info().Msg("Using default AWS credentials config from system for dynamodb") + } + session := session.Must(session.NewSession(&config)) + db := dynamo.New(session) + db.CreateTable(schemas.Collections.User, schemas.User{}).Wait() + db.CreateTable(schemas.Collections.Session, schemas.Session{}).Wait() + db.CreateTable(schemas.Collections.EmailTemplate, schemas.EmailTemplate{}).Wait() + db.CreateTable(schemas.Collections.Env, schemas.Env{}).Wait() + db.CreateTable(schemas.Collections.OTP, schemas.OTP{}).Wait() + db.CreateTable(schemas.Collections.VerificationRequest, schemas.VerificationRequest{}).Wait() + db.CreateTable(schemas.Collections.Webhook, schemas.Webhook{}).Wait() + db.CreateTable(schemas.Collections.WebhookLog, schemas.WebhookLog{}).Wait() + db.CreateTable(schemas.Collections.Authenticators, schemas.Authenticator{}).Wait() + return &provider{ + db: db, + config: cfg, + dependencies: deps, + }, nil +} diff --git a/server/db/providers/dynamodb/session.go b/internal/storage/db/dynamodb/session.go similarity index 70% rename from server/db/providers/dynamodb/session.go rename to internal/storage/db/dynamodb/session.go index d65da9a7f..3a06ae406 100644 --- a/server/db/providers/dynamodb/session.go +++ b/internal/storage/db/dynamodb/session.go @@ -4,13 +4,14 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session *models.Session) error { - collection := p.db.Table(models.Collections.Session) +func (p *provider) AddSession(ctx context.Context, session *schemas.Session) error { + collection := p.db.Table(schemas.Collections.Session) if session.ID == "" { session.ID = uuid.New().String() } diff --git a/server/db/providers/dynamodb/shared.go b/internal/storage/db/dynamodb/shared.go similarity index 100% rename from server/db/providers/dynamodb/shared.go rename to internal/storage/db/dynamodb/shared.go diff --git a/server/db/providers/dynamodb/user.go b/internal/storage/db/dynamodb/user.go similarity index 70% rename from server/db/providers/dynamodb/user.go rename to internal/storage/db/dynamodb/user.go index faa5badb4..da517e4bf 100644 --- a/server/db/providers/dynamodb/user.go +++ b/internal/storage/db/dynamodb/user.go @@ -7,28 +7,22 @@ import ( "strings" "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/authorizerdev/authorizer/server/refs" "github.com/google/uuid" "github.com/guregu/dynamo" - log "github.com/sirupsen/logrus" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { - collection := p.db.Table(models.Collections.User) +func (p *provider) AddUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { + collection := p.db.Table(schemas.Collections.User) if user.ID == "" { user.ID = uuid.New().String() } if user.Roles == "" { - defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - return nil, err - } - user.Roles = defaultRoles + user.Roles = strings.Join(p.config.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 { @@ -49,8 +43,8 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User } // UpdateUser to update user information in database -func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) { - collection := p.db.Table(models.Collections.User) +func (p *provider) UpdateUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { + collection := p.db.Table(schemas.Collections.User) if user.ID != "" { user.UpdatedAt = time.Now().Unix() err := UpdateByHashKey(collection, "id", user.ID, user) @@ -62,9 +56,9 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { - collection := p.db.Table(models.Collections.User) - sessionCollection := p.db.Table(models.Collections.Session) +func (p *provider) DeleteUser(ctx context.Context, user *schemas.User) error { + collection := p.db.Table(schemas.Collections.User) + sessionCollection := p.db.Table(schemas.Collections.Session) if user.ID != "" { err := collection.Delete("id", user.ID).Run() if err != nil { @@ -79,24 +73,24 @@ func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { - var user *models.User +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) ([]*schemas.User, *model.Pagination, error) { + var user *schemas.User var lastEval dynamo.PagingKey var iter dynamo.PagingIter var iteration int64 = 0 - collection := p.db.Table(models.Collections.User) - users := []*model.User{} + collection := p.db.Table(schemas.Collections.User) + var users []*schemas.User paginationClone := pagination scanner := collection.Scan() count, err := scanner.Count() if err != nil { - return nil, err + return nil, nil, err } for (paginationClone.Offset + paginationClone.Limit) > iteration { iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter() for iter.NextWithContext(ctx, &user) { if paginationClone.Offset == iteration { - users = append(users, user.AsAPIUser()) + users = append(users, user) } } lastEval = iter.LastEvaluatedKey() @@ -104,20 +98,17 @@ func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) } err = iter.Err() if err != nil { - return nil, err + return nil, nil, err } paginationClone.Total = count - return &model.Users{ - Pagination: paginationClone, - Users: users, - }, nil + return users, paginationClone, nil } // GetUserByEmail to get user information from database using email address -func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) { - var users []*models.User - var user *models.User - collection := p.db.Table(models.Collections.User) +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*schemas.User, error) { + var users []*schemas.User + var user *schemas.User + collection := p.db.Table(schemas.Collections.User) err := collection.Scan().Index("email").Filter("'email' = ?", email).AllWithContext(ctx, &users) if err != nil { return user, nil @@ -131,9 +122,9 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us } // GetUserByID to get user information from database using user ID -func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) { - collection := p.db.Table(models.Collections.User) - var user *models.User +func (p *provider) GetUserByID(ctx context.Context, id string) (*schemas.User, error) { + collection := p.db.Table(schemas.Collections.User) + var user *schemas.User err := collection.Get("id", id).OneWithContext(ctx, &user) if err != nil { if refs.StringValue(user.Email) == "" { @@ -149,8 +140,8 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er // 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 - userCollection := p.db.Table(models.Collections.User) - var allUsers []models.User + userCollection := p.db.Table(schemas.Collections.User) + var allUsers []schemas.User var res int64 = 0 var err error if len(ids) > 0 { @@ -170,16 +161,16 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, if err != nil { return err } else { - log.Info("Updated users: ", res) + p.dependencies.Log.Info().Int64("modified_count", res).Msg("users updated") } 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) +func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.User, error) { + var users []*schemas.User + var user *schemas.User + collection := p.db.Table(schemas.Collections.User) err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).AllWithContext(ctx, &users) if err != nil { return nil, err diff --git a/server/db/providers/dynamodb/verification_requests.go b/internal/storage/db/dynamodb/verification_requests.go similarity index 67% rename from server/db/providers/dynamodb/verification_requests.go rename to internal/storage/db/dynamodb/verification_requests.go index 32bceb28d..c44dd52e6 100644 --- a/server/db/providers/dynamodb/verification_requests.go +++ b/internal/storage/db/dynamodb/verification_requests.go @@ -4,15 +4,16 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" "github.com/guregu/dynamo" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { - collection := p.db.Table(models.Collections.VerificationRequest) +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) (*schemas.VerificationRequest, error) { + collection := p.db.Table(schemas.Collections.VerificationRequest) if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() verificationRequest.CreatedAt = time.Now().Unix() @@ -26,9 +27,9 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { - collection := p.db.Table(models.Collections.VerificationRequest) - var verificationRequest *models.VerificationRequest +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*schemas.VerificationRequest, error) { + collection := p.db.Table(schemas.Collections.VerificationRequest) + var verificationRequest *schemas.VerificationRequest iter := collection.Scan().Filter("'token' = ?", token).Iter() for iter.NextWithContext(ctx, &verificationRequest) { return verificationRequest, nil @@ -41,9 +42,9 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { - var verificationRequest *models.VerificationRequest - collection := p.db.Table(models.Collections.VerificationRequest) +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*schemas.VerificationRequest, error) { + var verificationRequest *schemas.VerificationRequest + collection := p.db.Table(schemas.Collections.VerificationRequest) iter := collection.Scan().Filter("'email' = ?", email).Filter("'identifier' = ?", identifier).Iter() for iter.NextWithContext(ctx, &verificationRequest) { return verificationRequest, nil @@ -56,43 +57,40 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { - verificationRequests := []*model.VerificationRequest{} - var verificationRequest *models.VerificationRequest +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) ([]*schemas.VerificationRequest, *model.Pagination, error) { + var verificationRequests []*schemas.VerificationRequest + var verificationRequest *schemas.VerificationRequest var lastEval dynamo.PagingKey var iter dynamo.PagingIter var iteration int64 = 0 - collection := p.db.Table(models.Collections.VerificationRequest) + collection := p.db.Table(schemas.Collections.VerificationRequest) paginationClone := pagination scanner := collection.Scan() count, err := scanner.Count() if err != nil { - return nil, err + return nil, nil, err } for (paginationClone.Offset + paginationClone.Limit) > iteration { iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter() for iter.NextWithContext(ctx, &verificationRequest) { if paginationClone.Offset == iteration { - verificationRequests = append(verificationRequests, verificationRequest.AsAPIVerificationRequest()) + verificationRequests = append(verificationRequests, verificationRequest) } } err = iter.Err() if err != nil { - return nil, err + return nil, nil, err } lastEval = iter.LastEvaluatedKey() iteration += paginationClone.Limit } paginationClone.Total = count - return &model.VerificationRequests{ - VerificationRequests: verificationRequests, - Pagination: paginationClone, - }, nil + return verificationRequests, paginationClone, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { - collection := p.db.Table(models.Collections.VerificationRequest) +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) error { + collection := p.db.Table(schemas.Collections.VerificationRequest) if verificationRequest != nil { err := collection.Delete("id", verificationRequest.ID).RunWithContext(ctx) diff --git a/server/db/providers/dynamodb/webhook.go b/internal/storage/db/dynamodb/webhook.go similarity index 56% rename from server/db/providers/dynamodb/webhook.go rename to internal/storage/db/dynamodb/webhook.go index ca47b71d3..e85ef9640 100644 --- a/server/db/providers/dynamodb/webhook.go +++ b/internal/storage/db/dynamodb/webhook.go @@ -10,13 +10,13 @@ import ( "github.com/google/uuid" "github.com/guregu/dynamo" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddWebhook to add webhook -func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) { - collection := p.db.Table(models.Collections.Webhook) +func (p *provider) AddWebhook(ctx context.Context, webhook *schemas.Webhook) (*schemas.Webhook, error) { + collection := p.db.Table(schemas.Collections.Webhook) if webhook.ID == "" { webhook.ID = uuid.New().String() } @@ -29,109 +29,104 @@ func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*mo if err != nil { return nil, err } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // 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 *schemas.Webhook) (*schemas.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()) } - collection := p.db.Table(models.Collections.Webhook) + collection := p.db.Table(schemas.Collections.Webhook) err := UpdateByHashKey(collection, "id", webhook.ID, webhook) if err != nil { return nil, err } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { - webhooks := []*model.Webhook{} - var webhook *models.Webhook +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) ([]*schemas.Webhook, *model.Pagination, error) { + webhooks := []*schemas.Webhook{} + var webhook *schemas.Webhook var lastEval dynamo.PagingKey var iter dynamo.PagingIter var iteration int64 = 0 - collection := p.db.Table(models.Collections.Webhook) + collection := p.db.Table(schemas.Collections.Webhook) paginationClone := pagination scanner := collection.Scan() count, err := scanner.Count() if err != nil { - return nil, err + return nil, nil, err } for (paginationClone.Offset + paginationClone.Limit) > iteration { iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter() for iter.NextWithContext(ctx, &webhook) { if paginationClone.Offset == iteration { - webhooks = append(webhooks, webhook.AsAPIWebhook()) + webhooks = append(webhooks, webhook) } } err = iter.Err() if err != nil { - return nil, err + return nil, nil, err } lastEval = iter.LastEvaluatedKey() iteration += paginationClone.Limit } paginationClone.Total = count - return &model.Webhooks{ - Pagination: paginationClone, - Webhooks: webhooks, - }, nil + return webhooks, paginationClone, nil } // GetWebhookByID to get webhook by id -func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) { - collection := p.db.Table(models.Collections.Webhook) - var webhook *models.Webhook +func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*schemas.Webhook, error) { + collection := p.db.Table(schemas.Collections.Webhook) + var webhook *schemas.Webhook err := collection.Get("id", webhookID).OneWithContext(ctx, &webhook) if err != nil { return nil, err } if webhook.ID == "" { - return nil, errors.New("no documets found") + return nil, errors.New("no document found") } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // GetWebhookByEventName to get webhook by event_name -func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*model.Webhook, error) { - webhooks := []models.Webhook{} - collection := p.db.Table(models.Collections.Webhook) +func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*schemas.Webhook, error) { + webhooks := []*schemas.Webhook{} + collection := p.db.Table(schemas.Collections.Webhook) err := collection.Scan().Index("event_name").Filter("contains(event_name, ?)", eventName).AllWithContext(ctx, &webhooks) if err != nil { return nil, err } - resWebhooks := []*model.Webhook{} - for _, w := range webhooks { - resWebhooks = append(resWebhooks, w.AsAPIWebhook()) - } - return resWebhooks, nil + return webhooks, nil } // DeleteWebhook to delete webhook -func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error { +func (p *provider) DeleteWebhook(ctx context.Context, webhook *schemas.Webhook) error { // Also delete webhook logs for given webhook id if webhook != nil { - webhookCollection := p.db.Table(models.Collections.Webhook) - webhookLogCollection := p.db.Table(models.Collections.WebhookLog) + webhookCollection := p.db.Table(schemas.Collections.Webhook) + webhookLogCollection := p.db.Table(schemas.Collections.WebhookLog) err := webhookCollection.Delete("id", webhook.ID).RunWithContext(ctx) if err != nil { return err } pagination := &model.Pagination{} - webhookLogs, errIs := p.ListWebhookLogs(ctx, pagination, webhook.ID) - for _, webhookLog := range webhookLogs.WebhookLogs { - err = webhookLogCollection.Delete("id", webhookLog.ID).RunWithContext(ctx) - if err != nil { - return err + webhookLogs, _, err := p.ListWebhookLogs(ctx, pagination, webhook.ID) + if err != nil { + p.dependencies.Log.Debug().Err(err).Msg("failed to list webhook logs") + } else { + for _, webhookLog := range webhookLogs { + err = webhookLogCollection.Delete("id", webhookLog.ID).RunWithContext(ctx) + if err != nil { + p.dependencies.Log.Debug().Err(err).Msg("failed to delete webhook log") + // continue + } } } - if errIs != nil { - return errIs - } } return nil } diff --git a/server/db/providers/dynamodb/webhook_log.go b/internal/storage/db/dynamodb/webhook_log.go similarity index 66% rename from server/db/providers/dynamodb/webhook_log.go rename to internal/storage/db/dynamodb/webhook_log.go index 18ba2613d..2092b1d18 100644 --- a/server/db/providers/dynamodb/webhook_log.go +++ b/internal/storage/db/dynamodb/webhook_log.go @@ -4,15 +4,16 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" "github.com/guregu/dynamo" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { - collection := p.db.Table(models.Collections.WebhookLog) +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *schemas.WebhookLog) (*schemas.WebhookLog, error) { + collection := p.db.Table(schemas.Collections.WebhookLog) if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } @@ -23,42 +24,42 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.Webhook if err != nil { return nil, err } - return webhookLog.AsAPIWebhookLog(), nil + return webhookLog, nil } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { - webhookLogs := []*model.WebhookLog{} - var webhookLog *models.WebhookLog +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) ([]*schemas.WebhookLog, *model.Pagination, error) { + webhookLogs := []*schemas.WebhookLog{} + var webhookLog *schemas.WebhookLog var lastEval dynamo.PagingKey var iter dynamo.PagingIter var iteration int64 = 0 var err error var count int64 - collection := p.db.Table(models.Collections.WebhookLog) + collection := p.db.Table(schemas.Collections.WebhookLog) paginationClone := pagination scanner := collection.Scan() if webhookID != "" { iter = scanner.Index("webhook_id").Filter("'webhook_id' = ?", webhookID).Iter() for iter.NextWithContext(ctx, &webhookLog) { - webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog()) + webhookLogs = append(webhookLogs, webhookLog) } err = iter.Err() if err != nil { - return nil, err + return nil, nil, err } } else { for (paginationClone.Offset + paginationClone.Limit) > iteration { iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter() for iter.NextWithContext(ctx, &webhookLog) { if paginationClone.Offset == iteration { - webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog()) + webhookLogs = append(webhookLogs, webhookLog) } } err = iter.Err() if err != nil { - return nil, err + return nil, nil, err } lastEval = iter.LastEvaluatedKey() iteration += paginationClone.Limit @@ -66,8 +67,5 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagina } paginationClone.Total = count // paginationClone.Cursor = iter.LastEvaluatedKey() - return &model.WebhookLogs{ - Pagination: paginationClone, - WebhookLogs: webhookLogs, - }, nil + return webhookLogs, paginationClone, nil } diff --git a/server/db/providers/mongodb/authenticator.go b/internal/storage/db/mongodb/authenticator.go similarity index 66% rename from server/db/providers/mongodb/authenticator.go rename to internal/storage/db/mongodb/authenticator.go index 7dae455b0..edb1c4cb1 100644 --- a/server/db/providers/mongodb/authenticator.go +++ b/internal/storage/db/mongodb/authenticator.go @@ -8,10 +8,10 @@ import ( "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" - "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) -func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) AddAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method) if exists != nil { return authenticators, nil @@ -23,7 +23,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models. authenticators.CreatedAt = time.Now().Unix() authenticators.UpdatedAt = time.Now().Unix() authenticators.Key = authenticators.ID - authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection()) + authenticatorsCollection := p.db.Collection(schemas.Collections.Authenticators, options.Collection()) _, err := authenticatorsCollection.InsertOne(ctx, authenticators) if err != nil { return nil, err @@ -31,9 +31,9 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models. return authenticators, nil } -func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { authenticators.UpdatedAt = time.Now().Unix() - authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection()) + authenticatorsCollection := p.db.Collection(schemas.Collections.Authenticators, options.Collection()) _, err := authenticatorsCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": authenticators.ID}}, bson.M{"$set": authenticators}) if err != nil { return nil, err @@ -41,9 +41,9 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode return authenticators, nil } -func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) { - var authenticators *models.Authenticator - authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection()) +func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*schemas.Authenticator, error) { + var authenticators *schemas.Authenticator + authenticatorsCollection := p.db.Collection(schemas.Collections.Authenticators, options.Collection()) err := authenticatorsCollection.FindOne(ctx, bson.M{"user_id": userId, "method": authenticatorType}).Decode(&authenticators) if err != nil { return nil, err diff --git a/server/db/providers/mongodb/email_template.go b/internal/storage/db/mongodb/email_template.go similarity index 56% rename from server/db/providers/mongodb/email_template.go rename to internal/storage/db/mongodb/email_template.go index c3fa31b01..ed4b3a1b0 100644 --- a/server/db/providers/mongodb/email_template.go +++ b/internal/storage/db/mongodb/email_template.go @@ -4,99 +4,97 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() } emailTemplate.Key = emailTemplate.ID emailTemplate.CreatedAt = time.Now().Unix() emailTemplate.UpdatedAt = time.Now().Unix() - emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection()) + emailTemplateCollection := p.db.Collection(schemas.Collections.EmailTemplate, options.Collection()) _, err := emailTemplateCollection.InsertOne(ctx, emailTemplate) if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { emailTemplate.UpdatedAt = time.Now().Unix() - emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection()) + emailTemplateCollection := p.db.Collection(schemas.Collections.EmailTemplate, options.Collection()) _, err := emailTemplateCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": emailTemplate.ID}}, bson.M{"$set": emailTemplate}, options.MergeUpdateOptions()) if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { - var emailTemplates []*model.EmailTemplate +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) ([]*schemas.EmailTemplate, *model.Pagination, error) { + var emailTemplates []*schemas.EmailTemplate opts := options.Find() opts.SetLimit(pagination.Limit) opts.SetSkip(pagination.Offset) opts.SetSort(bson.M{"created_at": -1}) paginationClone := pagination - emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection()) + emailTemplateCollection := p.db.Collection(schemas.Collections.EmailTemplate, options.Collection()) count, err := emailTemplateCollection.CountDocuments(ctx, bson.M{}, options.Count()) if err != nil { - return nil, err + return nil, nil, err } paginationClone.Total = count cursor, err := emailTemplateCollection.Find(ctx, bson.M{}, opts) if err != nil { - return nil, err + return nil, nil, err } defer cursor.Close(ctx) for cursor.Next(ctx) { - var emailTemplate *models.EmailTemplate + var emailTemplate *schemas.EmailTemplate err := cursor.Decode(&emailTemplate) if err != nil { - return nil, err + return nil, nil, err } - emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate()) + emailTemplates = append(emailTemplates, emailTemplate) } - return &model.EmailTemplates{ - Pagination: paginationClone, - EmailTemplates: emailTemplates, - }, nil + return emailTemplates, paginationClone, nil } // GetEmailTemplateByID to get EmailTemplate by id -func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { - var emailTemplate *models.EmailTemplate - emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection()) +func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*schemas.EmailTemplate, error) { + var emailTemplate *schemas.EmailTemplate + emailTemplateCollection := p.db.Collection(schemas.Collections.EmailTemplate, options.Collection()) err := emailTemplateCollection.FindOne(ctx, bson.M{"_id": emailTemplateID}).Decode(&emailTemplate) if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // GetEmailTemplateByEventName to get EmailTemplate by event_name -func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { - var emailTemplate *models.EmailTemplate - emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection()) +func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*schemas.EmailTemplate, error) { + var emailTemplate *schemas.EmailTemplate + emailTemplateCollection := p.db.Collection(schemas.Collections.EmailTemplate, options.Collection()) err := emailTemplateCollection.FindOne(ctx, bson.M{"event_name": eventName}).Decode(&emailTemplate) if err != nil { return nil, err } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // DeleteEmailTemplate to delete EmailTemplate -func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error { - emailTemplateCollection := p.db.Collection(models.Collections.EmailTemplate, options.Collection()) - _, err := emailTemplateCollection.DeleteOne(nil, bson.M{"_id": emailTemplate.ID}, options.Delete()) +func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) error { + emailTemplateCollection := p.db.Collection(schemas.Collections.EmailTemplate, options.Collection()) + _, err := emailTemplateCollection.DeleteOne(ctx, bson.M{"_id": emailTemplate.ID}, options.Delete()) if err != nil { return err } diff --git a/server/db/providers/mongodb/env.go b/internal/storage/db/mongodb/env.go similarity index 63% rename from server/db/providers/mongodb/env.go rename to internal/storage/db/mongodb/env.go index f88163a5e..d07a6ff67 100644 --- a/server/db/providers/mongodb/env.go +++ b/internal/storage/db/mongodb/env.go @@ -5,21 +5,22 @@ import ( "fmt" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *schemas.Env) (*schemas.Env, error) { if env.ID == "" { env.ID = uuid.New().String() } env.CreatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix() env.Key = env.ID - configCollection := p.db.Collection(models.Collections.Env, options.Collection()) + configCollection := p.db.Collection(schemas.Collections.Env, options.Collection()) _, err := configCollection.InsertOne(ctx, env) if err != nil { return nil, err @@ -28,9 +29,9 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er } // 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 *schemas.Env) (*schemas.Env, error) { env.UpdatedAt = time.Now().Unix() - configCollection := p.db.Collection(models.Collections.Env, options.Collection()) + configCollection := p.db.Collection(schemas.Collections.Env, options.Collection()) _, err := configCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions()) if err != nil { return nil, err @@ -39,15 +40,15 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { - var env *models.Env - configCollection := p.db.Collection(models.Collections.Env, options.Collection()) +func (p *provider) GetEnv(ctx context.Context) (*schemas.Env, error) { + var env *schemas.Env + configCollection := p.db.Collection(schemas.Collections.Env, options.Collection()) cursor, err := configCollection.Find(ctx, bson.M{}, options.Find()) if err != nil { return nil, err } defer cursor.Close(ctx) - for cursor.Next(nil) { + for cursor.Next(ctx) { err := cursor.Decode(&env) if err != nil { return nil, err diff --git a/server/db/providers/mongodb/otp.go b/internal/storage/db/mongodb/otp.go similarity index 66% rename from server/db/providers/mongodb/otp.go rename to internal/storage/db/mongodb/otp.go index d70818d18..9f7684392 100644 --- a/server/db/providers/mongodb/otp.go +++ b/internal/storage/db/mongodb/otp.go @@ -5,24 +5,25 @@ import ( "errors" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // UpsertOTP to add or update otp -func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { +func (p *provider) UpsertOTP(ctx context.Context, otpParam *schemas.OTP) (*schemas.OTP, error) { // check if email or phone number is present if otpParam.Email == "" && otpParam.PhoneNumber == "" { return nil, errors.New("email or phone_number is required") } - uniqueField := models.FieldNameEmail + uniqueField := schemas.FieldNameEmail if otpParam.Email == "" && otpParam.PhoneNumber != "" { - uniqueField = models.FieldNamePhoneNumber + uniqueField = schemas.FieldNamePhoneNumber } - var otp *models.OTP - if uniqueField == models.FieldNameEmail { + var otp *schemas.OTP + if uniqueField == schemas.FieldNameEmail { otp, _ = p.GetOTPByEmail(ctx, otpParam.Email) } else { otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber) @@ -30,7 +31,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models shouldCreate := false if otp == nil { id := uuid.NewString() - otp = &models.OTP{ + otp = &schemas.OTP{ ID: id, Key: id, Otp: otpParam.Otp, @@ -45,7 +46,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models otp.ExpiresAt = otpParam.ExpiresAt } otp.UpdatedAt = time.Now().Unix() - otpCollection := p.db.Collection(models.Collections.OTP, options.Collection()) + otpCollection := p.db.Collection(schemas.Collections.OTP, options.Collection()) var err error if shouldCreate { @@ -60,9 +61,9 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models } // GetOTPByEmail to get otp for a given email address -func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { - var otp models.OTP - otpCollection := p.db.Collection(models.Collections.OTP, options.Collection()) +func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*schemas.OTP, error) { + var otp schemas.OTP + otpCollection := p.db.Collection(schemas.Collections.OTP, options.Collection()) err := otpCollection.FindOne(ctx, bson.M{"email": emailAddress}).Decode(&otp) if err != nil { return nil, err @@ -71,9 +72,9 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod } // GetOTPByPhoneNumber to get otp for a given phone number -func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { - var otp models.OTP - otpCollection := p.db.Collection(models.Collections.OTP, options.Collection()) +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.OTP, error) { + var otp schemas.OTP + otpCollection := p.db.Collection(schemas.Collections.OTP, options.Collection()) err := otpCollection.FindOne(ctx, bson.M{"phone_number": phoneNumber}).Decode(&otp) if err != nil { return nil, err @@ -82,9 +83,9 @@ func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) } // DeleteOTP to delete otp -func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { - otpCollection := p.db.Collection(models.Collections.OTP, options.Collection()) - _, err := otpCollection.DeleteOne(nil, bson.M{"_id": otp.ID}, options.Delete()) +func (p *provider) DeleteOTP(ctx context.Context, otp *schemas.OTP) error { + otpCollection := p.db.Collection(schemas.Collections.OTP, options.Collection()) + _, err := otpCollection.DeleteOne(ctx, bson.M{"_id": otp.ID}, options.Delete()) if err != nil { return err } diff --git a/server/db/providers/mongodb/provider.go b/internal/storage/db/mongodb/provider.go similarity index 56% rename from server/db/providers/mongodb/provider.go rename to internal/storage/db/mongodb/provider.go index 1f174e3dd..9a5144656 100644 --- a/server/db/providers/mongodb/provider.go +++ b/internal/storage/db/mongodb/provider.go @@ -2,32 +2,38 @@ package mongodb import ( "context" + "fmt" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/rs/zerolog" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/readpref" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) +// Dependencies struct the mongodb data store provider +type Dependencies struct { + Log *zerolog.Logger +} + type provider struct { - db *mongo.Database + config *config.Config + dependencies *Dependencies + db *mongo.Database } // NewProvider to initialize mongodb connection -func NewProvider() (*provider, error) { - dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL +func NewProvider(config *config.Config, deps *Dependencies) (*provider, error) { + dbURL := config.DatabaseURL mongodbOptions := options.Client().ApplyURI(dbURL) maxWait := time.Duration(5 * time.Second) mongodbOptions.ConnectTimeout = &maxWait - mongoClient, err := mongo.NewClient(mongodbOptions) - if err != nil { - return nil, err - } ctx, _ := context.WithTimeout(context.Background(), 30*time.Second) - err = mongoClient.Connect(ctx) + mongoClient, err := mongo.Connect(ctx, mongodbOptions) if err != nil { return nil, err } @@ -37,11 +43,14 @@ func NewProvider() (*provider, error) { return nil, err } - dbName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName + dbName := config.DatabaseName + if dbName == "" { + return nil, fmt.Errorf("database name is required for mongodb") + } mongodb := mongoClient.Database(dbName, options.Database()) - mongodb.CreateCollection(ctx, models.Collections.User, options.CreateCollection()) - userCollection := mongodb.Collection(models.Collections.User, options.Collection()) + mongodb.CreateCollection(ctx, schemas.Collections.User, options.CreateCollection()) + userCollection := mongodb.Collection(schemas.Collections.User, options.Collection()) userCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ { Keys: bson.M{"email": 1}, @@ -54,8 +63,8 @@ func NewProvider() (*provider, error) { }), }, }, options.CreateIndexes()) - mongodb.CreateCollection(ctx, models.Collections.VerificationRequest, options.CreateCollection()) - verificationRequestCollection := mongodb.Collection(models.Collections.VerificationRequest, options.Collection()) + mongodb.CreateCollection(ctx, schemas.Collections.VerificationRequest, options.CreateCollection()) + verificationRequestCollection := mongodb.Collection(schemas.Collections.VerificationRequest, options.Collection()) verificationRequestCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ { Keys: bson.M{"email": 1, "identifier": 1}, @@ -69,8 +78,8 @@ func NewProvider() (*provider, error) { }, }, options.CreateIndexes()) - mongodb.CreateCollection(ctx, models.Collections.Session, options.CreateCollection()) - sessionCollection := mongodb.Collection(models.Collections.Session, options.Collection()) + mongodb.CreateCollection(ctx, schemas.Collections.Session, options.CreateCollection()) + sessionCollection := mongodb.Collection(schemas.Collections.Session, options.Collection()) sessionCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ { Keys: bson.M{"user_id": 1}, @@ -78,10 +87,10 @@ func NewProvider() (*provider, error) { }, }, options.CreateIndexes()) - mongodb.CreateCollection(ctx, models.Collections.Env, options.CreateCollection()) + mongodb.CreateCollection(ctx, schemas.Collections.Env, options.CreateCollection()) - mongodb.CreateCollection(ctx, models.Collections.Webhook, options.CreateCollection()) - webhookCollection := mongodb.Collection(models.Collections.Webhook, options.Collection()) + mongodb.CreateCollection(ctx, schemas.Collections.Webhook, options.CreateCollection()) + webhookCollection := mongodb.Collection(schemas.Collections.Webhook, options.Collection()) webhookCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ { Keys: bson.M{"event_name": 1}, @@ -89,8 +98,8 @@ func NewProvider() (*provider, error) { }, }, options.CreateIndexes()) - mongodb.CreateCollection(ctx, models.Collections.WebhookLog, options.CreateCollection()) - webhookLogCollection := mongodb.Collection(models.Collections.WebhookLog, options.Collection()) + mongodb.CreateCollection(ctx, schemas.Collections.WebhookLog, options.CreateCollection()) + webhookLogCollection := mongodb.Collection(schemas.Collections.WebhookLog, options.Collection()) webhookLogCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ { Keys: bson.M{"webhook_id": 1}, @@ -98,8 +107,8 @@ func NewProvider() (*provider, error) { }, }, options.CreateIndexes()) - mongodb.CreateCollection(ctx, models.Collections.EmailTemplate, options.CreateCollection()) - emailTemplateCollection := mongodb.Collection(models.Collections.EmailTemplate, options.Collection()) + mongodb.CreateCollection(ctx, schemas.Collections.EmailTemplate, options.CreateCollection()) + emailTemplateCollection := mongodb.Collection(schemas.Collections.EmailTemplate, options.Collection()) emailTemplateCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ { Keys: bson.M{"event_name": 1}, @@ -107,8 +116,8 @@ func NewProvider() (*provider, error) { }, }, options.CreateIndexes()) - mongodb.CreateCollection(ctx, models.Collections.OTP, options.CreateCollection()) - otpCollection := mongodb.Collection(models.Collections.OTP, options.Collection()) + mongodb.CreateCollection(ctx, schemas.Collections.OTP, options.CreateCollection()) + otpCollection := mongodb.Collection(schemas.Collections.OTP, options.Collection()) otpCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ { Keys: bson.M{"email": 1}, @@ -122,8 +131,8 @@ func NewProvider() (*provider, error) { }, }, options.CreateIndexes()) - mongodb.CreateCollection(ctx, models.Collections.Authenticators, options.CreateCollection()) - authenticatorsCollection := mongodb.Collection(models.Collections.Authenticators, options.Collection()) + mongodb.CreateCollection(ctx, schemas.Collections.Authenticators, options.CreateCollection()) + authenticatorsCollection := mongodb.Collection(schemas.Collections.Authenticators, options.Collection()) authenticatorsCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ { Keys: bson.M{"user_id": 1}, @@ -132,6 +141,8 @@ func NewProvider() (*provider, error) { }, options.CreateIndexes()) return &provider{ - db: mongodb, + config: config, + dependencies: deps, + db: mongodb, }, nil } diff --git a/server/db/providers/mongodb/session.go b/internal/storage/db/mongodb/session.go similarity index 71% rename from server/db/providers/mongodb/session.go rename to internal/storage/db/mongodb/session.go index 860eeefb3..395187fd0 100644 --- a/server/db/providers/mongodb/session.go +++ b/internal/storage/db/mongodb/session.go @@ -4,13 +4,14 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session *models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *schemas.Session) error { if session.ID == "" { session.ID = uuid.New().String() } @@ -18,7 +19,7 @@ func (p *provider) AddSession(ctx context.Context, session *models.Session) erro session.Key = session.ID session.CreatedAt = time.Now().Unix() session.UpdatedAt = time.Now().Unix() - sessionCollection := p.db.Collection(models.Collections.Session, options.Collection()) + sessionCollection := p.db.Collection(schemas.Collections.Session, options.Collection()) _, err := sessionCollection.InsertOne(ctx, session) if err != nil { return err diff --git a/server/db/providers/mongodb/user.go b/internal/storage/db/mongodb/user.go similarity index 65% rename from server/db/providers/mongodb/user.go rename to internal/storage/db/mongodb/user.go index 776c4fc97..cfaa27f22 100644 --- a/server/db/providers/mongodb/user.go +++ b/internal/storage/db/mongodb/user.go @@ -6,29 +6,23 @@ import ( "strings" "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/authorizerdev/authorizer/server/refs" "github.com/google/uuid" - log "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { if user.ID == "" { user.ID = uuid.New().String() } if user.Roles == "" { - defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - return nil, err - } - user.Roles = defaultRoles + user.Roles = strings.Join(p.config.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 { @@ -42,7 +36,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User user.CreatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix() user.Key = user.ID - userCollection := p.db.Collection(models.Collections.User, options.Collection()) + userCollection := p.db.Collection(schemas.Collections.User, options.Collection()) _, err := userCollection.InsertOne(ctx, user) if err != nil { return nil, err @@ -51,9 +45,9 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User } // UpdateUser to update user information in database -func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) UpdateUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { user.UpdatedAt = time.Now().Unix() - userCollection := p.db.Collection(models.Collections.User, options.Collection()) + userCollection := p.db.Collection(schemas.Collections.User, options.Collection()) _, err := userCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions()) if err != nil { return nil, err @@ -62,13 +56,13 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { - userCollection := p.db.Collection(models.Collections.User, options.Collection()) +func (p *provider) DeleteUser(ctx context.Context, user *schemas.User) error { + userCollection := p.db.Collection(schemas.Collections.User, options.Collection()) _, err := userCollection.DeleteOne(ctx, bson.M{"_id": user.ID}, options.Delete()) if err != nil { return err } - sessionCollection := p.db.Collection(models.Collections.Session, options.Collection()) + sessionCollection := p.db.Collection(schemas.Collections.Session, options.Collection()) _, err = sessionCollection.DeleteMany(ctx, bson.M{"user_id": user.ID}, options.Delete()) if err != nil { return err @@ -77,42 +71,39 @@ func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { - var users []*model.User +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) ([]*schemas.User, *model.Pagination, error) { + var users []*schemas.User opts := options.Find() opts.SetLimit(pagination.Limit) opts.SetSkip(pagination.Offset) opts.SetSort(bson.M{"created_at": -1}) paginationClone := pagination - userCollection := p.db.Collection(models.Collections.User, options.Collection()) + userCollection := p.db.Collection(schemas.Collections.User, options.Collection()) count, err := userCollection.CountDocuments(ctx, bson.M{}, options.Count()) if err != nil { - return nil, err + return nil, nil, err } paginationClone.Total = count cursor, err := userCollection.Find(ctx, bson.M{}, opts) if err != nil { - return nil, err + return nil, nil, err } defer cursor.Close(ctx) for cursor.Next(ctx) { - var user *models.User + var user *schemas.User err := cursor.Decode(&user) if err != nil { - return nil, err + return nil, nil, err } - users = append(users, user.AsAPIUser()) + users = append(users, user) } - return &model.Users{ - Pagination: paginationClone, - Users: users, - }, nil + return users, paginationClone, 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 - userCollection := p.db.Collection(models.Collections.User, options.Collection()) +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*schemas.User, error) { + var user *schemas.User + userCollection := p.db.Collection(schemas.Collections.User, options.Collection()) err := userCollection.FindOne(ctx, bson.M{"email": email}).Decode(&user) if err != nil { return nil, err @@ -121,9 +112,9 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us } // 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 - userCollection := p.db.Collection(models.Collections.User, options.Collection()) +func (p *provider) GetUserByID(ctx context.Context, id string) (*schemas.User, error) { + var user *schemas.User + userCollection := p.db.Collection(schemas.Collections.User, options.Collection()) err := userCollection.FindOne(ctx, bson.M{"_id": id}).Decode(&user) if err != nil { return nil, err @@ -136,7 +127,7 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error { // set updated_at time for all users data["updated_at"] = time.Now().Unix() - userCollection := p.db.Collection(models.Collections.User, options.Collection()) + userCollection := p.db.Collection(schemas.Collections.User, options.Collection()) var res *mongo.UpdateResult var err error if len(ids) > 0 { @@ -147,15 +138,15 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, if err != nil { return err } else { - log.Info("Updated users: ", res.ModifiedCount) + p.dependencies.Log.Info().Int64("modified_count", res.ModifiedCount).Msg("users updated") } 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()) +func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.User, error) { + var user *schemas.User + userCollection := p.db.Collection(schemas.Collections.User, options.Collection()) err := userCollection.FindOne(ctx, bson.M{"phone_number": phoneNumber}).Decode(&user) if err != nil { return nil, err diff --git a/server/db/providers/mongodb/verification_requests.go b/internal/storage/db/mongodb/verification_requests.go similarity index 63% rename from server/db/providers/mongodb/verification_requests.go rename to internal/storage/db/mongodb/verification_requests.go index a4088f1eb..49020dad3 100644 --- a/server/db/providers/mongodb/verification_requests.go +++ b/internal/storage/db/mongodb/verification_requests.go @@ -4,22 +4,23 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) (*schemas.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() verificationRequest.CreatedAt = time.Now().Unix() verificationRequest.UpdatedAt = time.Now().Unix() verificationRequest.Key = verificationRequest.ID - verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) + verificationRequestCollection := p.db.Collection(schemas.Collections.VerificationRequest, options.Collection()) _, err := verificationRequestCollection.InsertOne(ctx, verificationRequest) if err != nil { return nil, err @@ -30,10 +31,10 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { - var verificationRequest *models.VerificationRequest +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*schemas.VerificationRequest, error) { + var verificationRequest *schemas.VerificationRequest - verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) + verificationRequestCollection := p.db.Collection(schemas.Collections.VerificationRequest, options.Collection()) err := verificationRequestCollection.FindOne(ctx, bson.M{"token": token}).Decode(&verificationRequest) if err != nil { return nil, err @@ -43,10 +44,10 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { - var verificationRequest *models.VerificationRequest +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*schemas.VerificationRequest, error) { + var verificationRequest *schemas.VerificationRequest - verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) + verificationRequestCollection := p.db.Collection(schemas.Collections.VerificationRequest, options.Collection()) err := verificationRequestCollection.FindOne(ctx, bson.M{"email": email, "identifier": identifier}).Decode(&verificationRequest) if err != nil { return nil, err @@ -56,44 +57,43 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { - var verificationRequests []*model.VerificationRequest - +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) ([]*schemas.VerificationRequest, *model.Pagination, error) { + var verificationRequests []*schemas.VerificationRequest opts := options.Find() opts.SetLimit(pagination.Limit) opts.SetSkip(pagination.Offset) opts.SetSort(bson.M{"created_at": -1}) - verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) + verificationRequestCollection := p.db.Collection(schemas.Collections.VerificationRequest, options.Collection()) verificationRequestCollectionCount, err := verificationRequestCollection.CountDocuments(ctx, bson.M{}) + if err != nil { + return nil, nil, err + } paginationClone := pagination paginationClone.Total = verificationRequestCollectionCount cursor, err := verificationRequestCollection.Find(ctx, bson.M{}, opts) if err != nil { - return nil, err + return nil, nil, err } defer cursor.Close(ctx) for cursor.Next(ctx) { - var verificationRequest *models.VerificationRequest + var verificationRequest *schemas.VerificationRequest err := cursor.Decode(&verificationRequest) if err != nil { - return nil, err + return nil, nil, err } - verificationRequests = append(verificationRequests, verificationRequest.AsAPIVerificationRequest()) + verificationRequests = append(verificationRequests, verificationRequest) } - return &model.VerificationRequests{ - VerificationRequests: verificationRequests, - Pagination: paginationClone, - }, nil + return verificationRequests, paginationClone, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { - verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) error { + verificationRequestCollection := p.db.Collection(schemas.Collections.VerificationRequest, options.Collection()) _, err := verificationRequestCollection.DeleteOne(ctx, bson.M{"_id": verificationRequest.ID}, options.Delete()) if err != nil { return err diff --git a/server/db/providers/mongodb/webhook.go b/internal/storage/db/mongodb/webhook.go similarity index 58% rename from server/db/providers/mongodb/webhook.go rename to internal/storage/db/mongodb/webhook.go index ef6b3820b..cf606ae90 100644 --- a/server/db/providers/mongodb/webhook.go +++ b/internal/storage/db/mongodb/webhook.go @@ -6,15 +6,16 @@ import ( "strings" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // 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 *schemas.Webhook) (*schemas.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() } @@ -23,77 +24,74 @@ func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*mo 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(schemas.Collections.Webhook, options.Collection()) _, err := webhookCollection.InsertOne(ctx, webhook) if err != nil { return nil, err } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // 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 *schemas.Webhook) (*schemas.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()) } - webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection()) + webhookCollection := p.db.Collection(schemas.Collections.Webhook, options.Collection()) _, err := webhookCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": webhook.ID}}, bson.M{"$set": webhook}, options.MergeUpdateOptions()) if err != nil { return nil, err } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { - webhooks := []*model.Webhook{} +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) ([]*schemas.Webhook, *model.Pagination, error) { + webhooks := []*schemas.Webhook{} opts := options.Find() opts.SetLimit(pagination.Limit) opts.SetSkip(pagination.Offset) opts.SetSort(bson.M{"created_at": -1}) paginationClone := pagination - webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection()) + webhookCollection := p.db.Collection(schemas.Collections.Webhook, options.Collection()) count, err := webhookCollection.CountDocuments(ctx, bson.M{}, options.Count()) if err != nil { - return nil, err + return nil, nil, err } paginationClone.Total = count cursor, err := webhookCollection.Find(ctx, bson.M{}, opts) if err != nil { - return nil, err + return nil, nil, err } defer cursor.Close(ctx) for cursor.Next(ctx) { - var webhook *models.Webhook + var webhook *schemas.Webhook err := cursor.Decode(&webhook) if err != nil { - return nil, err + return nil, nil, err } - webhooks = append(webhooks, webhook.AsAPIWebhook()) + webhooks = append(webhooks, webhook) } - return &model.Webhooks{ - Pagination: paginationClone, - Webhooks: webhooks, - }, nil + return webhooks, paginationClone, nil } // GetWebhookByID to get webhook by id -func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) { - var webhook *models.Webhook - webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection()) +func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*schemas.Webhook, error) { + var webhook *schemas.Webhook + webhookCollection := p.db.Collection(schemas.Collections.Webhook, options.Collection()) err := webhookCollection.FindOne(ctx, bson.M{"_id": webhookID}).Decode(&webhook) if err != nil { return nil, err } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // GetWebhookByEventName to get webhook by event_name -func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*model.Webhook, error) { - webhooks := []*model.Webhook{} - webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection()) +func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*schemas.Webhook, error) { + webhooks := []*schemas.Webhook{} + webhookCollection := p.db.Collection(schemas.Collections.Webhook, options.Collection()) opts := options.Find() opts.SetSort(bson.M{"created_at": -1}) cursor, err := webhookCollection.Find(ctx, bson.M{"event_name": bson.M{ @@ -104,25 +102,25 @@ func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) } defer cursor.Close(ctx) for cursor.Next(ctx) { - var webhook *models.Webhook + var webhook *schemas.Webhook err := cursor.Decode(&webhook) if err != nil { return nil, err } - webhooks = append(webhooks, webhook.AsAPIWebhook()) + webhooks = append(webhooks, webhook) } return webhooks, nil } // DeleteWebhook to delete webhook -func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error { - webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection()) - _, err := webhookCollection.DeleteOne(nil, bson.M{"_id": webhook.ID}, options.Delete()) +func (p *provider) DeleteWebhook(ctx context.Context, webhook *schemas.Webhook) error { + webhookCollection := p.db.Collection(schemas.Collections.Webhook, options.Collection()) + _, err := webhookCollection.DeleteOne(ctx, bson.M{"_id": webhook.ID}, options.Delete()) if err != nil { return err } - webhookLogCollection := p.db.Collection(models.Collections.WebhookLog, options.Collection()) - _, err = webhookLogCollection.DeleteMany(nil, bson.M{"webhook_id": webhook.ID}, options.Delete()) + webhookLogCollection := p.db.Collection(schemas.Collections.WebhookLog, options.Collection()) + _, err = webhookLogCollection.DeleteMany(ctx, bson.M{"webhook_id": webhook.ID}, options.Delete()) if err != nil { return err } diff --git a/server/db/providers/mongodb/webhook_log.go b/internal/storage/db/mongodb/webhook_log.go similarity index 61% rename from server/db/providers/mongodb/webhook_log.go rename to internal/storage/db/mongodb/webhook_log.go index 0c464d8e3..49570f88a 100644 --- a/server/db/providers/mongodb/webhook_log.go +++ b/internal/storage/db/mongodb/webhook_log.go @@ -4,15 +4,15 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *schemas.WebhookLog) (*schemas.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } @@ -21,17 +21,17 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.Webhook webhookLog.CreatedAt = time.Now().Unix() webhookLog.UpdatedAt = time.Now().Unix() - webhookLogCollection := p.db.Collection(models.Collections.WebhookLog, options.Collection()) + webhookLogCollection := p.db.Collection(schemas.Collections.WebhookLog, options.Collection()) _, err := webhookLogCollection.InsertOne(ctx, webhookLog) if err != nil { return nil, err } - return webhookLog.AsAPIWebhookLog(), nil + return webhookLog, nil } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { - webhookLogs := []*model.WebhookLog{} +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) ([]*schemas.WebhookLog, *model.Pagination, error) { + webhookLogs := []*schemas.WebhookLog{} opts := options.Find() opts.SetLimit(pagination.Limit) opts.SetSkip(pagination.Offset) @@ -44,31 +44,28 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagina query = bson.M{"webhook_id": webhookID} } - webhookLogCollection := p.db.Collection(models.Collections.WebhookLog, options.Collection()) + webhookLogCollection := p.db.Collection(schemas.Collections.WebhookLog, options.Collection()) count, err := webhookLogCollection.CountDocuments(ctx, query, options.Count()) if err != nil { - return nil, err + return nil, nil, err } paginationClone.Total = count cursor, err := webhookLogCollection.Find(ctx, query, opts) if err != nil { - return nil, err + return nil, nil, err } defer cursor.Close(ctx) for cursor.Next(ctx) { - var webhookLog *models.WebhookLog + var webhookLog *schemas.WebhookLog err := cursor.Decode(&webhookLog) if err != nil { - return nil, err + return nil, nil, err } - webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog()) + webhookLogs = append(webhookLogs, webhookLog) } - return &model.WebhookLogs{ - Pagination: paginationClone, - WebhookLogs: webhookLogs, - }, nil + return webhookLogs, paginationClone, nil } diff --git a/server/db/providers/provider_template/authenticator.go b/internal/storage/db/provider_template/authenticator.go similarity index 69% rename from server/db/providers/provider_template/authenticator.go rename to internal/storage/db/provider_template/authenticator.go index 508cd5e60..5bc5702e0 100644 --- a/server/db/providers/provider_template/authenticator.go +++ b/internal/storage/db/provider_template/authenticator.go @@ -6,10 +6,10 @@ import ( "github.com/google/uuid" - "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) -func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) AddAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method) if exists != nil { return authenticators, nil @@ -23,12 +23,12 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models. return authenticators, nil } -func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { authenticators.UpdatedAt = time.Now().Unix() return authenticators, nil } -func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) { - var authenticators *models.Authenticator +func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*schemas.Authenticator, error) { + var authenticators *schemas.Authenticator return authenticators, nil } diff --git a/server/db/providers/provider_template/email_template.go b/internal/storage/db/provider_template/email_template.go similarity index 65% rename from server/db/providers/provider_template/email_template.go rename to internal/storage/db/provider_template/email_template.go index a30647995..8e1faf4a2 100644 --- a/server/db/providers/provider_template/email_template.go +++ b/internal/storage/db/provider_template/email_template.go @@ -4,13 +4,14 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() } @@ -18,31 +19,31 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.E emailTemplate.Key = emailTemplate.ID emailTemplate.CreatedAt = time.Now().Unix() emailTemplate.UpdatedAt = time.Now().Unix() - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { emailTemplate.UpdatedAt = time.Now().Unix() - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { - return nil, nil +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) ([]*schemas.EmailTemplate, *model.Pagination, error) { + return nil, nil, nil } // GetEmailTemplateByID to get EmailTemplate by id -func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { +func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*schemas.EmailTemplate, error) { return nil, nil } // GetEmailTemplateByEventName to get EmailTemplate by event_name -func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { +func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*schemas.EmailTemplate, error) { return nil, nil } // DeleteEmailTemplate to delete EmailTemplate -func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error { +func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) error { return nil } diff --git a/server/db/providers/provider_template/env.go b/internal/storage/db/provider_template/env.go similarity index 58% rename from server/db/providers/provider_template/env.go rename to internal/storage/db/provider_template/env.go index 823d4e305..1f4b05029 100644 --- a/server/db/providers/provider_template/env.go +++ b/internal/storage/db/provider_template/env.go @@ -4,12 +4,13 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *schemas.Env) (*schemas.Env, error) { if env.ID == "" { env.ID = uuid.New().String() } @@ -20,14 +21,14 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er } // 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 *schemas.Env) (*schemas.Env, error) { env.UpdatedAt = time.Now().Unix() return env, nil } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { - var env *models.Env +func (p *provider) GetEnv(ctx context.Context) (*schemas.Env, error) { + var env *schemas.Env return env, nil } diff --git a/server/db/providers/provider_template/otp.go b/internal/storage/db/provider_template/otp.go similarity index 58% rename from server/db/providers/provider_template/otp.go rename to internal/storage/db/provider_template/otp.go index 07167118f..94e351cbc 100644 --- a/server/db/providers/provider_template/otp.go +++ b/internal/storage/db/provider_template/otp.go @@ -3,25 +3,25 @@ package provider_template import ( "context" - "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // UpsertOTP to add or update otp -func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, error) { +func (p *provider) UpsertOTP(ctx context.Context, otp *schemas.OTP) (*schemas.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) { +func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*schemas.OTP, error) { return nil, nil } // GetOTPByPhoneNumber to get otp for a given phone number -func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.OTP, error) { return nil, nil } // DeleteOTP to delete otp -func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { +func (p *provider) DeleteOTP(ctx context.Context, otp *schemas.OTP) error { return nil } diff --git a/internal/storage/db/provider_template/provider.go b/internal/storage/db/provider_template/provider.go new file mode 100644 index 000000000..905db07a0 --- /dev/null +++ b/internal/storage/db/provider_template/provider.go @@ -0,0 +1,35 @@ +package provider_template + +import ( + "github.com/rs/zerolog" + "gorm.io/gorm" + + "github.com/authorizerdev/authorizer/internal/config" +) + +// Dependencies struct the TODO(replace with new db name) data store provider +type Dependencies struct { + Log *zerolog.Logger +} + +// TODO change following provider to new db provider +type provider struct { + config *config.Config + dependencies *Dependencies + db *gorm.DB +} + +// NewProvider returns a new SQL provider +// TODO change following provider to new db provider +func NewProvider( + config *config.Config, + deps *Dependencies, +) (*provider, error) { + var sqlDB *gorm.DB + + return &provider{ + config: config, + dependencies: deps, + db: sqlDB, + }, nil +} diff --git a/server/db/providers/provider_template/session.go b/internal/storage/db/provider_template/session.go similarity index 74% rename from server/db/providers/provider_template/session.go rename to internal/storage/db/provider_template/session.go index e398e8c51..ebbd8c79d 100644 --- a/server/db/providers/provider_template/session.go +++ b/internal/storage/db/provider_template/session.go @@ -4,12 +4,13 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session *models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *schemas.Session) error { if session.ID == "" { session.ID = uuid.New().String() } diff --git a/server/db/providers/provider_template/user.go b/internal/storage/db/provider_template/user.go similarity index 67% rename from server/db/providers/provider_template/user.go rename to internal/storage/db/provider_template/user.go index b84aa6316..e5e28c54d 100644 --- a/server/db/providers/provider_template/user.go +++ b/internal/storage/db/provider_template/user.go @@ -6,25 +6,20 @@ import ( "strings" "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/authorizerdev/authorizer/server/refs" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { if user.ID == "" { user.ID = uuid.New().String() } if user.Roles == "" { - defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - return nil, err - } - user.Roles = defaultRoles + user.Roles = strings.Join(p.config.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 { @@ -41,30 +36,30 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User } // UpdateUser to update user information in database -func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) UpdateUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { user.UpdatedAt = time.Now().Unix() return user, nil } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { +func (p *provider) DeleteUser(ctx context.Context, user *schemas.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 +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) ([]*schemas.User, *model.Pagination, error) { + return nil, nil, nil } // GetUserByEmail to get user information from database using email address -func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) { - var user *models.User +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*schemas.User, error) { + var user *schemas.User return user, nil } // GetUserByID to get user information from database using user ID -func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) { - var user *models.User +func (p *provider) GetUserByID(ctx context.Context, id string) (*schemas.User, error) { + var user *schemas.User return user, nil } @@ -77,7 +72,7 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } // GetUserByPhoneNumber to get user information from database using phone number -func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) { - var user *models.User +func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.User, error) { + var user *schemas.User return user, nil } diff --git a/server/db/providers/provider_template/verification_requests.go b/internal/storage/db/provider_template/verification_requests.go similarity index 63% rename from server/db/providers/provider_template/verification_requests.go rename to internal/storage/db/provider_template/verification_requests.go index c3a7f18a5..e7a7d6d52 100644 --- a/server/db/providers/provider_template/verification_requests.go +++ b/internal/storage/db/provider_template/verification_requests.go @@ -4,13 +4,14 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) (*schemas.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() } @@ -22,25 +23,25 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { - var verificationRequest *models.VerificationRequest +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*schemas.VerificationRequest, error) { + var verificationRequest *schemas.VerificationRequest return verificationRequest, nil } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { - var verificationRequest *models.VerificationRequest +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*schemas.VerificationRequest, error) { + var verificationRequest *schemas.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 +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) ([]*schemas.VerificationRequest, *model.Pagination, error) { + return nil, nil, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) error { return nil } diff --git a/server/db/providers/provider_template/webhook.go b/internal/storage/db/provider_template/webhook.go similarity index 63% rename from server/db/providers/provider_template/webhook.go rename to internal/storage/db/provider_template/webhook.go index cf0edbe00..fd945f87b 100644 --- a/server/db/providers/provider_template/webhook.go +++ b/internal/storage/db/provider_template/webhook.go @@ -6,13 +6,14 @@ import ( "strings" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // 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 *schemas.Webhook) (*schemas.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() } @@ -21,36 +22,36 @@ func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*mo 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, nil } // 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 *schemas.Webhook) (*schemas.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()) } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { - return nil, nil +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) ([]*schemas.Webhook, *model.Pagination, error) { + return nil, nil, nil } // 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) (*schemas.Webhook, error) { return nil, nil } // 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) ([]*schemas.Webhook, error) { return nil, nil } // DeleteWebhook to delete webhook -func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error { +func (p *provider) DeleteWebhook(ctx context.Context, webhook *schemas.Webhook) error { // Also delete webhook logs for given webhook id return nil } diff --git a/server/db/providers/provider_template/webhook_log.go b/internal/storage/db/provider_template/webhook_log.go similarity index 60% rename from server/db/providers/provider_template/webhook_log.go rename to internal/storage/db/provider_template/webhook_log.go index 9ad81d244..e2098cbaf 100644 --- a/server/db/providers/provider_template/webhook_log.go +++ b/internal/storage/db/provider_template/webhook_log.go @@ -4,13 +4,14 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *schemas.WebhookLog) (*schemas.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } @@ -18,10 +19,10 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.Webhook webhookLog.Key = webhookLog.ID webhookLog.CreatedAt = time.Now().Unix() webhookLog.UpdatedAt = time.Now().Unix() - return webhookLog.AsAPIWebhookLog(), nil + return webhookLog, nil } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { - return nil, nil +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) ([]*schemas.WebhookLog, *model.Pagination, error) { + return nil, nil, nil } diff --git a/server/db/providers/sql/authenticator.go b/internal/storage/db/sql/authenticator.go similarity index 79% rename from server/db/providers/sql/authenticator.go rename to internal/storage/db/sql/authenticator.go index b8cf79717..7792c1ad2 100644 --- a/server/db/providers/sql/authenticator.go +++ b/internal/storage/db/sql/authenticator.go @@ -7,10 +7,10 @@ import ( "github.com/google/uuid" "gorm.io/gorm/clause" - "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) -func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) AddAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method) if exists != nil { return authenticators, nil @@ -33,7 +33,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models. return authenticators, nil } -func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) { +func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *schemas.Authenticator) (*schemas.Authenticator, error) { authenticators.UpdatedAt = time.Now().Unix() result := p.db.Save(&authenticators) if result.Error != nil { @@ -42,8 +42,8 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode return authenticators, nil } -func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) { - var authenticators models.Authenticator +func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*schemas.Authenticator, error) { + var authenticators schemas.Authenticator result := p.db.Where("user_id = ?", userId).Where("method = ?", authenticatorType).First(&authenticators) if result.Error != nil { return nil, result.Error diff --git a/server/db/providers/sql/email_template.go b/internal/storage/db/sql/email_template.go similarity index 59% rename from server/db/providers/sql/email_template.go rename to internal/storage/db/sql/email_template.go index 8928b6f7a..3926107d7 100644 --- a/server/db/providers/sql/email_template.go +++ b/internal/storage/db/sql/email_template.go @@ -4,13 +4,14 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEmailTemplate to add EmailTemplate -func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() } @@ -23,72 +24,65 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate *models.E if res.Error != nil { return nil, res.Error } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // UpdateEmailTemplate to update EmailTemplate -func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) { +func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) { emailTemplate.UpdatedAt = time.Now().Unix() res := p.db.Save(&emailTemplate) if res.Error != nil { return nil, res.Error } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // ListEmailTemplates to list EmailTemplate -func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) { - var emailTemplates []*models.EmailTemplate +func (p *provider) ListEmailTemplate(ctx context.Context, pagination *model.Pagination) ([]*schemas.EmailTemplate, *model.Pagination, error) { + var emailTemplates []*schemas.EmailTemplate result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&emailTemplates) if result.Error != nil { - return nil, result.Error + return nil, nil, result.Error } var total int64 - totalRes := p.db.Model(&models.EmailTemplate{}).Count(&total) + totalRes := p.db.Model(&schemas.EmailTemplate{}).Count(&total) if totalRes.Error != nil { - return nil, totalRes.Error + return nil, nil, totalRes.Error } paginationClone := pagination paginationClone.Total = total - responseEmailTemplates := []*model.EmailTemplate{} - for _, w := range emailTemplates { - responseEmailTemplates = append(responseEmailTemplates, w.AsAPIEmailTemplate()) - } - return &model.EmailTemplates{ - Pagination: paginationClone, - EmailTemplates: responseEmailTemplates, - }, nil + return emailTemplates, paginationClone, nil } // GetEmailTemplateByID to get EmailTemplate by id -func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { - var emailTemplate *models.EmailTemplate +func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*schemas.EmailTemplate, error) { + var emailTemplate *schemas.EmailTemplate result := p.db.Where("id = ?", emailTemplateID).First(&emailTemplate) if result.Error != nil { return nil, result.Error } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // GetEmailTemplateByEventName to get EmailTemplate by event_name -func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { - var emailTemplate *models.EmailTemplate +func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*schemas.EmailTemplate, error) { + var emailTemplate *schemas.EmailTemplate result := p.db.Where("event_name = ?", eventName).First(&emailTemplate) if result.Error != nil { return nil, result.Error } - return emailTemplate.AsAPIEmailTemplate(), nil + return emailTemplate, nil } // DeleteEmailTemplate to delete EmailTemplate -func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error { - result := p.db.Delete(&models.EmailTemplate{ +func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) error { + result := p.db.Delete(&schemas.EmailTemplate{ ID: emailTemplate.ID, }) if result.Error != nil { diff --git a/server/db/providers/sql/env.go b/internal/storage/db/sql/env.go similarity index 68% rename from server/db/providers/sql/env.go rename to internal/storage/db/sql/env.go index 11584a050..f13503209 100644 --- a/server/db/providers/sql/env.go +++ b/internal/storage/db/sql/env.go @@ -4,12 +4,13 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddEnv to save environment information in database -func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) { +func (p *provider) AddEnv(ctx context.Context, env *schemas.Env) (*schemas.Env, error) { if env.ID == "" { env.ID = uuid.New().String() } @@ -26,7 +27,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er } // 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 *schemas.Env) (*schemas.Env, error) { env.UpdatedAt = time.Now().Unix() result := p.db.Save(&env) if result.Error != nil { @@ -36,8 +37,8 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, } // GetEnv to get environment information from database -func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) { - var env *models.Env +func (p *provider) GetEnv(ctx context.Context) (*schemas.Env, error) { + var env *schemas.Env result := p.db.First(&env) if result.Error != nil { return env, result.Error diff --git a/server/db/providers/sql/otp.go b/internal/storage/db/sql/otp.go similarity index 76% rename from server/db/providers/sql/otp.go rename to internal/storage/db/sql/otp.go index 4bf9b11f3..eed7e0596 100644 --- a/server/db/providers/sql/otp.go +++ b/internal/storage/db/sql/otp.go @@ -5,12 +5,13 @@ import ( "errors" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // UpsertOTP to add or update otp -func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { +func (p *provider) UpsertOTP(ctx context.Context, otpParam *schemas.OTP) (*schemas.OTP, error) { if otpParam.ID == "" { otpParam.ID = uuid.New().String() } @@ -18,12 +19,12 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models if otpParam.Email == "" && otpParam.PhoneNumber == "" { return nil, errors.New("email or phone_number is required") } - uniqueField := models.FieldNameEmail + uniqueField := schemas.FieldNameEmail if otpParam.Email == "" && otpParam.PhoneNumber != "" { - uniqueField = models.FieldNamePhoneNumber + uniqueField = schemas.FieldNamePhoneNumber } - var otp *models.OTP - if uniqueField == models.FieldNameEmail { + var otp *schemas.OTP + if uniqueField == schemas.FieldNameEmail { otp, _ = p.GetOTPByEmail(ctx, otpParam.Email) } else { otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber) @@ -31,7 +32,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models shouldCreate := false if otp == nil { id := uuid.NewString() - otp = &models.OTP{ + otp = &schemas.OTP{ ID: id, Key: id, Otp: otpParam.Otp, @@ -61,8 +62,8 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models } // GetOTPByEmail to get otp for a given email address -func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { - var otp models.OTP +func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*schemas.OTP, error) { + var otp schemas.OTP result := p.db.Where("email = ?", emailAddress).First(&otp) if result.Error != nil { return nil, result.Error @@ -71,8 +72,8 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod } // GetOTPByPhoneNumber to get otp for a given phone number -func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) { - var otp models.OTP +func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.OTP, error) { + var otp schemas.OTP result := p.db.Where("phone_number = ?", phoneNumber).First(&otp) if result.Error != nil { return nil, result.Error @@ -81,8 +82,8 @@ func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) } // DeleteOTP to delete otp -func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { - result := p.db.Delete(&models.OTP{ +func (p *provider) DeleteOTP(ctx context.Context, otp *schemas.OTP) error { + result := p.db.Delete(&schemas.OTP{ ID: otp.ID, }) if result.Error != nil { diff --git a/server/db/providers/sql/provider.go b/internal/storage/db/sql/provider.go similarity index 70% rename from server/db/providers/sql/provider.go rename to internal/storage/db/sql/provider.go index 02118ec2f..37d16ae39 100644 --- a/server/db/providers/sql/provider.go +++ b/internal/storage/db/sql/provider.go @@ -1,26 +1,33 @@ package sql import ( - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/memorystore" libsql "github.com/ekristen/gorm-libsql" "github.com/glebarez/sqlite" - "github.com/sirupsen/logrus" + "github.com/rs/zerolog" "gorm.io/driver/mysql" "gorm.io/driver/postgres" "gorm.io/driver/sqlserver" "gorm.io/gorm" - "gorm.io/gorm/logger" "gorm.io/gorm/schema" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) +// Dependencies struct the sql data store provider +type Dependencies struct { + Log *zerolog.Logger +} + type provider struct { - db *gorm.DB + config *config.Config + dependencies *Dependencies + db *gorm.DB } +/** +Required to address the impact of the following code block: const ( phoneNumberIndexName = "UQ_phone_number" phoneNumberColumnName = "phone_number" @@ -30,31 +37,25 @@ type indexInfo struct { IndexName string `json:"index_name"` ColumnName string `json:"column_name"` } +**/ // NewProvider returns a new SQL provider -func NewProvider() (*provider, error) { +func NewProvider( + config *config.Config, + deps *Dependencies, +) (*provider, error) { var sqlDB *gorm.DB var err error - customLogger := logger.New( - logrus.StandardLogger(), - logger.Config{ - SlowThreshold: time.Second, // Slow SQL threshold - LogLevel: logger.Error, // Log level - IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger - Colorful: false, // Disable color - }, - ) ormConfig := &gorm.Config{ - Logger: customLogger, NamingStrategy: schema.NamingStrategy{ - TablePrefix: models.Prefix, + TablePrefix: schemas.Prefix, }, AllowGlobalUpdate: true, } - dbType := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseType - dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL + dbType := config.DatabaseType + dbURL := config.DatabaseURL switch dbType { case constants.DbTypePostgres, constants.DbTypeYugabyte, constants.DbTypeCockroachDB: @@ -75,12 +76,14 @@ func NewProvider() (*provider, error) { // For sqlserver, handle uniqueness of phone_number manually via extra db call // during create and update mutation. - if sqlDB.Migrator().HasConstraint(&models.User{}, "authorizer_users_phone_number_key") { - err = sqlDB.Migrator().DropConstraint(&models.User{}, "authorizer_users_phone_number_key") - logrus.Debug("Failed to drop phone number constraint:", err) + if sqlDB.Migrator().HasConstraint(&schemas.User{}, "authorizer_users_phone_number_key") { + err = sqlDB.Migrator().DropConstraint(&schemas.User{}, "authorizer_users_phone_number_key") + if err != nil { + deps.Log.Debug().Err(err).Msg("failed to drop unique constraint on phone_number") + } } - err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}, &models.Webhook{}, &models.WebhookLog{}, &models.EmailTemplate{}, &models.OTP{}, &models.Authenticator{}) + err = sqlDB.AutoMigrate(&schemas.User{}, &schemas.VerificationRequest{}, &schemas.Session{}, &schemas.Env{}, &schemas.Webhook{}, &schemas.WebhookLog{}, &schemas.EmailTemplate{}, &schemas.OTP{}, &schemas.Authenticator{}) if err != nil { return nil, err } @@ -112,6 +115,8 @@ func NewProvider() (*provider, error) { // } return &provider{ - db: sqlDB, + config: config, + dependencies: deps, + db: sqlDB, }, nil } diff --git a/server/db/providers/sql/session.go b/internal/storage/db/sql/session.go similarity index 80% rename from server/db/providers/sql/session.go rename to internal/storage/db/sql/session.go index a7e3e1374..ad2941b36 100644 --- a/server/db/providers/sql/session.go +++ b/internal/storage/db/sql/session.go @@ -4,13 +4,14 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" "gorm.io/gorm/clause" + + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddSession to save session information in database -func (p *provider) AddSession(ctx context.Context, session *models.Session) error { +func (p *provider) AddSession(ctx context.Context, session *schemas.Session) error { if session.ID == "" { session.ID = uuid.New().String() } diff --git a/server/db/providers/sql/user.go b/internal/storage/db/sql/user.go similarity index 67% rename from server/db/providers/sql/user.go rename to internal/storage/db/sql/user.go index e0b61fe3d..ba6cdfdae 100644 --- a/server/db/providers/sql/user.go +++ b/internal/storage/db/sql/user.go @@ -6,27 +6,22 @@ import ( "strings" "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/authorizerdev/authorizer/server/refs" "github.com/google/uuid" "gorm.io/gorm" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddUser to save user information in database -func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) AddUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { if user.ID == "" { user.ID = uuid.New().String() } if user.Roles == "" { - defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - return nil, err - } - user.Roles = defaultRoles + user.Roles = strings.Join(p.config.DefaultRoles, ",") } if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" { @@ -52,7 +47,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User } // UpdateUser to update user information in database -func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) { +func (p *provider) UpdateUser(ctx context.Context, user *schemas.User) (*schemas.User, error) { user.UpdatedAt = time.Now().Unix() result := p.db.Save(&user) @@ -65,8 +60,8 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U } // DeleteUser to delete user information from database -func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { - result := p.db.Where("user_id = ?", user.ID).Delete(&models.Session{}) +func (p *provider) DeleteUser(ctx context.Context, user *schemas.User) error { + result := p.db.Where("user_id = ?", user.ID).Delete(&schemas.Session{}) if result.Error != nil { return result.Error } @@ -80,36 +75,28 @@ func (p *provider) DeleteUser(ctx context.Context, user *models.User) error { } // ListUsers to get list of users from database -func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) { - var users []models.User +func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) ([]*schemas.User, *model.Pagination, error) { + var users []*schemas.User result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&users) if result.Error != nil { - return nil, result.Error - } - - responseUsers := []*model.User{} - for _, user := range users { - responseUsers = append(responseUsers, user.AsAPIUser()) + return nil, nil, result.Error } var total int64 - totalRes := p.db.Model(&models.User{}).Count(&total) + totalRes := p.db.Model(&schemas.User{}).Count(&total) if totalRes.Error != nil { - return nil, totalRes.Error + return nil, nil, totalRes.Error } paginationClone := pagination paginationClone.Total = total - return &model.Users{ - Pagination: paginationClone, - Users: responseUsers, - }, nil + return users, paginationClone, nil } // GetUserByEmail to get user information from database using email address -func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) { - var user *models.User +func (p *provider) GetUserByEmail(ctx context.Context, email string) (*schemas.User, error) { + var user *schemas.User result := p.db.Where("email = ?", email).First(&user) if result.Error != nil { return nil, result.Error @@ -118,8 +105,8 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us } // GetUserByID to get user information from database using user ID -func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) { - var user *models.User +func (p *provider) GetUserByID(ctx context.Context, id string) (*schemas.User, error) { + var user *schemas.User result := p.db.Where("id = ?", id).First(&user) if result.Error != nil { return nil, result.Error @@ -134,9 +121,9 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, data["updated_at"] = time.Now().Unix() var res *gorm.DB if len(ids) > 0 { - res = p.db.Model(&models.User{}).Where("id in ?", ids).Updates(data) + res = p.db.Model(&schemas.User{}).Where("id in ?", ids).Updates(data) } else { - res = p.db.Model(&models.User{}).Updates(data) + res = p.db.Model(&schemas.User{}).Updates(data) } if res.Error != nil { return res.Error @@ -145,8 +132,8 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, } // GetUserByPhoneNumber to get user information from database using phone number -func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) { - var user *models.User +func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.User, error) { + var user *schemas.User result := p.db.Where("phone_number = ?", phoneNumber).First(&user) if result.Error != nil { return nil, result.Error diff --git a/server/db/providers/sql/verification_requests.go b/internal/storage/db/sql/verification_requests.go similarity index 66% rename from server/db/providers/sql/verification_requests.go rename to internal/storage/db/sql/verification_requests.go index ac91becdf..21bbc6cd3 100644 --- a/server/db/providers/sql/verification_requests.go +++ b/internal/storage/db/sql/verification_requests.go @@ -4,14 +4,15 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" "gorm.io/gorm/clause" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddVerification to save verification request in database -func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) { +func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) (*schemas.VerificationRequest, error) { if verificationRequest.ID == "" { verificationRequest.ID = uuid.New().String() } @@ -29,8 +30,8 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque } // GetVerificationRequestByToken to get verification request from database using token -func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) { - var verificationRequest *models.VerificationRequest +func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (*schemas.VerificationRequest, error) { + var verificationRequest *schemas.VerificationRequest result := p.db.Where("token = ?", token).First(&verificationRequest) if result.Error != nil { return verificationRequest, result.Error @@ -39,8 +40,8 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri } // GetVerificationRequestByEmail to get verification request by email from database -func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) { - var verificationRequest *models.VerificationRequest +func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*schemas.VerificationRequest, error) { + var verificationRequest *schemas.VerificationRequest result := p.db.Where("email = ? AND identifier = ?", email, identifier).First(&verificationRequest) if result.Error != nil { return verificationRequest, result.Error @@ -49,31 +50,24 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri } // ListVerificationRequests to get list of verification requests from database -func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) { - var verificationRequests []models.VerificationRequest +func (p *provider) ListVerificationRequests(ctx context.Context, pagination *model.Pagination) ([]*schemas.VerificationRequest, *model.Pagination, error) { + var verificationRequests []*schemas.VerificationRequest result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&verificationRequests) if result.Error != nil { - return nil, result.Error - } - responseVerificationRequests := []*model.VerificationRequest{} - for _, v := range verificationRequests { - responseVerificationRequests = append(responseVerificationRequests, v.AsAPIVerificationRequest()) + return nil, nil, result.Error } var total int64 - totalRes := p.db.Model(&models.VerificationRequest{}).Count(&total) + totalRes := p.db.Model(&schemas.VerificationRequest{}).Count(&total) if totalRes.Error != nil { - return nil, totalRes.Error + return nil, nil, totalRes.Error } paginationClone := pagination paginationClone.Total = total - return &model.VerificationRequests{ - VerificationRequests: responseVerificationRequests, - Pagination: paginationClone, - }, nil + return verificationRequests, paginationClone, nil } // DeleteVerificationRequest to delete verification request from database -func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error { +func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) error { result := p.db.Delete(&verificationRequest) if result.Error != nil { return result.Error diff --git a/server/db/providers/sql/webhook.go b/internal/storage/db/sql/webhook.go similarity index 57% rename from server/db/providers/sql/webhook.go rename to internal/storage/db/sql/webhook.go index 54e2d130f..41675c233 100644 --- a/server/db/providers/sql/webhook.go +++ b/internal/storage/db/sql/webhook.go @@ -6,13 +6,14 @@ import ( "strings" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // 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 *schemas.Webhook) (*schemas.Webhook, error) { if webhook.ID == "" { webhook.ID = uuid.New().String() } @@ -25,11 +26,11 @@ func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*mo if res.Error != nil { return nil, res.Error } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // 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 *schemas.Webhook) (*schemas.Webhook, error) { webhook.UpdatedAt = time.Now().Unix() // Event is changed if !strings.Contains(webhook.EventName, "-") { @@ -39,68 +40,58 @@ func (p *provider) UpdateWebhook(ctx context.Context, webhook *models.Webhook) ( if result.Error != nil { return nil, result.Error } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // ListWebhooks to list webhook -func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) { - var webhooks []models.Webhook +func (p *provider) ListWebhook(ctx context.Context, pagination *model.Pagination) ([]*schemas.Webhook, *model.Pagination, error) { + var webhooks []*schemas.Webhook result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&webhooks) if result.Error != nil { - return nil, result.Error + return nil, nil, result.Error } var total int64 - totalRes := p.db.Model(&models.Webhook{}).Count(&total) + totalRes := p.db.Model(&schemas.Webhook{}).Count(&total) if totalRes.Error != nil { - return nil, totalRes.Error + return nil, nil, totalRes.Error } paginationClone := pagination paginationClone.Total = total - responseWebhooks := []*model.Webhook{} - for _, w := range webhooks { - responseWebhooks = append(responseWebhooks, w.AsAPIWebhook()) - } - return &model.Webhooks{ - Pagination: paginationClone, - Webhooks: responseWebhooks, - }, nil + + return webhooks, paginationClone, nil } // GetWebhookByID to get webhook by id -func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) { - var webhook *models.Webhook +func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*schemas.Webhook, error) { + var webhook *schemas.Webhook result := p.db.Where("id = ?", webhookID).First(&webhook) if result.Error != nil { return nil, result.Error } - return webhook.AsAPIWebhook(), nil + return webhook, nil } // GetWebhookByEventName to get webhook by event_name -func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*model.Webhook, error) { - var webhooks []models.Webhook +func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) ([]*schemas.Webhook, error) { + var webhooks []*schemas.Webhook result := p.db.Where("event_name LIKE ?", eventName+"%").Find(&webhooks) if result.Error != nil { return nil, result.Error } - responseWebhooks := []*model.Webhook{} - for _, w := range webhooks { - responseWebhooks = append(responseWebhooks, w.AsAPIWebhook()) - } - return responseWebhooks, nil + return webhooks, nil } // DeleteWebhook to delete webhook -func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error { - result := p.db.Delete(&models.Webhook{ +func (p *provider) DeleteWebhook(ctx context.Context, webhook *schemas.Webhook) error { + result := p.db.Delete(&schemas.Webhook{ ID: webhook.ID, }) if result.Error != nil { return result.Error } - result = p.db.Where("webhook_id = ?", webhook.ID).Delete(&models.WebhookLog{}) + result = p.db.Where("webhook_id = ?", webhook.ID).Delete(&schemas.WebhookLog{}) if result.Error != nil { return result.Error } diff --git a/server/db/providers/sql/webhook_log.go b/internal/storage/db/sql/webhook_log.go similarity index 59% rename from server/db/providers/sql/webhook_log.go rename to internal/storage/db/sql/webhook_log.go index cf50be2c6..fddf9f951 100644 --- a/server/db/providers/sql/webhook_log.go +++ b/internal/storage/db/sql/webhook_log.go @@ -4,15 +4,16 @@ import ( "context" "time" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" "github.com/google/uuid" "gorm.io/gorm" "gorm.io/gorm/clause" + + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/schemas" ) // AddWebhookLog to add webhook log -func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) { +func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *schemas.WebhookLog) (*schemas.WebhookLog, error) { if webhookLog.ID == "" { webhookLog.ID = uuid.New().String() } @@ -28,41 +29,34 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.Webhook return nil, res.Error } - return webhookLog.AsAPIWebhookLog(), nil + return webhookLog, nil } // ListWebhookLogs to list webhook logs -func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) { - var webhookLogs []models.WebhookLog +func (p *provider) ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) ([]*schemas.WebhookLog, *model.Pagination, error) { + var webhookLogs []*schemas.WebhookLog var result *gorm.DB var totalRes *gorm.DB var total int64 if webhookID != "" { result = p.db.Where("webhook_id = ?", webhookID).Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&webhookLogs) - totalRes = p.db.Where("webhook_id = ?", webhookID).Model(&models.WebhookLog{}).Count(&total) + totalRes = p.db.Where("webhook_id = ?", webhookID).Model(&schemas.WebhookLog{}).Count(&total) } else { result = p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&webhookLogs) - totalRes = p.db.Model(&models.WebhookLog{}).Count(&total) + totalRes = p.db.Model(&schemas.WebhookLog{}).Count(&total) } if result.Error != nil { - return nil, result.Error + return nil, nil, result.Error } if totalRes.Error != nil { - return nil, totalRes.Error + return nil, nil, totalRes.Error } paginationClone := pagination paginationClone.Total = total - responseWebhookLogs := []*model.WebhookLog{} - for _, w := range webhookLogs { - responseWebhookLogs = append(responseWebhookLogs, w.AsAPIWebhookLog()) - } - return &model.WebhookLogs{ - WebhookLogs: responseWebhookLogs, - Pagination: paginationClone, - }, nil + return webhookLogs, paginationClone, nil } diff --git a/internal/storage/provider.go b/internal/storage/provider.go new file mode 100644 index 000000000..f30bef428 --- /dev/null +++ b/internal/storage/provider.go @@ -0,0 +1,171 @@ +package storage + +import ( + "context" + "fmt" + + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/storage/db/arangodb" + "github.com/authorizerdev/authorizer/internal/storage/db/cassandradb" + "github.com/authorizerdev/authorizer/internal/storage/db/couchbase" + "github.com/authorizerdev/authorizer/internal/storage/db/dynamodb" + "github.com/authorizerdev/authorizer/internal/storage/db/mongodb" + "github.com/authorizerdev/authorizer/internal/storage/db/sql" + "github.com/authorizerdev/authorizer/internal/storage/schemas" +) + +// Dependencies struct the data store provider +type Dependencies struct { + Log *zerolog.Logger +} + +// Provider is the interface which defines the methods for the database provider +type Provider interface { + // AddUser to save user information in database + AddUser(ctx context.Context, user *schemas.User) (*schemas.User, error) + // UpdateUser to update user information in database + UpdateUser(ctx context.Context, user *schemas.User) (*schemas.User, error) + // DeleteUser to delete user information from database + DeleteUser(ctx context.Context, user *schemas.User) error + // ListUsers to get list of users from database + ListUsers(ctx context.Context, pagination *model.Pagination) ([]*schemas.User, *model.Pagination, error) + // GetUserByEmail to get user information from database using email address + GetUserByEmail(ctx context.Context, email string) (*schemas.User, error) + // GetUserByPhoneNumber to get user information from database using phone number + GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.User, error) + // GetUserByID to get user information from database using user ID + GetUserByID(ctx context.Context, id string) (*schemas.User, error) + // UpdateUsers to update multiple users, with parameters of user IDs slice + // If ids set to nil / empty all the users will be updated + UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error + + // AddVerificationRequest to save verification request in database + AddVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) (*schemas.VerificationRequest, error) + // GetVerificationRequestByToken to get verification request from database using token + GetVerificationRequestByToken(ctx context.Context, token string) (*schemas.VerificationRequest, error) + // GetVerificationRequestByEmail to get verification request by email from database + GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*schemas.VerificationRequest, error) + // ListVerificationRequests to get list of verification requests from database + ListVerificationRequests(ctx context.Context, pagination *model.Pagination) ([]*schemas.VerificationRequest, *model.Pagination, error) + // DeleteVerificationRequest to delete verification request from database + DeleteVerificationRequest(ctx context.Context, verificationRequest *schemas.VerificationRequest) error + + // AddSession to save session information in database + AddSession(ctx context.Context, session *schemas.Session) error + // DeleteSession to delete session information from database + DeleteSession(ctx context.Context, userId string) error + + // // AddEnv to save environment information in database + // AddEnv(ctx context.Context, env *schemas.Env) (*schemas.Env, error) + // // UpdateEnv to update environment information in database + // UpdateEnv(ctx context.Context, env *schemas.Env) (*schemas.Env, error) + // // GetEnv to get environment information from database + // GetEnv(ctx context.Context) (*schemas.Env, error) + + // AddWebhook to add webhook + AddWebhook(ctx context.Context, webhook *schemas.Webhook) (*schemas.Webhook, error) + // UpdateWebhook to update webhook + UpdateWebhook(ctx context.Context, webhook *schemas.Webhook) (*schemas.Webhook, error) + // ListWebhook to list webhook + ListWebhook(ctx context.Context, pagination *model.Pagination) ([]*schemas.Webhook, *model.Pagination, error) + // GetWebhookByID to get webhook by id + GetWebhookByID(ctx context.Context, webhookID string) (*schemas.Webhook, error) + // GetWebhookByEventName to get webhook by event_name + GetWebhookByEventName(ctx context.Context, eventName string) ([]*schemas.Webhook, error) + // DeleteWebhook to delete webhook + DeleteWebhook(ctx context.Context, webhook *schemas.Webhook) error + + // AddWebhookLog to add webhook log + AddWebhookLog(ctx context.Context, webhookLog *schemas.WebhookLog) (*schemas.WebhookLog, error) + // ListWebhookLogs to list webhook logs + ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) ([]*schemas.WebhookLog, *model.Pagination, error) + + // AddEmailTemplate to add EmailTemplate + AddEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) + // UpdateEmailTemplate to update EmailTemplate + UpdateEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) (*schemas.EmailTemplate, error) + // ListEmailTemplate to list EmailTemplate + ListEmailTemplate(ctx context.Context, pagination *model.Pagination) ([]*schemas.EmailTemplate, *model.Pagination, error) + // GetEmailTemplateByID to get EmailTemplate by id + GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*schemas.EmailTemplate, error) + // GetEmailTemplateByEventName to get EmailTemplate by event_name + GetEmailTemplateByEventName(ctx context.Context, eventName string) (*schemas.EmailTemplate, error) + // DeleteEmailTemplate to delete EmailTemplate + DeleteEmailTemplate(ctx context.Context, emailTemplate *schemas.EmailTemplate) error + + // UpsertOTP to add or update otp + UpsertOTP(ctx context.Context, otp *schemas.OTP) (*schemas.OTP, error) + // GetOTPByEmail to get otp for a given email address + GetOTPByEmail(ctx context.Context, emailAddress string) (*schemas.OTP, error) + // GetOTPByPhoneNumber to get otp for a given phone number + GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*schemas.OTP, error) + // DeleteOTP to delete otp + DeleteOTP(ctx context.Context, otp *schemas.OTP) error + + // AddAuthenticator adds a new authenticator document to the database. + // If the authenticator doesn't have an ID, a new one is generated. + // The created document is returned, or an error if the operation fails. + AddAuthenticator(ctx context.Context, totp *schemas.Authenticator) (*schemas.Authenticator, error) + // UpdateAuthenticator updates an existing authenticator document in the database. + // The updated document is returned, or an error if the operation fails. + UpdateAuthenticator(ctx context.Context, totp *schemas.Authenticator) (*schemas.Authenticator, error) + // GetAuthenticatorDetailsByUserId retrieves details of an authenticator document based on user ID and authenticator type. + // If found, the authenticator document is returned, or an error if not found or an error occurs during the retrieval. + GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*schemas.Authenticator, error) +} + +// New creates a new database provider based on the configuration +func New(config *config.Config, deps *Dependencies) (Provider, error) { + var provider Provider + var err error + if config.DatabaseType == "" { + return nil, fmt.Errorf("database type is required") + } + + switch config.DatabaseType { + case constants.DbTypePostgres, + constants.DbTypeSqlite, + constants.DbTypeLibSQL, + constants.DbTypeMysql, + constants.DbTypeSqlserver, + constants.DbTypeYugabyte, + constants.DbTypeMariaDB, + constants.DbTypeCockroachDB, + constants.DbTypePlanetScaleDB: + provider, err = sql.NewProvider(config, &sql.Dependencies{ + Log: deps.Log, + }) + case constants.DbTypeMongoDB: + provider, err = mongodb.NewProvider(config, &mongodb.Dependencies{ + Log: deps.Log, + }) + case constants.DbTypeArangoDB: + provider, err = arangodb.NewProvider(config, &arangodb.Dependencies{ + Log: deps.Log, + }) + case constants.DbTypeCassandraDB, + constants.DbTypeScyllaDB: + provider, err = cassandradb.NewProvider(config, &cassandradb.Dependencies{ + Log: deps.Log, + }) + case constants.DbTypeCouchbaseDB: + provider, err = couchbase.NewProvider(config, &couchbase.Dependencies{ + Log: deps.Log, + }) + case constants.DbTypeDynamoDB: + provider, err = dynamodb.NewProvider(config, &dynamodb.Dependencies{ + Log: deps.Log, + }) + default: + err = fmt.Errorf("unsupported database type: %s", config.DatabaseType) + + } + if err != nil { + return nil, err + } + return provider, nil +} diff --git a/internal/storage/provider_test.go b/internal/storage/provider_test.go new file mode 100644 index 000000000..d70cbcb1d --- /dev/null +++ b/internal/storage/provider_test.go @@ -0,0 +1,401 @@ +package storage + +import ( + "context" + "os" + "testing" + "time" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/google/uuid" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var dbTypes = []string{ + constants.DbTypePostgres, + // constants.DbTypeMongoDB, + // constants.DbTypeArangoDB, + // constants.DbTypeScyllaDB, + // constants.DbTypeCouchbaseDB, + // constants.DbTypeDynamoDB, +} + +func getTestDBConfig(dbType string) *config.Config { + cfg := &config.Config{ + DatabaseName: "authorizer_test", + AWSRegion: "us-east-1", + } + cfg.DatabaseType = dbType + + // Set specific database URLs based on type + switch dbType { + case constants.DbTypePostgres: + cfg.DatabaseURL = "postgres://postgres:postgres@localhost:5432/postgres" + case constants.DbTypeMongoDB: + cfg.DatabaseURL = "mongodb://localhost:27017" + case constants.DbTypeArangoDB: + cfg.DatabaseURL = "http://localhost:8529" + case constants.DbTypeScyllaDB: + cfg.DatabaseURL = "127.0.0.1:9042" + case constants.DbTypeCouchbaseDB: + cfg.DatabaseURL = "couchbase://127.0.0.1" + case constants.DbTypeDynamoDB: + cfg.DatabaseURL = "http://0.0.0.0:8000" + } + + return cfg +} + +func TestStorageProvider(t *testing.T) { + // Initialize logger + logger := zerolog.New(zerolog.NewTestWriter(t)).With().Timestamp().Logger() + for _, dbType := range dbTypes { + t.Run("should test storage provider for "+dbType, func(t *testing.T) { + if dbType == constants.DbTypeDynamoDB { + os.Unsetenv("AWS_ACCESS_KEY_ID") + os.Unsetenv("AWS_SECRET_ACCESS_KEY") + } + cfg := getTestDBConfig(dbType) + if dbType == constants.DbTypeCouchbaseDB { + cfg.DatabaseUsername = "Administrator" + cfg.DatabasePassword = "password" + } + ctx := context.Background() + provider, err := New(cfg, &Dependencies{ + Log: &logger, + }) + if err != nil { + log.Error().Err(err).Msg("failed to create storage provider") + } + require.NoError(t, err) + require.NotNil(t, provider) + + t.Run("Authenticator Operations", func(t *testing.T) { + testAuthenticatorOperations(t, ctx, provider) + }) + + t.Run("Email Template Operations", func(t *testing.T) { + testEmailTemplateOperations(t, ctx, provider) + }) + + t.Run("OTP Operations", func(t *testing.T) { + testOTPOperations(t, ctx, provider) + }) + + t.Run("Session Operations", func(t *testing.T) { + testSessionOperations(t, ctx, provider) + }) + + t.Run("User Operations", func(t *testing.T) { + testUserOperations(t, ctx, provider) + }) + + t.Run("Verification Request Operations", func(t *testing.T) { + testVerificationRequestOperations(t, ctx, provider) + }) + + t.Run("Webhook Operations", func(t *testing.T) { + testWebhookOperations(t, ctx, provider) + }) + + }) + } +} + +func testUserOperations(t *testing.T, ctx context.Context, provider Provider) { + // Create test user + user := &schemas.User{ + ID: uuid.New().String(), + Email: refs.NewStringRef("test_" + uuid.New().String() + "@test.com"), + Password: refs.NewStringRef("hashedPassword"), + SignupMethods: "basic_auth", + } + + // Test AddUser + createdUser, err := provider.AddUser(ctx, user) + assert.NoError(t, err) + assert.NotNil(t, createdUser) + assert.Equal(t, user.Email, createdUser.Email) + + // Test GetUserByEmail + fetchedUser, err := provider.GetUserByEmail(ctx, *user.Email) + assert.NoError(t, err) + assert.Equal(t, user.Email, fetchedUser.Email) + + // Test UpdateUser + fetchedUser.GivenName = refs.NewStringRef("Updated") + updatedUser, err := provider.UpdateUser(ctx, fetchedUser) + assert.NoError(t, err) + assert.Equal(t, "Updated", *updatedUser.GivenName) + + // Test ListUsers + users, pagination, err := provider.ListUsers(ctx, &model.Pagination{ + Limit: 10, + Offset: 0, + }) + assert.NoError(t, err) + assert.NotNil(t, users) + assert.Greater(t, len(users), 0) + assert.NotNil(t, pagination) + assert.Greater(t, pagination.Total, int64(0)) + + // Test DeleteUser + err = provider.DeleteUser(ctx, user) + assert.NoError(t, err) + + // Verify deletion + _, err = provider.GetUserByEmail(ctx, *user.Email) + assert.Error(t, err) + + // Test GetUserByPhoneNumber + user.PhoneNumber = refs.NewStringRef("+1234567891") + createdUser, err = provider.AddUser(ctx, user) + assert.NoError(t, err) + assert.NotNil(t, createdUser) + assert.Equal(t, user.PhoneNumber, createdUser.PhoneNumber) + + // Test GetUserByID + fetchedUser, err = provider.GetUserByID(ctx, createdUser.ID) + assert.NoError(t, err) + assert.NotNil(t, fetchedUser) + assert.Equal(t, user.PhoneNumber, fetchedUser.PhoneNumber) + + // Test UpdateUsers + users, _, err = provider.ListUsers(ctx, &model.Pagination{ + Limit: 10, + Offset: 0, + }) + assert.NoError(t, err) + assert.NotNil(t, users) + assert.Greater(t, len(users), 0) + data := map[string]interface{}{ + "phone_number": "+3216549870", + } + err = provider.UpdateUsers(ctx, data, []string{createdUser.ID}) + assert.NoError(t, err) + + // Test GetUserByPhoneNumber after update + user, err = provider.GetUserByPhoneNumber(ctx, "+3216549870") + assert.NoError(t, err) + assert.NotNil(t, user) + assert.Equal(t, "+3216549870", *user.PhoneNumber) + +} + +func testVerificationRequestOperations(t *testing.T, ctx context.Context, provider Provider) { + vr := &schemas.VerificationRequest{ + Token: uuid.New().String(), + Email: "test_" + uuid.New().String() + "@test.com", + ExpiresAt: time.Now().Add(24 * time.Hour).Unix(), + Identifier: "email_verification", + } + + // Test AddVerificationRequest + created, err := provider.AddVerificationRequest(ctx, vr) + assert.NoError(t, err) + assert.NotNil(t, created) + + // Test GetVerificationRequestByToken + fetched, err := provider.GetVerificationRequestByToken(ctx, vr.Token) + assert.NoError(t, err) + assert.Equal(t, vr.Email, fetched.Email) + + // Test GetVerificationRequestByEmail + fetchedByEmail, err := provider.GetVerificationRequestByEmail(ctx, vr.Email, vr.Identifier) + assert.NoError(t, err) + assert.Equal(t, vr.Token, fetchedByEmail.Token) + + // Test ListVerificationRequests + requests, _, err := provider.ListVerificationRequests(ctx, &model.Pagination{ + Limit: 10, + Offset: 0, + }) + assert.NoError(t, err) + assert.NotNil(t, requests) + assert.Greater(t, len(requests), 0) + + // Test DeleteVerificationRequest + err = provider.DeleteVerificationRequest(ctx, vr) + assert.NoError(t, err) +} + +func testSessionOperations(t *testing.T, ctx context.Context, provider Provider) { + userID := uuid.New().String() + session := &schemas.Session{ + UserID: userID, + UserAgent: "test_user_agent", + IP: "127.0.0.1", + } + + // Test AddSession + err := provider.AddSession(ctx, session) + assert.NoError(t, err) + + // Test DeleteSession + err = provider.DeleteSession(ctx, userID) + assert.NoError(t, err) +} + +func testWebhookOperations(t *testing.T, ctx context.Context, provider Provider) { + webhook := &schemas.Webhook{ + EventName: "test_event", + EndPoint: "https://test.com/webhook", + Enabled: true, + } + + // Test AddWebhook + created, err := provider.AddWebhook(ctx, webhook) + assert.NoError(t, err) + assert.NotNil(t, created) + + // Test GetWebhookByID + fetched, err := provider.GetWebhookByID(ctx, created.ID) + assert.NoError(t, err) + assert.Equal(t, webhook.EventName, fetched.EventName) + + // Test GetWebhookByEventName + fetchedByEventName, err := provider.GetWebhookByEventName(ctx, webhook.EventName) + assert.NoError(t, err) + assert.NotNil(t, fetchedByEventName) + assert.Equal(t, created.ID, fetchedByEventName[0].ID) + + // Test UpdateWebhook + webhook.EndPoint = "https://test.com/webhook_updated" + updated, err := provider.UpdateWebhook(ctx, webhook) + assert.NoError(t, err) + assert.Equal(t, webhook.EndPoint, updated.EndPoint) + + // Test ListWebhook + webhooks, _, err := provider.ListWebhook(ctx, &model.Pagination{ + Limit: 10, + Offset: 0, + }) + assert.NoError(t, err) + assert.NotNil(t, webhooks) + assert.Greater(t, len(webhooks), 0) + + // Test ListWebhookLogs + logs, _, err := provider.ListWebhookLogs(ctx, &model.Pagination{ + Limit: 10, + Offset: 0, + }, webhook.ID) + assert.NoError(t, err) + assert.NotNil(t, logs) + assert.Empty(t, len(logs)) + + // Test DeleteWebhook + err = provider.DeleteWebhook(ctx, updated) + assert.NoError(t, err) +} + +func testEmailTemplateOperations(t *testing.T, ctx context.Context, provider Provider) { + template := &schemas.EmailTemplate{ + EventName: "test_event", + Template: "Test template", + Subject: "Test subject", + } + + // Test AddEmailTemplate + created, err := provider.AddEmailTemplate(ctx, template) + assert.NoError(t, err) + assert.NotNil(t, created) + + // Test GetEmailTemplateByID + fetched, err := provider.GetEmailTemplateByID(ctx, template.ID) + assert.NoError(t, err) + assert.Equal(t, template.EventName, fetched.EventName) + + // Test GetEmailTemplateByEventName + fetchedByEventName, err := provider.GetEmailTemplateByEventName(ctx, template.EventName) + assert.NoError(t, err) + assert.NotNil(t, fetchedByEventName) + assert.Equal(t, template.EventName, fetchedByEventName.EventName) + assert.Equal(t, created.ID, fetchedByEventName.ID) + + // Test UpdateEmailTemplate + template.Template = "Updated template" + updated, err := provider.UpdateEmailTemplate(ctx, template) + assert.NoError(t, err) + assert.Equal(t, template.Template, updated.Template) + + // Test ListEmailTemplate + templates, _, err := provider.ListEmailTemplate(ctx, &model.Pagination{ + Limit: 10, + Offset: 0, + }) + assert.NoError(t, err) + assert.NotNil(t, templates) + assert.Greater(t, len(templates), 0) + assert.Equal(t, template.EventName, templates[0].EventName) + assert.Equal(t, template.Template, templates[0].Template) + + // Test DeleteEmailTemplate + err = provider.DeleteEmailTemplate(ctx, updated) + assert.NoError(t, err) + + // Test GetEmailTemplateByEventName after delete + fetchedByEventName, err = provider.GetEmailTemplateByEventName(ctx, template.EventName) + assert.Error(t, err) + assert.Nil(t, fetchedByEventName) +} + +func testOTPOperations(t *testing.T, ctx context.Context, provider Provider) { + otp := &schemas.OTP{ + Email: "test_" + uuid.New().String() + "@test.com", + Otp: "123456", + ExpiresAt: time.Now().Add(5 * time.Minute).Unix(), + } + + // Test UpsertOTP + created, err := provider.UpsertOTP(ctx, otp) + assert.NoError(t, err) + assert.NotNil(t, created) + + // Test GetOTPByEmail + fetched, err := provider.GetOTPByEmail(ctx, otp.Email) + assert.NoError(t, err) + assert.Equal(t, otp.Otp, fetched.Otp) + + // For same email address, upsert should update the OTP + otp.Otp = "789012" + updated, err := provider.UpsertOTP(ctx, otp) + assert.NoError(t, err) + assert.NotNil(t, updated) + assert.Equal(t, otp.Otp, updated.Otp) + + // Test DeleteOTP + err = provider.DeleteOTP(ctx, updated) + assert.NoError(t, err) +} + +func testAuthenticatorOperations(t *testing.T, ctx context.Context, provider Provider) { + auth := &schemas.Authenticator{ + UserID: uuid.New().String(), + Method: constants.EnvKeyTOTPAuthenticator, + RecoveryCodes: refs.NewStringRef("test"), + Secret: "test_secret", + } + + // Test AddAuthenticator + created, err := provider.AddAuthenticator(ctx, auth) + assert.NoError(t, err) + assert.NotNil(t, created) + + // Test GetAuthenticatorDetailsByUserId + fetched, err := provider.GetAuthenticatorDetailsByUserId(ctx, auth.UserID, constants.EnvKeyTOTPAuthenticator) + assert.NoError(t, err) + assert.Equal(t, auth.Secret, fetched.Secret) + + // Test UpdateAuthenticator + auth.Secret = "updated_secret" + updated, err := provider.UpdateAuthenticator(ctx, auth) + assert.NoError(t, err) + assert.Equal(t, "updated_secret", updated.Secret) +} diff --git a/server/db/models/authenticators.go b/internal/storage/schemas/authenticators.go similarity index 98% rename from server/db/models/authenticators.go rename to internal/storage/schemas/authenticators.go index c5c05ed41..b0d65ba1d 100644 --- a/server/db/models/authenticators.go +++ b/internal/storage/schemas/authenticators.go @@ -1,4 +1,4 @@ -package models +package schemas // Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation diff --git a/server/db/models/email_templates.go b/internal/storage/schemas/email_templates.go similarity index 91% rename from server/db/models/email_templates.go rename to internal/storage/schemas/email_templates.go index f8be29259..0ee6c1ace 100644 --- a/server/db/models/email_templates.go +++ b/internal/storage/schemas/email_templates.go @@ -1,10 +1,10 @@ -package models +package schemas import ( "strings" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" ) // EmailTemplate model for database diff --git a/server/db/models/env.go b/internal/storage/schemas/env.go similarity index 98% rename from server/db/models/env.go rename to internal/storage/schemas/env.go index 8c39cd6bf..02215a74d 100644 --- a/server/db/models/env.go +++ b/internal/storage/schemas/env.go @@ -1,4 +1,4 @@ -package models +package schemas // Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation diff --git a/server/db/models/model.go b/internal/storage/schemas/model.go similarity index 98% rename from server/db/models/model.go rename to internal/storage/schemas/model.go index 908303716..9060d0d8e 100644 --- a/server/db/models/model.go +++ b/internal/storage/schemas/model.go @@ -1,4 +1,4 @@ -package models +package schemas // CollectionList / Tables available for authorizer in the database type CollectionList struct { diff --git a/server/db/models/otp.go b/internal/storage/schemas/otp.go similarity index 98% rename from server/db/models/otp.go rename to internal/storage/schemas/otp.go index ad84cf26e..4fb94ead6 100644 --- a/server/db/models/otp.go +++ b/internal/storage/schemas/otp.go @@ -1,4 +1,4 @@ -package models +package schemas const ( // FieldName email is the field name for email diff --git a/server/db/models/session.go b/internal/storage/schemas/session.go similarity index 98% rename from server/db/models/session.go rename to internal/storage/schemas/session.go index 8460c66d8..3400917f8 100644 --- a/server/db/models/session.go +++ b/internal/storage/schemas/session.go @@ -1,4 +1,4 @@ -package models +package schemas // Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation diff --git a/server/db/models/user.go b/internal/storage/schemas/user.go similarity index 96% rename from server/db/models/user.go rename to internal/storage/schemas/user.go index 3e4f354e8..a5a5a5f69 100644 --- a/server/db/models/user.go +++ b/internal/storage/schemas/user.go @@ -1,11 +1,11 @@ -package models +package schemas import ( "encoding/json" "strings" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" ) // Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation @@ -58,7 +58,7 @@ func (user *User) AsAPIUser() *model.User { Gender: user.Gender, Birthdate: user.Birthdate, PhoneNumber: user.PhoneNumber, - PhoneNumberVerified: &isPhoneVerified, + PhoneNumberVerified: isPhoneVerified, Picture: user.Picture, Roles: strings.Split(user.Roles, ","), RevokedTimestamp: user.RevokedTimestamp, diff --git a/server/db/models/verification_requests.go b/internal/storage/schemas/verification_requests.go similarity index 93% rename from server/db/models/verification_requests.go rename to internal/storage/schemas/verification_requests.go index 615452356..893ef2548 100644 --- a/server/db/models/verification_requests.go +++ b/internal/storage/schemas/verification_requests.go @@ -1,10 +1,10 @@ -package models +package schemas import ( "strings" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" ) // Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation diff --git a/server/db/models/webhook.go b/internal/storage/schemas/webhook.go similarity index 94% rename from server/db/models/webhook.go rename to internal/storage/schemas/webhook.go index 3faefc1bd..d70d2eb99 100644 --- a/server/db/models/webhook.go +++ b/internal/storage/schemas/webhook.go @@ -1,11 +1,11 @@ -package models +package schemas import ( "encoding/json" "strings" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" ) // Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation diff --git a/server/db/models/webhook_log.go b/internal/storage/schemas/webhook_log.go similarity index 92% rename from server/db/models/webhook_log.go rename to internal/storage/schemas/webhook_log.go index 0648487d8..97e90eb04 100644 --- a/server/db/models/webhook_log.go +++ b/internal/storage/schemas/webhook_log.go @@ -1,10 +1,10 @@ -package models +package schemas import ( "strings" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" + "github.com/authorizerdev/authorizer/internal/graph/model" + "github.com/authorizerdev/authorizer/internal/refs" ) // Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation diff --git a/internal/token/admin_token.go b/internal/token/admin_token.go new file mode 100644 index 000000000..cd530f01f --- /dev/null +++ b/internal/token/admin_token.go @@ -0,0 +1,47 @@ +package token + +import ( + "fmt" + + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/gin-gonic/gin" + "golang.org/x/crypto/bcrypt" +) + +// TODO remove if not used +// // CreateAdminAuthToken creates the admin token based on secret key +// func CreateAdminAuthToken(tokenType string, c *gin.Context) (string, error) { +// adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) +// if err != nil { +// return "", err +// } +// return crypto.EncryptPassword(adminSecret) +// } + +// GetAdminAuthToken helps in getting the admin token from the request cookie +func (p *provider) GetAdminAuthToken(gc *gin.Context) (string, error) { + token, err := cookie.GetAdminCookie(gc) + if err != nil || token == "" { + return "", fmt.Errorf("unauthorized") + } + err = bcrypt.CompareHashAndPassword([]byte(token), []byte(p.config.AdminSecret)) + if err != nil { + return "", fmt.Errorf(`unauthorized`) + } + + return token, nil +} + +// IsSuperAdmin checks if user is super admin +func (p *provider) IsSuperAdmin(gc *gin.Context) bool { + token, err := p.GetAdminAuthToken(gc) + if err != nil { + secret := gc.Request.Header.Get("x-authorizer-admin-secret") + if secret == "" { + return false + } + return secret == p.config.AdminSecret + } + + return token != "" +} diff --git a/server/token/auth_token.go b/internal/token/auth_token.go similarity index 57% rename from server/token/auth_token.go rename to internal/token/auth_token.go index 3fb4f3a91..8128c2db1 100644 --- a/server/token/auth_token.go +++ b/internal/token/auth_token.go @@ -8,29 +8,40 @@ import ( "strings" "time" - log "github.com/sirupsen/logrus" - "github.com/gin-gonic/gin" - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v4" "github.com/robertkrimen/otto" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/cookie" + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/parsers" + "github.com/authorizerdev/authorizer/internal/storage/schemas" + "github.com/authorizerdev/authorizer/internal/utils" ) +// AuthTokenConfig is the configuration for auth token +type AuthTokenConfig struct { + LoginMethod string + Nonce string + Code string + AtHash string + CodeHash string + ExpireTime string + User *schemas.User + HostName string + Roles []string + Scope []string +} + // JWTToken is a struct to hold JWT token and its expiration time type JWTToken struct { Token string `json:"token"` ExpiresAt int64 `json:"expires_at"` } -// Token object to hold the finger print and refresh token information -type Token struct { +// AuthToken object to hold the finger print, access token, id token and refresh token information +type AuthToken struct { FingerPrint string `json:"fingerprint"` // Session Token FingerPrintHash string `json:"fingerprint_hash"` @@ -52,13 +63,12 @@ type SessionData struct { } // CreateAuthToken creates a new auth token when userlogs in -func CreateAuthToken(gc *gin.Context, user *models.User, roles, scope []string, loginMethod, nonce string, code string) (*Token, error) { - hostname := parsers.GetHost(gc) - _, fingerPrintHash, sessionTokenExpiresAt, err := CreateSessionToken(user, nonce, roles, scope, loginMethod) +func (p *provider) CreateAuthToken(gc *gin.Context, cfg *AuthTokenConfig) (*AuthToken, error) { + _, fingerPrintHash, sessionTokenExpiresAt, err := p.CreateSessionToken(cfg) if err != nil { return nil, err } - accessToken, accessTokenExpiresAt, err := CreateAccessToken(user, roles, scope, hostname, nonce, loginMethod) + accessToken, accessTokenExpiresAt, err := p.CreateAccessToken(cfg) if err != nil { return nil, err } @@ -69,30 +79,30 @@ func CreateAuthToken(gc *gin.Context, user *models.User, roles, scope []string, // hashedToken := string(bs) atHashDigest := atHashBytes[0 : len(atHashBytes)/2] atHashString := base64.RawURLEncoding.EncodeToString(atHashDigest) - + cfg.AtHash = atHashString codeHashString := "" - if code != "" { + if cfg.Code != "" { codeHash := sha256.New() - codeHash.Write([]byte(code)) + codeHash.Write([]byte(cfg.Code)) codeHashBytes := codeHash.Sum(nil) codeHashDigest := codeHashBytes[0 : len(codeHashBytes)/2] codeHashString = base64.RawURLEncoding.EncodeToString(codeHashDigest) } - - idToken, idTokenExpiresAt, err := CreateIDToken(user, roles, hostname, nonce, atHashString, codeHashString, loginMethod) + cfg.CodeHash = codeHashString + idToken, idTokenExpiresAt, err := p.CreateIDToken(cfg) if err != nil { return nil, err } - res := &Token{ - FingerPrint: nonce, + res := &AuthToken{ + FingerPrint: cfg.Nonce, FingerPrintHash: fingerPrintHash, SessionTokenExpiresAt: sessionTokenExpiresAt, AccessToken: &JWTToken{Token: accessToken, ExpiresAt: accessTokenExpiresAt}, IDToken: &JWTToken{Token: idToken, ExpiresAt: idTokenExpiresAt}, } - if utils.StringSliceContains(scope, "offline_access") { - refreshToken, refreshTokenExpiresAt, err := CreateRefreshToken(user, roles, scope, hostname, nonce, loginMethod) + if utils.StringSliceContains(cfg.Scope, "offline_access") { + refreshToken, refreshTokenExpiresAt, err := p.CreateRefreshToken(cfg) if err != nil { return nil, err } @@ -104,19 +114,19 @@ func CreateAuthToken(gc *gin.Context, user *models.User, roles, scope []string, } // CreateSessionToken creates a new session token -func CreateSessionToken(user *models.User, nonce string, roles, scope []string, loginMethod string) (*SessionData, string, int64, error) { +func (p *provider) CreateSessionToken(cfg *AuthTokenConfig) (*SessionData, string, int64, error) { expiresAt := time.Now().AddDate(1, 0, 0).Unix() fingerPrintMap := &SessionData{ - Nonce: nonce, - Roles: roles, - Subject: user.ID, - Scope: scope, - LoginMethod: loginMethod, + Nonce: cfg.Nonce, + Roles: cfg.Roles, + Subject: cfg.User.ID, + Scope: cfg.Scope, + LoginMethod: cfg.LoginMethod, IssuedAt: time.Now().Unix(), ExpiresAt: expiresAt, } fingerPrintBytes, _ := json.Marshal(fingerPrintMap) - fingerPrintHash, err := crypto.EncryptAES(string(fingerPrintBytes)) + fingerPrintHash, err := crypto.EncryptAES(p.config.ClientSecret, string(fingerPrintBytes)) if err != nil { return nil, "", 0, err } @@ -125,29 +135,25 @@ func CreateSessionToken(user *models.User, nonce string, roles, scope []string, } // CreateRefreshToken util to create JWT token -func CreateRefreshToken(user *models.User, roles, scopes []string, hostname, nonce, loginMethod string) (string, int64, error) { +func (p *provider) CreateRefreshToken(cfg *AuthTokenConfig) (string, int64, error) { // expires in 1 year expiryBound := time.Hour * 8760 expiresAt := time.Now().Add(expiryBound).Unix() - clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) - if err != nil { - return "", 0, err - } customClaims := jwt.MapClaims{ - "iss": hostname, - "aud": clientID, - "sub": user.ID, + "iss": cfg.HostName, + "aud": p.config.ClientID, + "sub": cfg.User.ID, "exp": expiresAt, "iat": time.Now().Unix(), "token_type": constants.TokenTypeRefreshToken, - "roles": roles, - "scope": scopes, - "nonce": nonce, - "login_method": loginMethod, - "allowed_roles": strings.Split(user.Roles, ","), + "roles": cfg.Roles, + "scope": cfg.Scope, + "nonce": cfg.Nonce, + "login_method": cfg.LoginMethod, + "allowed_roles": strings.Split(cfg.User.Roles, ","), } - token, err := SignJWTToken(customClaims) + token, err := p.SignJWTToken(customClaims) if err != nil { return "", 0, err } @@ -157,41 +163,28 @@ func CreateRefreshToken(user *models.User, roles, scopes []string, hostname, non // CreateAccessToken util to create JWT token, based on // user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT -func CreateAccessToken(user *models.User, roles, scopes []string, hostName, nonce, loginMethod string) (string, int64, error) { - expireTime, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAccessTokenExpiryTime) - if err != nil { - return "", 0, err - } - expiryBound, err := utils.ParseDurationInSeconds(expireTime) +func (p *provider) CreateAccessToken(cfg *AuthTokenConfig) (string, int64, error) { + expiryBound, err := utils.ParseDurationInSeconds(cfg.ExpireTime) if err != nil { expiryBound = time.Minute * 30 } expiresAt := time.Now().Add(expiryBound).Unix() - clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) - if err != nil { - return "", 0, err - } customClaims := jwt.MapClaims{ - "iss": hostName, - "aud": clientID, - "nonce": nonce, - "sub": user.ID, + "iss": cfg.HostName, + "aud": p.config.ClientID, + "nonce": cfg.Nonce, + "sub": cfg.User.ID, "exp": expiresAt, "iat": time.Now().Unix(), "token_type": constants.TokenTypeAccessToken, - "scope": scopes, - "roles": roles, - "login_method": loginMethod, - "allowed_roles": strings.Split(user.Roles, ","), + "scope": cfg.Scope, + "roles": cfg.Roles, + "login_method": cfg.LoginMethod, + "allowed_roles": strings.Split(cfg.User.Roles, ","), } // check for the extra access token script - accessTokenScript, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyCustomAccessTokenScript) - if err != nil { - log.Debug("Failed to get custom access token script: ", err) - accessTokenScript = "" - } - if accessTokenScript != "" { - resUser := user.AsAPIUser() + if p.config.CustomAccessTokenScript != "" { + resUser := cfg.User.AsAPIUser() userBytes, _ := json.Marshal(&resUser) var userMap map[string]interface{} json.Unmarshal(userBytes, &userMap) @@ -202,16 +195,16 @@ func CreateAccessToken(user *models.User, roles, scopes []string, hostName, nonc var tokenPayload = %s; var customFunction = %s; var functionRes = JSON.stringify(customFunction(user, tokenPayload)); - `, string(userBytes), string(claimBytes), accessTokenScript)) + `, string(userBytes), string(claimBytes), p.config.CustomAccessTokenScript)) val, err := vm.Get("functionRes") if err != nil { - log.Debug("error getting custom access token script: ", err) + p.dependencies.Log.Debug().Err(err).Msg("error getting custom access token script") } else { extraPayload := make(map[string]interface{}) - err = json.Unmarshal([]byte(fmt.Sprintf("%s", val)), &extraPayload) + err = json.Unmarshal([]byte(fmt.Sprintf("%v", val)), &extraPayload) if err != nil { - log.Debug("error converting accessTokenScript response to map: ", err) + p.dependencies.Log.Debug().Err(err).Msg("error converting accessTokenScript response to map") } else { for k, v := range extraPayload { customClaims[k] = v @@ -219,7 +212,7 @@ func CreateAccessToken(user *models.User, roles, scopes []string, hostName, nonc } } } - token, err := SignJWTToken(customClaims) + token, err := p.SignJWTToken(customClaims) if err != nil { return "", 0, err } @@ -228,7 +221,7 @@ func CreateAccessToken(user *models.User, roles, scopes []string, hostName, nonc } // GetAccessToken returns the access token from the request (either from header or cookie) -func GetAccessToken(gc *gin.Context) (string, error) { +func (p *provider) GetAccessToken(gc *gin.Context) (string, error) { // try to check in auth header for cookie auth := gc.Request.Header.Get("Authorization") if auth == "" { @@ -249,37 +242,44 @@ func GetAccessToken(gc *gin.Context) (string, error) { } // Function to validate access token for authorizer apis (profile, update_profile) -func ValidateAccessToken(gc *gin.Context, accessToken string) (map[string]interface{}, error) { +func (p *provider) ValidateAccessToken(gc *gin.Context, accessToken string) (map[string]interface{}, error) { res := make(map[string]interface{}) if accessToken == "" { return res, fmt.Errorf(`unauthorized`) } - res, err := ParseJWTToken(accessToken) + res, err := p.ParseJWTToken(accessToken) if err != nil { return res, err } userID := res["sub"].(string) nonce := res["nonce"].(string) + loginMethod := res["login_method"] sessionKey := userID if loginMethod != nil && loginMethod != "" { sessionKey = loginMethod.(string) + ":" + userID } - token, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce) + token, err := p.dependencies.MemoryStoreProvider.GetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce) if nonce == "" || err != nil { + p.dependencies.Log.Debug().Err(err).Msgf("invalid access token: %v, key: %s", err, sessionKey+":"+constants.TokenTypeAccessToken+"_"+nonce) return res, fmt.Errorf(`unauthorized`) } if token != accessToken { + p.dependencies.Log.Debug().Msgf("invalid access token: %s, key: %s", err, sessionKey+":"+constants.TokenTypeAccessToken+"_"+nonce) return res, fmt.Errorf(`unauthorized`) } hostname := parsers.GetHost(gc) - if ok, err := ValidateJWTClaims(res, hostname, nonce, userID); !ok || err != nil { + if ok, err := p.ValidateJWTClaims(res, &AuthTokenConfig{ + HostName: hostname, + Nonce: nonce, + User: &schemas.User{ID: userID}, + }); !ok || err != nil { return res, err } @@ -291,36 +291,43 @@ func ValidateAccessToken(gc *gin.Context, accessToken string) (map[string]interf } // Function to validate refreshToken -func ValidateRefreshToken(gc *gin.Context, refreshToken string) (map[string]interface{}, error) { +func (p *provider) ValidateRefreshToken(gc *gin.Context, refreshToken string) (map[string]interface{}, error) { res := make(map[string]interface{}) if refreshToken == "" { return res, fmt.Errorf(`unauthorized`) } - res, err := ParseJWTToken(refreshToken) + res, err := p.ParseJWTToken(refreshToken) if err != nil { return res, err } userID := res["sub"].(string) nonce := res["nonce"].(string) + loginMethod := res["login_method"] sessionKey := userID if loginMethod != nil && loginMethod != "" { sessionKey = loginMethod.(string) + ":" + userID } - token, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+nonce) + token, err := p.dependencies.MemoryStoreProvider.GetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+nonce) if nonce == "" || err != nil { + p.dependencies.Log.Debug().Err(err).Msgf("invalid refresh token: %v, key: %s", err, sessionKey+":"+constants.TokenTypeRefreshToken+"_"+nonce) return res, fmt.Errorf(`unauthorized`) } if token != refreshToken { + p.dependencies.Log.Debug().Msgf("invalid refresh token: %s, key: %s", err, sessionKey+":"+constants.TokenTypeRefreshToken+"_"+nonce) return res, fmt.Errorf(`unauthorized`) } hostname := parsers.GetHost(gc) - if ok, err := ValidateJWTClaims(res, hostname, nonce, userID); !ok || err != nil { + if ok, err := p.ValidateJWTClaims(res, &AuthTokenConfig{ + HostName: hostname, + Nonce: nonce, + User: &schemas.User{ID: userID}, + }); !ok || err != nil { return res, err } @@ -331,12 +338,12 @@ func ValidateRefreshToken(gc *gin.Context, refreshToken string) (map[string]inte return res, nil } -func ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionData, error) { +func (p *provider) ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionData, error) { if encryptedSession == "" { return nil, fmt.Errorf(`unauthorized`) } - decryptedFingerPrint, err := crypto.DecryptAES(encryptedSession) + decryptedFingerPrint, err := crypto.DecryptAES(p.config.ClientSecret, encryptedSession) if err != nil { return nil, err } @@ -351,9 +358,9 @@ func ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionD if res.LoginMethod != "" { sessionStoreKey = res.LoginMethod + ":" + res.Subject } - token, err := memorystore.Provider.GetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+res.Nonce) + token, err := p.dependencies.MemoryStoreProvider.GetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+res.Nonce) if token == "" || err != nil { - log.Debugf("invalid browser session: %v, key: %s", err, sessionStoreKey+":"+constants.TokenTypeSessionToken+"_"+res.Nonce) + p.dependencies.Log.Debug().Err(err).Msgf("invalid session token: %v, key: %s", err, sessionStoreKey+":"+constants.TokenTypeSessionToken+"_"+res.Nonce) return nil, fmt.Errorf(`unauthorized`) } @@ -361,7 +368,7 @@ func ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionD return nil, fmt.Errorf(`unauthorized: invalid nonce`) } - if res.ExpiresAt < time.Now().Unix() { + if res.ExpiresAt <= time.Now().Unix() { return nil, fmt.Errorf(`unauthorized: token expired`) } @@ -372,48 +379,35 @@ func ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionD // user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT // For response_type (code) / authorization_code grant nonce should be empty // for implicit flow it should be present to verify with actual state -func CreateIDToken(user *models.User, roles []string, hostname, nonce, atHash, cHash, loginMethod string) (string, int64, error) { - expireTime, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAccessTokenExpiryTime) - if err != nil { - return "", 0, err - } - expiryBound, err := utils.ParseDurationInSeconds(expireTime) +func (p *provider) CreateIDToken(cfg *AuthTokenConfig) (string, int64, error) { + expiryBound, err := utils.ParseDurationInSeconds(cfg.ExpireTime) if err != nil { expiryBound = time.Minute * 30 } expiresAt := time.Now().Add(expiryBound).Unix() - resUser := user.AsAPIUser() + resUser := cfg.User.AsAPIUser() userBytes, _ := json.Marshal(&resUser) var userMap map[string]interface{} json.Unmarshal(userBytes, &userMap) - claimKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtRoleClaim) - if err != nil { - claimKey = "roles" - } - - clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) - if err != nil { - return "", 0, err - } customClaims := jwt.MapClaims{ - "iss": hostname, - "aud": clientID, - "sub": user.ID, - "exp": expiresAt, - "iat": time.Now().Unix(), - "token_type": constants.TokenTypeIdentityToken, - "allowed_roles": strings.Split(user.Roles, ","), - "login_method": loginMethod, - claimKey: roles, + "iss": cfg.HostName, + "aud": p.config.ClientID, + "sub": cfg.User.ID, + "exp": expiresAt, + "iat": time.Now().Unix(), + "token_type": constants.TokenTypeIdentityToken, + "allowed_roles": strings.Split(cfg.User.Roles, ","), + "login_method": cfg.LoginMethod, + p.config.JWTRoleClaim: cfg.Roles, } // split nonce to see if its authorization code grant method - if cHash != "" { - customClaims["at_hash"] = atHash - customClaims["c_hash"] = cHash + if cfg.CodeHash != "" { + customClaims["at_hash"] = cfg.AtHash + customClaims["c_hash"] = cfg.CodeHash } else { - customClaims["nonce"] = nonce - customClaims["at_hash"] = atHash + customClaims["nonce"] = cfg.Nonce + customClaims["at_hash"] = cfg.Nonce } for k, v := range userMap { if k != "roles" { @@ -421,12 +415,7 @@ func CreateIDToken(user *models.User, roles []string, hostname, nonce, atHash, c } } // check for the extra access token script - accessTokenScript, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyCustomAccessTokenScript) - if err != nil { - log.Debug("Failed to get custom access token script: ", err) - accessTokenScript = "" - } - if accessTokenScript != "" { + if p.config.CustomAccessTokenScript != "" { vm := otto.New() claimBytes, _ := json.Marshal(customClaims) vm.Run(fmt.Sprintf(` @@ -434,16 +423,16 @@ func CreateIDToken(user *models.User, roles []string, hostname, nonce, atHash, c var tokenPayload = %s; var customFunction = %s; var functionRes = JSON.stringify(customFunction(user, tokenPayload)); - `, string(userBytes), string(claimBytes), accessTokenScript)) + `, string(userBytes), string(claimBytes), p.config.CustomAccessTokenScript)) val, err := vm.Get("functionRes") if err != nil { - log.Debug("error getting custom access token script: ", err) + p.dependencies.Log.Debug().Err(err).Msg("error getting custom access token script") } else { extraPayload := make(map[string]interface{}) - err = json.Unmarshal([]byte(fmt.Sprintf("%s", val)), &extraPayload) + err = json.Unmarshal([]byte(fmt.Sprintf("%v", val)), &extraPayload) if err != nil { - log.Debug("error converting accessTokenScript response to map: ", err) + p.dependencies.Log.Debug().Err(err).Msg("error converting accessTokenScript response to map") } else { for k, v := range extraPayload { customClaims[k] = v @@ -452,7 +441,7 @@ func CreateIDToken(user *models.User, roles []string, hostname, nonce, atHash, c } } - token, err := SignJWTToken(customClaims) + token, err := p.SignJWTToken(customClaims) if err != nil { return "", 0, err } @@ -461,7 +450,7 @@ func CreateIDToken(user *models.User, roles []string, hostname, nonce, atHash, c } // GetIDToken returns the id token from the request header -func GetIDToken(gc *gin.Context) (string, error) { +func (p *provider) GetIDToken(gc *gin.Context) (string, error) { // try to check in auth header for cookie auth := gc.Request.Header.Get("Authorization") if auth == "" { @@ -489,23 +478,23 @@ type SessionOrAccessTokenData struct { } // GetUserIDFromSessionOrAccessToken returns the user id from the session or access token -func GetUserIDFromSessionOrAccessToken(gc *gin.Context) (*SessionOrAccessTokenData, error) { +func (p *provider) GetUserIDFromSessionOrAccessToken(gc *gin.Context) (*SessionOrAccessTokenData, error) { // First try to get the user id from the session isSession := true token, err := cookie.GetSession(gc) if err != nil || token == "" { - log.Debug("Failed to get session token: ", err) + p.dependencies.Log.Debug().Err(err).Msg("Failed to get session token") isSession = false - token, err = GetAccessToken(gc) + token, err = p.GetAccessToken(gc) if err != nil || token == "" { - log.Debug("Failed to get access token: ", err) + p.dependencies.Log.Debug().Err(err).Msg("Failed to get access token") return nil, fmt.Errorf(`unauthorized`) } } if isSession { - claims, err := ValidateBrowserSession(gc, token) + claims, err := p.ValidateBrowserSession(gc, token) if err != nil { - log.Debug("Failed to validate session token: ", err) + p.dependencies.Log.Debug().Err(err).Msg("Failed to validate session token") return nil, fmt.Errorf(`unauthorized`) } return &SessionOrAccessTokenData{ @@ -515,9 +504,9 @@ func GetUserIDFromSessionOrAccessToken(gc *gin.Context) (*SessionOrAccessTokenDa }, nil } // If not session, then validate the access token - claims, err := ValidateAccessToken(gc, token) + claims, err := p.ValidateAccessToken(gc, token) if err != nil { - log.Debug("Failed to validate access token: ", err) + p.dependencies.Log.Debug().Err(err).Msg("Failed to validate access token") return nil, fmt.Errorf(`unauthorized`) } return &SessionOrAccessTokenData{ diff --git a/internal/token/jwt.go b/internal/token/jwt.go new file mode 100644 index 000000000..ad869fd3c --- /dev/null +++ b/internal/token/jwt.go @@ -0,0 +1,125 @@ +package token + +import ( + "errors" + + "github.com/golang-jwt/jwt/v4" + + "github.com/authorizerdev/authorizer/internal/crypto" + "github.com/authorizerdev/authorizer/internal/refs" +) + +// SignJWTToken common util to sing jwt token +func (p *provider) SignJWTToken(jwtclaims jwt.MapClaims) (string, error) { + signingMethod := jwt.GetSigningMethod(p.config.JWTType) + if signingMethod == nil { + return "", errors.New("unsupported signing method") + } + t := jwt.New(signingMethod) + if t == nil { + return "", errors.New("unsupported signing method") + } + t.Claims = jwtclaims + + switch signingMethod { + case jwt.SigningMethodHS256, jwt.SigningMethodHS384, jwt.SigningMethodHS512: + return t.SignedString([]byte(p.config.JWTSecret)) + case jwt.SigningMethodRS256, jwt.SigningMethodRS384, jwt.SigningMethodRS512: + key, err := crypto.ParseRsaPrivateKeyFromPemStr(p.config.JWTPublicKey) + if err != nil { + return "", err + } + return t.SignedString(key) + case jwt.SigningMethodES256, jwt.SigningMethodES384, jwt.SigningMethodES512: + key, err := crypto.ParseEcdsaPrivateKeyFromPemStr(p.config.JWTPrivateKey) + if err != nil { + return "", err + } + + return t.SignedString(key) + default: + return "", errors.New("unsupported signing method") + } +} + +// ParseJWTToken common util to parse jwt token +func (p *provider) ParseJWTToken(token string) (jwt.MapClaims, error) { + signingMethod := jwt.GetSigningMethod(p.config.JWTType) + + var claims jwt.MapClaims + var err error + switch signingMethod { + case jwt.SigningMethodHS256, jwt.SigningMethodHS384, jwt.SigningMethodHS512: + _, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { + return []byte(p.config.JWTSecret), nil + }) + case jwt.SigningMethodRS256, jwt.SigningMethodRS384, jwt.SigningMethodRS512: + _, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { + key, err := crypto.ParseRsaPublicKeyFromPemStr(p.config.JWTPublicKey) + if err != nil { + return nil, err + } + return key, nil + }) + case jwt.SigningMethodES256, jwt.SigningMethodES384, jwt.SigningMethodES512: + _, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { + key, err := crypto.ParseEcdsaPublicKeyFromPemStr(p.config.JWTSecret) + if err != nil { + return nil, err + } + return key, nil + }) + default: + err = errors.New("unsupported signing method") + } + if err != nil { + return claims, err + } + + // claim parses exp & iat into float 64 with e^10, + // but we expect it to be int64 + // hence we need to assert interface and convert to int64 + intExp := int64(claims["exp"].(float64)) + intIat := int64(claims["iat"].(float64)) + claims["exp"] = intExp + claims["iat"] = intIat + + return claims, nil +} + +// ValidateJWTClaims common util to validate claims +func (p *provider) ValidateJWTClaims(claims jwt.MapClaims, authTokenConfig *AuthTokenConfig) (bool, error) { + if claims["aud"] != p.config.ClientID { + return false, errors.New("invalid audience") + } + + if claims["nonce"] != authTokenConfig.Nonce { + return false, errors.New("invalid nonce") + } + + if claims["iss"] != authTokenConfig.HostName { + return false, errors.New("invalid issuer") + } + + if claims["sub"] != authTokenConfig.User.ID && claims["sub"] != refs.StringValue(authTokenConfig.User.Email) { + return false, errors.New("invalid subject") + } + + return true, nil +} + +// ValidateJWTTokenWithoutNonce common util to validate claims without nonce +func (p *provider) ValidateJWTTokenWithoutNonce(claims jwt.MapClaims, authTokenConfig *AuthTokenConfig) (bool, error) { + if claims["aud"] != p.config.ClientID { + return false, errors.New("invalid audience") + } + + if claims["iss"] != authTokenConfig.HostName { + return false, errors.New("invalid issuer") + } + + if claims["sub"] != authTokenConfig.User.ID { + return false, errors.New("invalid subject") + } + return true, nil +} diff --git a/internal/token/provider.go b/internal/token/provider.go new file mode 100644 index 000000000..f6fa29f08 --- /dev/null +++ b/internal/token/provider.go @@ -0,0 +1,95 @@ +package token + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt/v4" + "github.com/rs/zerolog" + + "github.com/authorizerdev/authorizer/internal/config" + "github.com/authorizerdev/authorizer/internal/memory_store" +) + +// Dependencies struct for twilio provider +type Dependencies struct { + Log *zerolog.Logger + MemoryStoreProvider memory_store.Provider +} + +type provider struct { + config *config.Config + dependencies *Dependencies +} + +var _ Provider = &provider{} + +// Provider interface for token provider +type Provider interface { + // CreateAccessToken creates an access token + CreateAccessToken(cfg *AuthTokenConfig) (string, int64, error) + // CreateAuthToken creates all types of auth token + CreateAuthToken(gc *gin.Context, cfg *AuthTokenConfig) (*AuthToken, error) + // CreateIDToken creates an id token + CreateIDToken(cfg *AuthTokenConfig) (string, int64, error) + // CreateRefreshToken creates a refresh token + CreateRefreshToken(cfg *AuthTokenConfig) (string, int64, error) + // CreateSessionToken creates a session token + CreateSessionToken(cfg *AuthTokenConfig) (*SessionData, string, int64, error) + // CreateVerificationToken creates a verification token + CreateVerificationToken(authTokenConfig *AuthTokenConfig, redirectURL string, tokenType string) (string, error) + // GetAd + GetAdminAuthToken(gc *gin.Context) (string, error) + // GetAccessToken gets access token from request + GetAccessToken(gc *gin.Context) (string, error) + // GetIDToken gets id token from request + GetIDToken(gc *gin.Context) (string, error) + // GetUserIDFromSessionOrAccessToken gets user id from session or access token + GetUserIDFromSessionOrAccessToken(gc *gin.Context) (*SessionOrAccessTokenData, error) + // IsSuperAdmin checks if user is super admin + IsSuperAdmin(gc *gin.Context) bool + // ParseJWTToken parses jwt token + ParseJWTToken(token string) (jwt.MapClaims, error) + // SignJWTToken signs jwt token + SignJWTToken(jwtclaims jwt.MapClaims) (string, error) + // ValidateAccessToken validates access token + ValidateAccessToken(gc *gin.Context, accessToken string) (map[string]interface{}, error) + // ValidateAdminToken validates session token + ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionData, error) + // ValidateJWTClaims validates jwt claims + ValidateJWTClaims(claims jwt.MapClaims, authTokenConfig *AuthTokenConfig) (bool, error) + // ValidateJWTTokenWithoutNonce validates jwt token without nonce + ValidateJWTTokenWithoutNonce(claims jwt.MapClaims, authTokenConfig *AuthTokenConfig) (bool, error) + // ValidateRefreshToken validates refresh token + ValidateRefreshToken(gc *gin.Context, refreshToken string) (map[string]interface{}, error) +} + +// New returns a new token provider +func New(cfg *config.Config, deps *Dependencies) (Provider, error) { + if cfg.JWTType == "" { + deps.Log.Debug().Msg("missing jwt type") + return nil, fmt.Errorf("missing jwt type") + } + signingMethod := jwt.GetSigningMethod(cfg.JWTType) + switch signingMethod { + case jwt.SigningMethodHS256, jwt.SigningMethodHS384, jwt.SigningMethodHS512: + if cfg.JWTSecret == "" { + deps.Log.Debug().Msg("missing jwt secret") + return nil, fmt.Errorf("missing jwt secret") + } + case jwt.SigningMethodRS256, jwt.SigningMethodRS384, jwt.SigningMethodRS512, + jwt.SigningMethodES256, jwt.SigningMethodES384, jwt.SigningMethodES512: + if cfg.JWTPrivateKey == "" { + deps.Log.Debug().Msg("missing jwt private key") + return nil, fmt.Errorf("missing jwt private key") + } + if cfg.JWTPublicKey == "" { + deps.Log.Debug().Msg("missing jwt public key") + return nil, fmt.Errorf("missing jwt public key") + } + } + return &provider{ + config: cfg, + dependencies: deps, + }, nil +} diff --git a/internal/token/verification_token.go b/internal/token/verification_token.go new file mode 100644 index 000000000..54f737c9e --- /dev/null +++ b/internal/token/verification_token.go @@ -0,0 +1,23 @@ +package token + +import ( + "time" + + "github.com/golang-jwt/jwt/v4" +) + +// CreateVerificationToken creates a verification JWT token +func (p *provider) CreateVerificationToken(authTokenConfig *AuthTokenConfig, redirectURL, tokenType string) (string, error) { + claims := jwt.MapClaims{ + "iss": authTokenConfig.HostName, + "aud": p.config.ClientID, + "sub": authTokenConfig.User.Email, + "exp": time.Now().Add(time.Minute * 30).Unix(), + "iat": time.Now().Unix(), + "token_type": tokenType, + "nonce": authTokenConfig.Nonce, + "redirect_uri": redirectURL, + } + + return p.SignJWTToken(claims) +} diff --git a/server/tools.go b/internal/tools.go similarity index 100% rename from server/tools.go rename to internal/tools.go diff --git a/server/types/interface_slice.go b/internal/types/interface_slice.go similarity index 100% rename from server/types/interface_slice.go rename to internal/types/interface_slice.go diff --git a/server/utils/common.go b/internal/utils/common.go similarity index 88% rename from server/utils/common.go rename to internal/utils/common.go index b5f81b6ca..c0602a7d8 100644 --- a/server/utils/common.go +++ b/internal/utils/common.go @@ -3,8 +3,7 @@ package utils import ( "reflect" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/internal/config" ) // StringSliceContains checks if a string slice contains a particular string @@ -63,15 +62,9 @@ func ConvertInterfaceToStringSlice(slice interface{}) []string { } // GetOrganization to get organization object -func GetOrganization() map[string]interface{} { - orgLogo, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo) - if err != nil { - return nil - } - orgName, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName) - if err != nil { - return nil - } +func GetOrganization(cfg *config.Config) map[string]interface{} { + orgLogo := cfg.OrganizationLogo + orgName := cfg.OrganizationName organization := map[string]interface{}{ "name": orgName, "logo": orgLogo, diff --git a/server/utils/file.go b/internal/utils/file.go similarity index 100% rename from server/utils/file.go rename to internal/utils/file.go diff --git a/server/utils/generate_otp.go b/internal/utils/generate_otp.go similarity index 100% rename from server/utils/generate_otp.go rename to internal/utils/generate_otp.go diff --git a/server/utils/generate_totp_recovery_code.go b/internal/utils/generate_totp_recovery_code.go similarity index 100% rename from server/utils/generate_totp_recovery_code.go rename to internal/utils/generate_totp_recovery_code.go diff --git a/server/utils/gin_context.go b/internal/utils/gin_context.go similarity index 100% rename from server/utils/gin_context.go rename to internal/utils/gin_context.go diff --git a/server/utils/nonce.go b/internal/utils/nonce.go similarity index 51% rename from server/utils/nonce.go rename to internal/utils/nonce.go index 311b3259f..6cffa1e10 100644 --- a/server/utils/nonce.go +++ b/internal/utils/nonce.go @@ -3,32 +3,26 @@ package utils import ( "github.com/google/uuid" - "github.com/authorizerdev/authorizer/server/crypto" + "github.com/authorizerdev/authorizer/internal/crypto" ) -// GenerateNonce generats random nonce string and returns +// GenerateNonce generates random nonce string and returns // the nonce string, nonce hash, error func GenerateNonce() (string, string, error) { nonce := uuid.New().String() - nonceHash, err := crypto.EncryptAES(nonce) - if err != nil { - return "", "", err - } - return nonce, nonceHash, err + nonceHash := crypto.EncryptB64(nonce) + return nonce, nonceHash, nil } // EncryptNonce nonce string func EncryptNonce(nonce string) (string, error) { - nonceHash, err := crypto.EncryptAES(nonce) - if err != nil { - return "", err - } - return nonceHash, err + nonceHash := crypto.EncryptB64(nonce) + return nonceHash, nil } // DecryptNonce nonce string func DecryptNonce(nonceHash string) (string, error) { - nonce, err := crypto.DecryptAES(nonceHash) + nonce, err := crypto.DecryptB64(nonceHash) if err != nil { return "", err } diff --git a/server/utils/pagination.go b/internal/utils/pagination.go similarity index 74% rename from server/utils/pagination.go rename to internal/utils/pagination.go index 384eebdb8..35aba6b0b 100644 --- a/server/utils/pagination.go +++ b/internal/utils/pagination.go @@ -1,13 +1,13 @@ package utils import ( - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/internal/constants" + "github.com/authorizerdev/authorizer/internal/graph/model" ) // GetPagination helps getting pagination data from paginated input // also returns default limit and offset if pagination data is not present -func GetPagination(paginatedInput *model.PaginatedInput) *model.Pagination { +func GetPagination(paginatedInput *model.PaginatedRequest) *model.Pagination { limit := int64(constants.DefaultLimit) page := int64(1) if paginatedInput != nil && paginatedInput.Pagination != nil { diff --git a/server/utils/parser.go b/internal/utils/parser.go similarity index 100% rename from server/utils/parser.go rename to internal/utils/parser.go diff --git a/server/utils/pkce.go b/internal/utils/pkce.go similarity index 100% rename from server/utils/pkce.go rename to internal/utils/pkce.go diff --git a/server/utils/request_info.go b/internal/utils/request_info.go similarity index 100% rename from server/utils/request_info.go rename to internal/utils/request_info.go diff --git a/server/utils/response.go b/internal/utils/response.go similarity index 100% rename from server/utils/response.go rename to internal/utils/response.go diff --git a/server/validators/common.go b/internal/validators/common.go similarity index 100% rename from server/validators/common.go rename to internal/validators/common.go diff --git a/server/validators/email.go b/internal/validators/email.go similarity index 100% rename from server/validators/email.go rename to internal/validators/email.go diff --git a/server/validators/email_template.go b/internal/validators/email_template.go similarity index 89% rename from server/validators/email_template.go rename to internal/validators/email_template.go index 7b5469b60..0634b0eb9 100644 --- a/server/validators/email_template.go +++ b/internal/validators/email_template.go @@ -1,6 +1,6 @@ package validators -import "github.com/authorizerdev/authorizer/server/constants" +import "github.com/authorizerdev/authorizer/internal/constants" // IsValidEmailTemplateEventName function to validate email template events func IsValidEmailTemplateEventName(eventName string) bool { diff --git a/server/validators/password.go b/internal/validators/password.go similarity index 72% rename from server/validators/password.go rename to internal/validators/password.go index 282dd7596..217993e6e 100644 --- a/server/validators/password.go +++ b/internal/validators/password.go @@ -2,9 +2,6 @@ package validators import ( "errors" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" ) // ValidatePassword to validate the password against the following policy @@ -14,18 +11,11 @@ import ( // at least one lower case letter // at least one digit // at least one special character -func IsValidPassword(password string) error { +func IsValidPassword(password string, isStrongPasswordDisabled bool) error { if len(password) < 6 || len(password) > 36 { return errors.New("password must be of minimum 6 characters and maximum 36 characters") } - // if strong password is disabled - // just check for min 6 chars & max 36 - isStrongPasswordDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableStrongPassword) - if isStrongPasswordDisabled { - return nil - } - hasUpperCase := false hasLowerCase := false hasDigit := false diff --git a/server/validators/roles.go b/internal/validators/roles.go similarity index 81% rename from server/validators/roles.go rename to internal/validators/roles.go index 9a43a51bb..8a2a3b484 100644 --- a/server/validators/roles.go +++ b/internal/validators/roles.go @@ -1,6 +1,6 @@ package validators -import "github.com/authorizerdev/authorizer/server/utils" +import "github.com/authorizerdev/authorizer/internal/utils" // IsValidRoles validates roles func IsValidRoles(userRoles []string, roles []string) bool { diff --git a/server/validators/url.go b/internal/validators/url.go similarity index 68% rename from server/validators/url.go rename to internal/validators/url.go index 6f8a15fe3..505f3fedd 100644 --- a/server/validators/url.go +++ b/internal/validators/url.go @@ -4,19 +4,14 @@ import ( "regexp" "strings" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" + "github.com/authorizerdev/authorizer/internal/parsers" ) // IsValidOrigin validates origin based on ALLOWED_ORIGINS -func IsValidOrigin(url string) bool { - allowedOriginsString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAllowedOrigins) - allowedOrigins := []string{} - if err != nil { +func IsValidOrigin(url string, allowedOriginsConfig []string) bool { + allowedOrigins := allowedOriginsConfig + if len(allowedOrigins) == 0 { allowedOrigins = []string{"*"} - } else { - allowedOrigins = strings.Split(allowedOriginsString, ",") } if len(allowedOrigins) == 1 && allowedOrigins[0] == "*" { return true diff --git a/server/validators/verification_requests.go b/internal/validators/verification_requests.go similarity index 86% rename from server/validators/verification_requests.go rename to internal/validators/verification_requests.go index 48c918350..17a64fd8b 100644 --- a/server/validators/verification_requests.go +++ b/internal/validators/verification_requests.go @@ -1,6 +1,6 @@ package validators -import "github.com/authorizerdev/authorizer/server/constants" +import "github.com/authorizerdev/authorizer/internal/constants" // IsValidVerificationIdentifier validates verification identifier that is used to identify // the type of verification request diff --git a/server/validators/webhook.go b/internal/validators/webhook.go similarity index 89% rename from server/validators/webhook.go rename to internal/validators/webhook.go index eb2476bc3..b8c920ab1 100644 --- a/server/validators/webhook.go +++ b/internal/validators/webhook.go @@ -1,6 +1,6 @@ package validators -import "github.com/authorizerdev/authorizer/server/constants" +import "github.com/authorizerdev/authorizer/internal/constants" // IsValidWebhookEventName to validate webhook event name func IsValidWebhookEventName(eventName string) bool { diff --git a/main.go b/main.go new file mode 100644 index 000000000..161807851 --- /dev/null +++ b/main.go @@ -0,0 +1,7 @@ +package main + +import "github.com/authorizerdev/authorizer/cmd" + +func main() { + cmd.RootCmd.Execute() +} diff --git a/scripts/build-mac.sh b/scripts/build-mac.sh deleted file mode 100644 index e41d5298e..000000000 --- a/scripts/build-mac.sh +++ /dev/null @@ -1,18 +0,0 @@ -VERSION="$1" -make clean && make build-app && CGO_ENABLED=1 VERSION=${VERSION} make -FILE_NAME=authorizer-${VERSION}-darwin-amd64.tar.gz -tar cvfz ${FILE_NAME} .env app/build build templates dashboard/build -AUTH="Authorization: token $GITHUB_TOKEN" -RELASE_INFO=$(curl -sH "$AUTH" https://api.github.com/repos/authorizerdev/authorizer/releases/tags/${VERSION}) -echo $RELASE_INFO - -eval $(echo "$RELASE_INFO" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=') -[ "$id" ] || { echo "Error: Failed to get release id for tag: $VERSION"; echo "$RELASE_INFO" | awk 'length($0)<100' >&2; exit 1; } -echo $id -GH_ASSET="https://uploads.github.com/repos/authorizerdev/authorizer/releases/$id/assets?name=$(basename $FILE_NAME)" - -echo $GH_ASSET - -curl -H $AUTH -H "Content-Type: $(file -b --mime-type $FILE_NAME)" --data-binary @$FILE_NAME $GH_ASSET - -curl "$GITHUB_OAUTH_BASIC" --data-binary @"$FILE_NAME" -H "Authorization: token $GITHUB_TOKEN" -H "Content-Type: application/octet-stream" $GH_ASSET diff --git a/server/authenticators/providers/providers.go b/server/authenticators/providers/providers.go deleted file mode 100644 index 7f43ef5c7..000000000 --- a/server/authenticators/providers/providers.go +++ /dev/null @@ -1,25 +0,0 @@ -package providers - -import "context" - -// AuthenticatorConfig defines authenticator config -type AuthenticatorConfig struct { - // ScannerImage is the base64 of QR code image - ScannerImage string - // Secrets is the secret key - Secret string - // RecoveryCode is the list of recovery codes - RecoveryCodes []string - // RecoveryCodeMap is the map of recovery codes - RecoveryCodeMap map[string]bool -} - -// Provider defines authenticators provider -type Provider interface { - // Generate totp: to generate totp, store secret into db and returns base64 of QR code image - Generate(ctx context.Context, id string) (*AuthenticatorConfig, error) - // Validate totp: user passcode with secret stored in our db - Validate(ctx context.Context, passcode string, userID string) (bool, error) - // ValidateRecoveryCode totp: allows user to validate using recovery code incase if they lost their device - ValidateRecoveryCode(ctx context.Context, recoveryCode, userID string) (bool, error) -} diff --git a/server/authenticators/providers/totp/provider.go b/server/authenticators/providers/totp/provider.go deleted file mode 100644 index f3bd9da3b..000000000 --- a/server/authenticators/providers/totp/provider.go +++ /dev/null @@ -1,23 +0,0 @@ -package totp - -import ( - "context" -) - -type provider struct { - ctx context.Context -} - -// TOTPConfig defines totp config -type TOTPConfig struct { - ScannerImage string - Secret string -} - -// NewProvider returns a new totp provider -func NewProvider() (*provider, error) { - ctx := context.Background() - return &provider{ - ctx: ctx, - }, nil -} diff --git a/server/authenticators/totp_store.go b/server/authenticators/totp_store.go deleted file mode 100644 index 268e66eb7..000000000 --- a/server/authenticators/totp_store.go +++ /dev/null @@ -1,26 +0,0 @@ -package authenticators - -import ( - "github.com/authorizerdev/authorizer/server/authenticators/providers" - "github.com/authorizerdev/authorizer/server/authenticators/providers/totp" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -// Provider is the global authenticators provider. -var Provider providers.Provider - -// InitTOTPStore initializes the TOTP authenticator store if it's not disabled in the environment variables. -// It sets the global Provider variable to a new TOTP provider. -func InitTOTPStore() error { - var err error - isTOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin) - - if !isTOTPEnvServiceDisabled { - Provider, err = totp.NewProvider() - if err != nil { - return err - } - } - return nil -} diff --git a/server/constants/env.go b/server/constants/env.go deleted file mode 100644 index 983a87fe6..000000000 --- a/server/constants/env.go +++ /dev/null @@ -1,215 +0,0 @@ -package constants - -var VERSION = "0.0.1" - -const ( - // TestEnv is used for testing - TestEnv = "test" - // EnvKeyEnv key for env variable ENV - EnvKeyEnv = "ENV" - // EnvKeyEnvPath key for cli arg variable ENV_PATH - EnvKeyEnvPath = "ENV_PATH" - // EnvKeyAuthorizerURL key for env variable AUTHORIZER_URL - EnvKeyAuthorizerURL = "AUTHORIZER_URL" - // EnvKeyPort key for env variable PORT - EnvKeyPort = "PORT" - // EnvKeyAccessTokenExpiryTime key for env variable ACCESS_TOKEN_EXPIRY_TIME - EnvKeyAccessTokenExpiryTime = "ACCESS_TOKEN_EXPIRY_TIME" - // EnvKeyAdminSecret key for env variable ADMIN_SECRET - EnvKeyAdminSecret = "ADMIN_SECRET" - // EnvKeyDatabaseType key for env variable DATABASE_TYPE - EnvKeyDatabaseType = "DATABASE_TYPE" - // EnvKeyDatabaseURL key for env variable DATABASE_URL - EnvKeyDatabaseURL = "DATABASE_URL" - // EnvAwsRegion key for env variable AWS REGION - EnvAwsRegion = "AWS_REGION" - // EnvAwsAccessKeyID key for env variable AWS_ACCESS_KEY_ID - EnvAwsAccessKeyID = "AWS_ACCESS_KEY_ID" - // EnvAwsAccessKey key for env variable AWS_SECRET_ACCESS_KEY - EnvAwsSecretAccessKey = "AWS_SECRET_ACCESS_KEY" - // EnvKeyDatabaseName key for env variable DATABASE_NAME - EnvKeyDatabaseName = "DATABASE_NAME" - // EnvKeyDatabaseUsername key for env variable DATABASE_USERNAME - EnvKeyDatabaseUsername = "DATABASE_USERNAME" - // EnvKeyDatabasePassword key for env variable DATABASE_PASSWORD - EnvKeyDatabasePassword = "DATABASE_PASSWORD" - // EnvKeyDatabasePort key for env variable DATABASE_PORT - EnvKeyDatabasePort = "DATABASE_PORT" - // EnvKeyDatabaseHost key for env variable DATABASE_HOST - EnvKeyDatabaseHost = "DATABASE_HOST" - // EnvKeyDatabaseCert key for env variable DATABASE_CERT - EnvKeyDatabaseCert = "DATABASE_CERT" - // EnvKeyDatabaseCertKey key for env variable DATABASE_KEY - EnvKeyDatabaseCertKey = "DATABASE_CERT_KEY" - // EnvKeyDatabaseCACert key for env variable 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 = "SMTP_HOST" - // EnvKeySmtpPort key for env variable SMTP_PORT - EnvKeySmtpPort = "SMTP_PORT" - // EnvKeySmtpUsername key for env variable SMTP_USERNAME - EnvKeySmtpUsername = "SMTP_USERNAME" - // EnvKeySmtpPassword key for env variable SMTP_PASSWORD - EnvKeySmtpPassword = "SMTP_PASSWORD" - // EnvKeySmtpLocalName key for env variable SMTP_LOCAL_NAME - EnvKeySmtpLocalName = "SMTP_LOCAL_NAME" - // EnvKeySenderEmail key for env variable SENDER_EMAIL - EnvKeySenderEmail = "SENDER_EMAIL" - // EnvKeySenderName key for env variable SENDER_NAME - EnvKeySenderName = "SENDER_NAME" - // EnvKeyIsEmailServiceEnabled key for env variable IS_EMAIL_SERVICE_ENABLED - EnvKeyIsEmailServiceEnabled = "IS_EMAIL_SERVICE_ENABLED" - // EnvKeyIsSMSServiceEnabled key for env variable IS_SMS_SERVICE_ENABLED - EnvKeyIsSMSServiceEnabled = "IS_SMS_SERVICE_ENABLED" - // EnvKeyAppCookieSecure key for env variable APP_COOKIE_SECURE - EnvKeyAppCookieSecure = "APP_COOKIE_SECURE" - // EnvKeyAdminCookieSecure key for env variable ADMIN_COOKIE_SECURE - EnvKeyAdminCookieSecure = "ADMIN_COOKIE_SECURE" - // EnvKeyJwtType key for env variable JWT_TYPE - EnvKeyJwtType = "JWT_TYPE" - // EnvKeyJwtSecret key for env variable JWT_SECRET - EnvKeyJwtSecret = "JWT_SECRET" - // EnvKeyJwtPrivateKey key for env variable JWT_PRIVATE_KEY - EnvKeyJwtPrivateKey = "JWT_PRIVATE_KEY" - // EnvKeyJwtPublicKey key for env variable JWT_PUBLIC_KEY - EnvKeyJwtPublicKey = "JWT_PUBLIC_KEY" - // EnvKeyAppURL key for env variable APP_URL - EnvKeyAppURL = "APP_URL" - // EnvKeyRedisURL key for env variable REDIS_URL - EnvKeyRedisURL = "REDIS_URL" - // EnvKeyResetPasswordURL key for env variable RESET_PASSWORD_URL - EnvKeyResetPasswordURL = "RESET_PASSWORD_URL" - // EnvKeyJwtRoleClaim key for env variable JWT_ROLE_CLAIM - EnvKeyJwtRoleClaim = "JWT_ROLE_CLAIM" - // EnvKeyGoogleClientID key for env variable GOOGLE_CLIENT_ID - EnvKeyGoogleClientID = "GOOGLE_CLIENT_ID" - // EnvKeyGoogleClientSecret key for env variable GOOGLE_CLIENT_SECRET - EnvKeyGoogleClientSecret = "GOOGLE_CLIENT_SECRET" - // EnvKeyGithubClientID key for env variable GITHUB_CLIENT_ID - EnvKeyGithubClientID = "GITHUB_CLIENT_ID" - // EnvKeyGithubClientSecret key for env variable GITHUB_CLIENT_SECRET - EnvKeyGithubClientSecret = "GITHUB_CLIENT_SECRET" - // EnvKeyFacebookClientID key for env variable FACEBOOK_CLIENT_ID - EnvKeyFacebookClientID = "FACEBOOK_CLIENT_ID" - // EnvKeyFacebookClientSecret key for env variable FACEBOOK_CLIENT_SECRET - EnvKeyFacebookClientSecret = "FACEBOOK_CLIENT_SECRET" - // EnvKeyLinkedinClientID key for env variable LINKEDIN_CLIENT_ID - EnvKeyLinkedInClientID = "LINKEDIN_CLIENT_ID" - // EnvKeyLinkedinClientSecret key for env variable LINKEDIN_CLIENT_SECRET - EnvKeyLinkedInClientSecret = "LINKEDIN_CLIENT_SECRET" - // EnvKeyAppleClientID key for env variable APPLE_CLIENT_ID - EnvKeyAppleClientID = "APPLE_CLIENT_ID" - // EnvKeyAppleClientSecret key for env variable APPLE_CLIENT_SECRET - EnvKeyAppleClientSecret = "APPLE_CLIENT_SECRET" - // EnvKeyDiscordClientID key for env variable DISCORD_CLIENT_ID - EnvKeyDiscordClientID = "DISCORD_CLIENT_ID" - // EnvKeyDiscordClientSecret key for env variable DISCORD_CLIENT_SECRET - EnvKeyDiscordClientSecret = "DISCORD_CLIENT_SECRET" - // EnvKeyTwitterClientID key for env variable TWITTER_CLIENT_ID - EnvKeyTwitterClientID = "TWITTER_CLIENT_ID" - // EnvKeyTwitterClientSecret key for env variable 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" - // EnvKeyTwitchClientID key for env variable TWITCH_CLIENT_ID - EnvKeyTwitchClientID = "TWITCH_CLIENT_ID" - // EnvKeyTwitchClientSecret key for env variable TWITCH_CLIENT_SECRET - EnvKeyTwitchClientSecret = "TWITCH_CLIENT_SECRET" - // EnvKeyRobloxClientID key for env variable ROBLOX_CLIENT_ID - EnvKeyRobloxClientID = "ROBLOX_CLIENT_ID" - // EnvKeyRobloxClientSecret key for env variable ROBLOX_CLIENT_SECRET - EnvKeyRobloxClientSecret = "ROBLOX_CLIENT_SECRET" - // EnvKeyOrganizationName key for env variable ORGANIZATION_NAME - EnvKeyOrganizationName = "ORGANIZATION_NAME" - // EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO - EnvKeyOrganizationLogo = "ORGANIZATION_LOGO" - // EnvKeyCustomAccessTokenScript key for env variable CUSTOM_ACCESS_TOKEN_SCRIPT - EnvKeyCustomAccessTokenScript = "CUSTOM_ACCESS_TOKEN_SCRIPT" - - // Not Exposed Keys - // EnvKeyClientID key for env variable CLIENT_ID - EnvKeyClientID = "CLIENT_ID" - // EnvKeyClientSecret key for env variable CLIENT_SECRET - EnvKeyClientSecret = "CLIENT_SECRET" - // EnvKeyEncryptionKey key for env variable ENCRYPTION_KEY - EnvKeyEncryptionKey = "ENCRYPTION_KEY" - // EnvKeyJWK key for env variable JWK - EnvKeyJWK = "JWK" - - // Boolean variables - // EnvKeyIsProd key for env variable IS_PROD - EnvKeyIsProd = "IS_PROD" - // EnvKeyDisableEmailVerification key for env variable DISABLE_EMAIL_VERIFICATION - EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION" - // EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH - EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION" - // EnvKeyDisableBasicAuthentication key for env variable DISABLE_MOBILE_BASIC_AUTH - EnvKeyDisableMobileBasicAuthentication = "DISABLE_MOBILE_BASIC_AUTHENTICATION" - // EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN - EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN" - // EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE - EnvKeyDisableLoginPage = "DISABLE_LOGIN_PAGE" - // EnvKeyDisableSignUp key for env variable DISABLE_SIGN_UP - EnvKeyDisableSignUp = "DISABLE_SIGN_UP" - // EnvKeyDisableRedisForEnv key for env variable DISABLE_REDIS_FOR_ENV - EnvKeyDisableRedisForEnv = "DISABLE_REDIS_FOR_ENV" - // EnvKeyDisableStrongPassword key for env variable DISABLE_STRONG_PASSWORD - EnvKeyDisableStrongPassword = "DISABLE_STRONG_PASSWORD" - // EnvKeyEnforceMultiFactorAuthentication is key for env variable ENFORCE_MULTI_FACTOR_AUTHENTICATION - // If enforced and changed later on, existing user will have MFA but new user will not have MFA - EnvKeyEnforceMultiFactorAuthentication = "ENFORCE_MULTI_FACTOR_AUTHENTICATION" - // EnvKeyDisableMultiFactorAuthentication is key for env variable DISABLE_MULTI_FACTOR_AUTHENTICATION - // this variable is used to completely disable multi factor authentication. It will have no effect on profile preference - EnvKeyDisableMultiFactorAuthentication = "DISABLE_MULTI_FACTOR_AUTHENTICATION" - // EnvKeyDisableTOTPLogin is key for env variable DISABLE_TOTP_LOGIN - // this variable is used to completely disable totp verification - EnvKeyDisableTOTPLogin = "DISABLE_TOTP_LOGIN" - // EnvKeyDisableMailOTPLogin is key for env variable DISABLE_MAIL_OTP_LOGIN - // this variable is used to completely disable totp verification - EnvKeyDisableMailOTPLogin = "DISABLE_MAIL_OTP_LOGIN" - // EnvKeyDisablePhoneVerification is key for env variable DISABLE_PHONE_VERIFICATION - // this variable is used to disable phone verification - EnvKeyDisablePhoneVerification = "DISABLE_PHONE_VERIFICATION" - // EnvKeyDisablePlayGround is key for env variable DISABLE_PLAYGROUND - // this variable will disable or enable playground use in dashboard - EnvKeyDisablePlayGround = "DISABLE_PLAYGROUND" - - // Slice variables - // EnvKeyRoles key for env variable ROLES - EnvKeyRoles = "ROLES" - // EnvKeyProtectedRoles key for env variable PROTECTED_ROLES - EnvKeyProtectedRoles = "PROTECTED_ROLES" - // EnvKeyDefaultRoles key for env variable DEFAULT_ROLES - EnvKeyDefaultRoles = "DEFAULT_ROLES" - // EnvKeyAllowedOrigins key for env variable ALLOWED_ORIGINS - EnvKeyAllowedOrigins = "ALLOWED_ORIGINS" - - // For oauth/openid/authorize - // EnvKeyDefaultAuthorizeResponseType key for env variable DEFAULT_AUTHORIZE_RESPONSE_TYPE - // This env is used for setting default response type in authorize handler - EnvKeyDefaultAuthorizeResponseType = "DEFAULT_AUTHORIZE_RESPONSE_TYPE" - // EnvKeyDefaultAuthorizeResponseMode key for env variable DEFAULT_AUTHORIZE_RESPONSE_MODE - // This env is used for setting default response mode in authorize handler - EnvKeyDefaultAuthorizeResponseMode = "DEFAULT_AUTHORIZE_RESPONSE_MODE" - - // Twilio env variables - // EnvKeyTwilioAPIKey key for env variable TWILIO_API_KEY - EnvKeyTwilioAPIKey = "TWILIO_API_KEY" - // EnvKeyTwilioAPISecret key for env variable TWILIO_API_SECRET - EnvKeyTwilioAPISecret = "TWILIO_API_SECRET" - // EnvKeyTwilioAccountSID key for env variable TWILIO_ACCOUNT_SID - EnvKeyTwilioAccountSID = "TWILIO_ACCOUNT_SID" - // EnvKeyTwilioSender key for env variable TWILIO_SENDER - EnvKeyTwilioSender = "TWILIO_SENDER" -) diff --git a/server/crypto/aes.go b/server/crypto/aes.go deleted file mode 100644 index 422f694dd..000000000 --- a/server/crypto/aes.go +++ /dev/null @@ -1,124 +0,0 @@ -package crypto - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "io" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -var bytes = []byte{35, 46, 57, 24, 85, 35, 24, 74, 87, 35, 88, 98, 66, 32, 14, 0o5} - -// EncryptAES method is to encrypt or hide any classified text -func EncryptAES(text string) (string, error) { - k, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey) - if err != nil { - return "", err - } - key := []byte(k) - block, err := aes.NewCipher(key) - if err != nil { - return "", err - } - plainText := []byte(text) - cfb := cipher.NewCFBEncrypter(block, bytes) - cipherText := make([]byte, len(plainText)) - cfb.XORKeyStream(cipherText, plainText) - return EncryptB64(string(cipherText)), nil -} - -// DecryptAES method is to extract back the encrypted text -func DecryptAES(text string) (string, error) { - k, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey) - if err != nil { - return "", err - } - key := []byte(k) - block, err := aes.NewCipher(key) - if err != nil { - return "", err - } - cipherText, err := DecryptB64(text) - if err != nil { - return "", err - } - cfb := cipher.NewCFBDecrypter(block, bytes) - plainText := make([]byte, len(cipherText)) - cfb.XORKeyStream(plainText, []byte(cipherText)) - return string(plainText), nil -} - -// EncryptAESEnv encrypts data using AES algorithm -// kept for the backward compatibility of env data encryption -func EncryptAESEnv(text []byte) ([]byte, error) { - var res []byte - k, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey) - if err != nil { - return res, err - } - key := []byte(k) - c, err := aes.NewCipher(key) - if err != nil { - return res, err - } - - // gcm or Galois/Counter Mode, is a mode of operation - // for symmetric key cryptographic block ciphers - // - https://en.wikipedia.org/wiki/Galois/Counter_Mode - gcm, err := cipher.NewGCM(c) - if err != nil { - return res, err - } - - // creates a new byte array the size of the nonce - // which must be passed to Seal - nonce := make([]byte, gcm.NonceSize()) - // populates our nonce with a cryptographically secure - // random sequence - if _, err = io.ReadFull(rand.Reader, nonce); err != nil { - return res, err - } - - // here we encrypt our text using the Seal function - // Seal encrypts and authenticates plaintext, authenticates the - // additional data and appends the result to dst, returning the updated - // slice. The nonce must be NonceSize() bytes long and unique for all - // time, for a given key. - return gcm.Seal(nonce, nonce, text, nil), nil -} - -// DecryptAES decrypts data using AES algorithm -// Kept for the backward compatibility of env data decryption -func DecryptAESEnv(ciphertext []byte) ([]byte, error) { - var res []byte - k, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEncryptionKey) - if err != nil { - return res, err - } - key := []byte(k) - c, err := aes.NewCipher(key) - if err != nil { - return res, err - } - - gcm, err := cipher.NewGCM(c) - if err != nil { - return res, err - } - - nonceSize := gcm.NonceSize() - if len(ciphertext) < nonceSize { - return res, err - } - - nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] - plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) - if err != nil { - return res, err - } - - return plaintext, nil -} diff --git a/server/crypto/common.go b/server/crypto/common.go deleted file mode 100644 index 91aed06ad..000000000 --- a/server/crypto/common.go +++ /dev/null @@ -1,136 +0,0 @@ -package crypto - -import ( - "crypto/x509" - "encoding/json" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "golang.org/x/crypto/bcrypt" - "gopkg.in/square/go-jose.v2" -) - -// GetPubJWK returns JWK for given keys -func GetPubJWK(algo, keyID string, publicKey interface{}) (string, error) { - jwk := &jose.JSONWebKeySet{ - Keys: []jose.JSONWebKey{ - { - Algorithm: algo, - Key: publicKey, - Use: "sig", - KeyID: keyID, - Certificates: []*x509.Certificate{}, - CertificateThumbprintSHA1: []uint8{}, - CertificateThumbprintSHA256: []uint8{}, - }, - }, - } - jwkPublicKey, err := jwk.Keys[0].MarshalJSON() - if err != nil { - return "", err - } - return string(jwkPublicKey), nil -} - -// GenerateJWKBasedOnEnv generates JWK based on env -// make sure clientID, jwtType, jwtSecret / public & private key pair is set -// this is called while initializing app / when env is updated -func GenerateJWKBasedOnEnv() (string, error) { - jwk := "" - algo, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType) - if err != nil { - return jwk, err - } - clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) - if err != nil { - return jwk, err - } - - jwtSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret) - if err != nil { - return jwk, err - } - - // check if jwt secret is provided - if IsHMACA(algo) { - jwk, err = GetPubJWK(algo, clientID, []byte(jwtSecret)) - if err != nil { - return "", err - } - } - - jwtPublicKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey) - if err != nil { - return jwk, err - } - - if IsRSA(algo) { - publicKeyInstance, err := ParseRsaPublicKeyFromPemStr(jwtPublicKey) - if err != nil { - return "", err - } - - jwk, err = GetPubJWK(algo, clientID, publicKeyInstance) - if err != nil { - return "", err - } - } - - if IsECDSA(algo) { - jwtPublicKey, err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey) - if err != nil { - return jwk, err - } - publicKeyInstance, err := ParseEcdsaPublicKeyFromPemStr(jwtPublicKey) - if err != nil { - return "", err - } - - jwk, err = GetPubJWK(algo, clientID, publicKeyInstance) - if err != nil { - return "", err - } - } - - return jwk, nil -} - -// EncryptEnvData is used to encrypt the env data -func EncryptEnvData(data map[string]interface{}) (string, error) { - jsonBytes, err := json.Marshal(data) - if err != nil { - return "", err - } - - storeData, err := memorystore.Provider.GetEnvStore() - if err != nil { - return "", err - } - - err = json.Unmarshal(jsonBytes, &storeData) - if err != nil { - return "", err - } - - configData, err := json.Marshal(storeData) - if err != nil { - return "", err - } - - encryptedConfig, err := EncryptAESEnv(configData) - if err != nil { - return "", err - } - - return EncryptB64(string(encryptedConfig)), nil -} - -// EncryptPassword is used for encrypting password -func EncryptPassword(password string) (string, error) { - pw, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) - if err != nil { - return "", err - } - - return string(pw), nil -} diff --git a/server/db/db.go b/server/db/db.go deleted file mode 100644 index 80b3309f1..000000000 --- a/server/db/db.go +++ /dev/null @@ -1,86 +0,0 @@ -package db - -import ( - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db/providers" - "github.com/authorizerdev/authorizer/server/db/providers/arangodb" - "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/mongodb" - "github.com/authorizerdev/authorizer/server/db/providers/sql" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -// Provider returns the current database provider -var Provider providers.Provider - -func InitDB() error { - var err error - - 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.DbTypeCouchbaseDB - isArangoDB := envs.DatabaseType == constants.DbTypeArangodb - isMongoDB := envs.DatabaseType == constants.DbTypeMongodb - isCassandra := envs.DatabaseType == constants.DbTypeCassandraDB || envs.DatabaseType == constants.DbTypeScyllaDB - isDynamoDB := envs.DatabaseType == constants.DbTypeDynamoDB - isCouchbaseDB := envs.DatabaseType == constants.DbTypeCouchbaseDB - - if isSQL { - log.Info("Initializing SQL Driver for: ", envs.DatabaseType) - Provider, err = sql.NewProvider() - if err != nil { - log.Fatal("Failed to initialize SQL driver: ", err) - return err - } - } - if isArangoDB { - log.Info("Initializing ArangoDB Driver") - Provider, err = arangodb.NewProvider() - if err != nil { - log.Fatal("Failed to initialize ArangoDB driver: ", err) - return err - } - } - - if isMongoDB { - log.Info("Initializing MongoDB Driver") - Provider, err = mongodb.NewProvider() - if err != nil { - log.Fatal("Failed to initialize MongoDB driver: ", err) - return err - } - } - - if isCassandra { - log.Info("Initializing CassandraDB Driver") - Provider, err = cassandradb.NewProvider() - if err != nil { - log.Fatal("Failed to initialize CassandraDB driver: ", err) - return err - } - } - - if isDynamoDB { - log.Info("Initializing DynamoDB Driver for: ", envs.DatabaseType) - Provider, err = dynamodb.NewProvider() - if err != nil { - log.Fatal("Failed to initialize DynamoDB driver: ", err) - return err - } - } - - if isCouchbaseDB { - log.Info("Initializing CouchbaseDB Driver for: ", envs.DatabaseType) - Provider, err = couchbase.NewProvider() - if err != nil { - log.Fatal("Failed to initialize Couchbase driver: ", err) - return err - } - } - - return nil -} diff --git a/server/db/providers/dynamodb/provider.go b/server/db/providers/dynamodb/provider.go deleted file mode 100644 index 70a893068..000000000 --- a/server/db/providers/dynamodb/provider.go +++ /dev/null @@ -1,59 +0,0 @@ -package dynamodb - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/guregu/dynamo" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -type provider struct { - db *dynamo.DB -} - -// NewProvider returns a new Dynamo provider -func NewProvider() (*provider, error) { - dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL - awsRegion := memorystore.RequiredEnvStoreObj.GetRequiredEnv().AwsRegion - awsAccessKeyID := memorystore.RequiredEnvStoreObj.GetRequiredEnv().AwsAccessKeyID - awsSecretAccessKey := memorystore.RequiredEnvStoreObj.GetRequiredEnv().AwsSecretAccessKey - - config := aws.Config{ - MaxRetries: aws.Int(3), - CredentialsChainVerboseErrors: aws.Bool(true), // for full error logs - } - - if awsRegion != "" { - config.Region = aws.String(awsRegion) - } - // custom awsAccessKeyID, awsSecretAccessKey took first priority, if not then fetch config from aws credentials - if awsAccessKeyID != "" && awsSecretAccessKey != "" { - config.Credentials = credentials.NewStaticCredentials(awsAccessKeyID, awsSecretAccessKey, "") - } else if dbURL != "" { - log.Debug("Tring to use database url for dynamodb") - // static config in case of testing or local-setup - config.Credentials = credentials.NewStaticCredentials("key", "key", "") - config.Endpoint = aws.String(dbURL) - } else { - log.Debugf("%s or %s or %s not found. Trying to load default credentials from aws config", constants.EnvAwsRegion, constants.EnvAwsAccessKeyID, constants.EnvAwsSecretAccessKey) - } - session := session.Must(session.NewSession(&config)) - db := dynamo.New(session) - db.CreateTable(models.Collections.User, models.User{}).Wait() - db.CreateTable(models.Collections.Session, models.Session{}).Wait() - db.CreateTable(models.Collections.EmailTemplate, models.EmailTemplate{}).Wait() - db.CreateTable(models.Collections.Env, models.Env{}).Wait() - db.CreateTable(models.Collections.OTP, models.OTP{}).Wait() - db.CreateTable(models.Collections.VerificationRequest, models.VerificationRequest{}).Wait() - db.CreateTable(models.Collections.Webhook, models.Webhook{}).Wait() - db.CreateTable(models.Collections.WebhookLog, models.WebhookLog{}).Wait() - db.CreateTable(models.Collections.Authenticators, models.Authenticator{}).Wait() - return &provider{ - db: db, - }, nil -} diff --git a/server/db/providers/provider_template/provider.go b/server/db/providers/provider_template/provider.go deleted file mode 100644 index 30490b4f2..000000000 --- a/server/db/providers/provider_template/provider.go +++ /dev/null @@ -1,20 +0,0 @@ -package provider_template - -import ( - "gorm.io/gorm" -) - -// TODO change following provider to new db provider -type provider struct { - db *gorm.DB -} - -// NewProvider returns a new SQL provider -// TODO change following provider to new db provider -func NewProvider() (*provider, error) { - var sqlDB *gorm.DB - - return &provider{ - db: sqlDB, - }, nil -} diff --git a/server/db/providers/providers.go b/server/db/providers/providers.go deleted file mode 100644 index 6ea95cc41..000000000 --- a/server/db/providers/providers.go +++ /dev/null @@ -1,102 +0,0 @@ -package providers - -import ( - "context" - - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" -) - -type Provider interface { - // AddUser to save user information in database - AddUser(ctx context.Context, user *models.User) (*models.User, error) - // UpdateUser to update user information in database - UpdateUser(ctx context.Context, user *models.User) (*models.User, error) - // DeleteUser to delete user information from database - DeleteUser(ctx context.Context, user *models.User) error - // ListUsers to get list of users from database - ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) - // GetUserByEmail to get user information from database using email address - GetUserByEmail(ctx context.Context, email string) (*models.User, error) - // GetUserByPhoneNumber to get user information from database using phone number - GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) - // GetUserByID to get user information from database using user ID - GetUserByID(ctx context.Context, id string) (*models.User, error) - // UpdateUsers to update multiple users, with parameters of user IDs slice - // If ids set to nil / empty all the users will be updated - UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error - - // AddVerificationRequest to save verification request in database - AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error) - // GetVerificationRequestByToken to get verification request from database using token - GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error) - // GetVerificationRequestByEmail to get verification request by email from database - GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (*models.VerificationRequest, error) - // ListVerificationRequests to get list of verification requests from database - ListVerificationRequests(ctx context.Context, pagination *model.Pagination) (*model.VerificationRequests, error) - // DeleteVerificationRequest to delete verification request from database - DeleteVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) error - - // AddSession to save session information in database - AddSession(ctx context.Context, session *models.Session) error - // DeleteSession to delete session information from database - DeleteSession(ctx context.Context, userId string) error - - // AddEnv to save environment information in database - AddEnv(ctx context.Context, env *models.Env) (*models.Env, error) - // UpdateEnv to update environment information in database - UpdateEnv(ctx context.Context, env *models.Env) (*models.Env, error) - // GetEnv to get environment information from database - GetEnv(ctx context.Context) (*models.Env, error) - - // AddWebhook to add webhook - AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) - // UpdateWebhook to update webhook - UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error) - // ListWebhook to list webhook - ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error) - // GetWebhookByID to get webhook by id - GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) - // GetWebhookByEventName to get webhook by event_name - GetWebhookByEventName(ctx context.Context, eventName string) ([]*model.Webhook, error) - // DeleteWebhook to delete webhook - DeleteWebhook(ctx context.Context, webhook *model.Webhook) error - - // AddWebhookLog to add webhook log - AddWebhookLog(ctx context.Context, webhookLog *models.WebhookLog) (*model.WebhookLog, error) - // ListWebhookLogs to list webhook logs - ListWebhookLogs(ctx context.Context, pagination *model.Pagination, webhookID string) (*model.WebhookLogs, error) - - // AddEmailTemplate to add EmailTemplate - AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) - // UpdateEmailTemplate to update EmailTemplate - UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error) - // ListEmailTemplate to list EmailTemplate - ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error) - // GetEmailTemplateByID to get EmailTemplate by id - GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) - // GetEmailTemplateByEventName to get EmailTemplate by event_name - GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) - // DeleteEmailTemplate to delete EmailTemplate - DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error - - // UpsertOTP to add or update otp - UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, error) - // GetOTPByEmail to get otp for a given email address - GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) - // GetOTPByPhoneNumber to get otp for a given phone number - GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) - // DeleteOTP to delete otp - DeleteOTP(ctx context.Context, otp *models.OTP) error - - // AddAuthenticator adds a new authenticator document to the database. - // If the authenticator doesn't have an ID, a new one is generated. - // The created document is returned, or an error if the operation fails. - AddAuthenticator(ctx context.Context, totp *models.Authenticator) (*models.Authenticator, error) - // UpdateAuthenticator updates an existing authenticator document in the database. - // The updated document is returned, or an error if the operation fails. - UpdateAuthenticator(ctx context.Context, totp *models.Authenticator) (*models.Authenticator, error) - // GetAuthenticatorDetailsByUserId retrieves details of an authenticator document based on user ID and authenticator type. - // If found, the authenticator document is returned, or an error if not found or an error occurs during the retrieval. - GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) -} diff --git a/server/email/email.go b/server/email/email.go deleted file mode 100644 index 8376931d8..000000000 --- a/server/email/email.go +++ /dev/null @@ -1,166 +0,0 @@ -package email - -import ( - "bytes" - "context" - "crypto/tls" - "strconv" - "strings" - "text/template" - - log "github.com/sirupsen/logrus" - gomail "gopkg.in/mail.v2" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -func getDefaultTemplate(event string) *model.EmailTemplate { - switch event { - case constants.VerificationTypeBasicAuthSignup, constants.VerificationTypeMagicLinkLogin, constants.VerificationTypeUpdateEmail: - return &model.EmailTemplate{ - Subject: emailVerificationSubject, - Template: emailVerificationTemplate, - } - case constants.VerificationTypeForgotPassword: - return &model.EmailTemplate{ - Subject: forgotPasswordSubject, - Template: forgotPasswordTemplate, - } - case constants.VerificationTypeInviteMember: - return &model.EmailTemplate{ - Subject: inviteEmailSubject, - Template: inviteEmailTemplate, - } - case constants.VerificationTypeOTP: - return &model.EmailTemplate{ - Subject: otpEmailSubject, - Template: otpEmailTemplate, - } - default: - return nil - } -} - -func getEmailTemplate(event string, data map[string]interface{}) (*model.EmailTemplate, error) { - ctx := context.Background() - tmp, err := db.Provider.GetEmailTemplateByEventName(ctx, event) - if err != nil || tmp == nil { - tmp = getDefaultTemplate(event) - } - - templ, err := template.New(event + "_template.tmpl").Parse(tmp.Template) - if err != nil { - return nil, err - } - buf := &bytes.Buffer{} - err = templ.Execute(buf, data) - if err != nil { - return nil, err - } - templateString := buf.String() - - subject, err := template.New(event + "_subject.tmpl").Parse(tmp.Subject) - if err != nil { - return nil, err - } - buf = &bytes.Buffer{} - err = subject.Execute(buf, data) - if err != nil { - return nil, err - } - subjectString := buf.String() - return &model.EmailTemplate{ - Template: templateString, - Subject: subjectString, - }, nil -} - -// SendEmail function to send mail -func SendEmail(to []string, event string, data map[string]interface{}) error { - // dont trigger email sending in case of test - envKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEnv) - if err != nil { - return err - } - if envKey == constants.TestEnv { - return nil - } - - tmp, err := getEmailTemplate(event, data) - if err != nil { - log.Error("Failed to get event template: ", err) - return err - } - - m := gomail.NewMessage() - senderEmail, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySenderEmail) - if err != nil { - log.Errorf("Error while getting sender email from env variable: %v", err) - return err - } - - senderName, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySenderName) - if err != nil { - log.Errorf("Error while getting sender name from env variable: %v", err) - return err - } - - smtpPort, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySmtpPort) - if err != nil { - log.Errorf("Error while getting smtp port from env variable: %v", err) - return err - } - - smtpHost, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySmtpHost) - if err != nil { - log.Errorf("Error while getting smtp host from env variable: %v", err) - return err - } - - smtpUsername, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySmtpUsername) - if err != nil { - log.Errorf("Error while getting smtp username from env variable: %v", err) - return err - } - - smtpPassword, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySmtpPassword) - if err != nil { - log.Errorf("Error while getting smtp password from env variable: %v", err) - return err - } - - smtpLocalName, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySmtpLocalName) - if err != nil { - log.Debugf("Error while getting smtp localname from env variable: %v", err) - smtpLocalName = "" - } - - isProd, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsProd) - if err != nil { - log.Errorf("Error while getting env variable: %v", err) - return err - } - - m.SetAddressHeader("From", senderEmail, senderName) - m.SetHeader("To", to...) - m.SetHeader("Subject", tmp.Subject) - m.SetBody("text/html", tmp.Template) - port, _ := strconv.Atoi(smtpPort) - d := gomail.NewDialer(smtpHost, port, smtpUsername, smtpPassword) - if !isProd { - d.TLSConfig = &tls.Config{InsecureSkipVerify: true} - } - - if strings.TrimSpace(smtpLocalName) != "" { - d.LocalName = smtpLocalName - } - - if err := d.DialAndSend(m); err != nil { - log.Debug("SMTP Failed: ", err) - return err - } - return nil -} diff --git a/server/env/env.go b/server/env/env.go deleted file mode 100644 index 110e0c5af..000000000 --- a/server/env/env.go +++ /dev/null @@ -1,903 +0,0 @@ -package env - -import ( - "errors" - "fmt" - "os" - "strconv" - "strings" - - "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/utils" -) - -// InitEnv to initialize EnvData and through error if required env are not present -func InitAllEnv() error { - envData, err := GetEnvData() - if err != nil || envData == nil { - log.Info("No env data found in db, using local clone of env data") - // get clone of current store - envData, err = memorystore.Provider.GetEnvStore() - if err != nil { - log.Debug("Error while getting env data from memorystore: ", err) - return err - } - } - - // unique client id for each instance - cid, ok := envData[constants.EnvKeyClientID] - clientID := "" - if !ok || cid == "" { - clientID = uuid.New().String() - envData[constants.EnvKeyClientID] = clientID - } else { - clientID = cid.(string) - } - - // unique client secret for each instance - if val, ok := envData[constants.EnvKeyClientSecret]; !ok || val != "" { - envData[constants.EnvKeyClientSecret] = uuid.New().String() - } - - // os string envs - osEnv := os.Getenv(constants.EnvKeyEnv) - osAppURL := os.Getenv(constants.EnvKeyAppURL) - osAuthorizerURL := os.Getenv(constants.EnvKeyAuthorizerURL) - osPort := os.Getenv(constants.EnvKeyPort) - osAccessTokenExpiryTime := os.Getenv(constants.EnvKeyAccessTokenExpiryTime) - osAdminSecret := os.Getenv(constants.EnvKeyAdminSecret) - osSmtpHost := os.Getenv(constants.EnvKeySmtpHost) - osSmtpPort := os.Getenv(constants.EnvKeySmtpPort) - osSmtpUsername := os.Getenv(constants.EnvKeySmtpUsername) - osSmtpPassword := os.Getenv(constants.EnvKeySmtpPassword) - osSmtpLocalName := os.Getenv(constants.EnvKeySmtpLocalName) - osSenderEmail := os.Getenv(constants.EnvKeySenderEmail) - osSenderName := os.Getenv(constants.EnvKeySenderName) - osJwtType := os.Getenv(constants.EnvKeyJwtType) - osJwtSecret := os.Getenv(constants.EnvKeyJwtSecret) - osJwtPrivateKey := os.Getenv(constants.EnvKeyJwtPrivateKey) - osJwtPublicKey := os.Getenv(constants.EnvKeyJwtPublicKey) - osJwtRoleClaim := os.Getenv(constants.EnvKeyJwtRoleClaim) - osCustomAccessTokenScript := os.Getenv(constants.EnvKeyCustomAccessTokenScript) - osGoogleClientID := os.Getenv(constants.EnvKeyGoogleClientID) - osGoogleClientSecret := os.Getenv(constants.EnvKeyGoogleClientSecret) - osGithubClientID := os.Getenv(constants.EnvKeyGithubClientID) - osGithubClientSecret := os.Getenv(constants.EnvKeyGithubClientSecret) - osFacebookClientID := os.Getenv(constants.EnvKeyFacebookClientID) - osFacebookClientSecret := os.Getenv(constants.EnvKeyFacebookClientSecret) - osLinkedInClientID := os.Getenv(constants.EnvKeyLinkedInClientID) - osLinkedInClientSecret := os.Getenv(constants.EnvKeyLinkedInClientSecret) - osAppleClientID := os.Getenv(constants.EnvKeyAppleClientID) - osAppleClientSecret := os.Getenv(constants.EnvKeyAppleClientSecret) - osTwitterClientID := os.Getenv(constants.EnvKeyTwitterClientID) - osTwitterClientSecret := os.Getenv(constants.EnvKeyTwitterClientSecret) - osMicrosoftClientID := os.Getenv(constants.EnvKeyMicrosoftClientID) - osMicrosoftClientSecret := os.Getenv(constants.EnvKeyMicrosoftClientSecret) - osMicrosoftActiveDirectoryTenantID := os.Getenv(constants.EnvKeyMicrosoftActiveDirectoryTenantID) - osTwitchClientID := os.Getenv(constants.EnvKeyTwitchClientID) - osTwitchClientSecret := os.Getenv(constants.EnvKeyTwitchClientSecret) - osRobloxClientID := os.Getenv(constants.EnvKeyTwitchClientID) - osRobloxClientSecret := os.Getenv(constants.EnvKeyTwitchClientSecret) - osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL) - osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName) - osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo) - osAwsRegion := os.Getenv(constants.EnvAwsRegion) - osAwsAccessKey := os.Getenv(constants.EnvAwsAccessKeyID) - 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 - osAppCookieSecure := os.Getenv(constants.EnvKeyAppCookieSecure) - osAdminCookieSecure := os.Getenv(constants.EnvKeyAdminCookieSecure) - osDisableBasicAuthentication := os.Getenv(constants.EnvKeyDisableBasicAuthentication) - osDisableMobileBasicAuthentication := os.Getenv(constants.AuthRecipeMethodMobileBasicAuth) - osDisableEmailVerification := os.Getenv(constants.EnvKeyDisableEmailVerification) - osDisableMagicLinkLogin := os.Getenv(constants.EnvKeyDisableMagicLinkLogin) - osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage) - osDisableSignUp := os.Getenv(constants.EnvKeyDisableSignUp) - osDisableRedisForEnv := os.Getenv(constants.EnvKeyDisableRedisForEnv) - osDisableStrongPassword := os.Getenv(constants.EnvKeyDisableStrongPassword) - osEnforceMultiFactorAuthentication := os.Getenv(constants.EnvKeyEnforceMultiFactorAuthentication) - osDisableMultiFactorAuthentication := os.Getenv(constants.EnvKeyDisableMultiFactorAuthentication) - osDisableTOTPLogin := os.Getenv(constants.EnvKeyDisableTOTPLogin) - osDisableMailOTPLogin := os.Getenv(constants.EnvKeyDisableMailOTPLogin) - // phone verification var - osDisablePhoneVerification := os.Getenv(constants.EnvKeyDisablePhoneVerification) - osDisablePlayground := os.Getenv(constants.EnvKeyDisablePlayGround) - - // twilio vars - osTwilioApiKey := os.Getenv(constants.EnvKeyTwilioAPIKey) - osTwilioApiSecret := os.Getenv(constants.EnvKeyTwilioAPISecret) - osTwilioAccountSid := os.Getenv(constants.EnvKeyTwilioAccountSID) - osTwilioSender := os.Getenv(constants.EnvKeyTwilioSender) - - // os slice vars - osAllowedOrigins := os.Getenv(constants.EnvKeyAllowedOrigins) - osRoles := os.Getenv(constants.EnvKeyRoles) - osDefaultRoles := os.Getenv(constants.EnvKeyDefaultRoles) - osProtectedRoles := os.Getenv(constants.EnvKeyProtectedRoles) - - ienv, ok := envData[constants.EnvKeyEnv] - if !ok || ienv == "" { - envData[constants.EnvKeyEnv] = osEnv - if envData[constants.EnvKeyEnv] == "" { - envData[constants.EnvKeyEnv] = "production" - } - - if envData[constants.EnvKeyEnv] == "production" { - envData[constants.EnvKeyIsProd] = true - } else { - envData[constants.EnvKeyIsProd] = false - } - } - if osEnv != "" && osEnv != envData[constants.EnvKeyEnv] { - envData[constants.EnvKeyEnv] = osEnv - if envData[constants.EnvKeyEnv] == "production" { - envData[constants.EnvKeyIsProd] = true - } else { - envData[constants.EnvKeyIsProd] = false - } - } - - if val, ok := envData[constants.EnvAwsRegion]; !ok || val == "" { - envData[constants.EnvAwsRegion] = osAwsRegion - } - - if osAwsRegion != "" && envData[constants.EnvAwsRegion] != osAwsRegion { - envData[constants.EnvAwsRegion] = osAwsRegion - } - - if val, ok := envData[constants.EnvAwsAccessKeyID]; !ok || val == "" { - envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey - } - if osAwsAccessKey != "" && envData[constants.EnvAwsAccessKeyID] != osAwsAccessKey { - envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey - } - - if val, ok := envData[constants.EnvAwsSecretAccessKey]; !ok || val == "" { - envData[constants.EnvAwsSecretAccessKey] = osAwsSecretKey - } - if 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 == "" { - envData[constants.EnvKeyAppURL] = osAppURL - } - if osAppURL != "" && envData[constants.EnvKeyAppURL] != osAppURL { - envData[constants.EnvKeyAppURL] = osAppURL - } - - if val, ok := envData[constants.EnvKeyAuthorizerURL]; !ok || val == "" { - envData[constants.EnvKeyAuthorizerURL] = osAuthorizerURL - } - if osAuthorizerURL != "" && envData[constants.EnvKeyAuthorizerURL] != osAuthorizerURL { - envData[constants.EnvKeyAuthorizerURL] = osAuthorizerURL - } - - if val, ok := envData[constants.EnvKeyPort]; !ok || val == "" { - envData[constants.EnvKeyPort] = osPort - if envData[constants.EnvKeyPort] == "" { - envData[constants.EnvKeyPort] = "8080" - } - } - if osPort != "" && envData[constants.EnvKeyPort] != osPort { - envData[constants.EnvKeyPort] = osPort - } - - if val, ok := envData[constants.EnvKeyAccessTokenExpiryTime]; !ok || val == "" { - envData[constants.EnvKeyAccessTokenExpiryTime] = osAccessTokenExpiryTime - if envData[constants.EnvKeyAccessTokenExpiryTime] == "" { - envData[constants.EnvKeyAccessTokenExpiryTime] = "30m" - } - } - if osAccessTokenExpiryTime != "" && envData[constants.EnvKeyAccessTokenExpiryTime] != osAccessTokenExpiryTime { - envData[constants.EnvKeyAccessTokenExpiryTime] = osAccessTokenExpiryTime - } - - if val, ok := envData[constants.EnvKeyAdminSecret]; !ok || val == "" { - envData[constants.EnvKeyAdminSecret] = osAdminSecret - } - if osAdminSecret != "" && envData[constants.EnvKeyAdminSecret] != osAdminSecret { - envData[constants.EnvKeyAdminSecret] = osAdminSecret - } - - if val, ok := envData[constants.EnvKeySmtpHost]; !ok || val == "" { - envData[constants.EnvKeySmtpHost] = osSmtpHost - } - if osSmtpHost != "" && envData[constants.EnvKeySmtpHost] != osSmtpHost { - envData[constants.EnvKeySmtpHost] = osSmtpHost - } - - if val, ok := envData[constants.EnvKeySmtpPort]; !ok || val == "" { - envData[constants.EnvKeySmtpPort] = osSmtpPort - } - if osSmtpPort != "" && envData[constants.EnvKeySmtpPort] != osSmtpPort { - envData[constants.EnvKeySmtpPort] = osSmtpPort - } - - if val, ok := envData[constants.EnvKeySmtpUsername]; !ok || val == "" { - envData[constants.EnvKeySmtpUsername] = osSmtpUsername - } - if osSmtpUsername != "" && envData[constants.EnvKeySmtpUsername] != osSmtpUsername { - envData[constants.EnvKeySmtpUsername] = osSmtpUsername - } - - if val, ok := envData[constants.EnvKeySmtpLocalName]; !ok || val == "" { - envData[constants.EnvKeySmtpLocalName] = osSmtpLocalName - } - if osSmtpLocalName != "" && envData[constants.EnvKeySmtpLocalName] != osSmtpLocalName { - envData[constants.EnvKeySmtpLocalName] = osSmtpLocalName - } - - if val, ok := envData[constants.EnvKeySmtpPassword]; !ok || val == "" { - envData[constants.EnvKeySmtpPassword] = osSmtpPassword - } - if osSmtpPassword != "" && envData[constants.EnvKeySmtpPassword] != osSmtpPassword { - envData[constants.EnvKeySmtpPassword] = osSmtpPassword - } - - if val, ok := envData[constants.EnvKeySenderEmail]; !ok || val == "" { - envData[constants.EnvKeySenderEmail] = osSenderEmail - } - if osSenderEmail != "" && envData[constants.EnvKeySenderEmail] != osSenderEmail { - envData[constants.EnvKeySenderEmail] = osSenderEmail - } - - if val, ok := envData[constants.EnvKeySenderName]; !ok || val == "" { - envData[constants.EnvKeySenderName] = osSenderName - } - if osSenderName != "" && envData[constants.EnvKeySenderName] != osSenderName { - envData[constants.EnvKeySenderName] = osSenderName - } - - algoVal, ok := envData[constants.EnvKeyJwtType] - algo := "" - if !ok || algoVal == "" { - envData[constants.EnvKeyJwtType] = osJwtType - if envData[constants.EnvKeyJwtType] == "" { - envData[constants.EnvKeyJwtType] = "RS256" - algo = envData[constants.EnvKeyJwtType].(string) - } - } else { - algo = algoVal.(string) - if !crypto.IsHMACA(algo) && !crypto.IsRSA(algo) && !crypto.IsECDSA(algo) { - log.Debug("Invalid JWT Algorithm") - return errors.New("invalid JWT_TYPE") - } - } - if osJwtType != "" && osJwtType != algo { - if !crypto.IsHMACA(osJwtType) && !crypto.IsRSA(osJwtType) && !crypto.IsECDSA(osJwtType) { - log.Debug("Invalid JWT Algorithm") - return errors.New("invalid JWT_TYPE") - } - algo = osJwtType - envData[constants.EnvKeyJwtType] = osJwtType - } - - if crypto.IsHMACA(algo) { - if val, ok := envData[constants.EnvKeyJwtSecret]; !ok || val == "" { - envData[constants.EnvKeyJwtSecret] = osJwtSecret - if envData[constants.EnvKeyJwtSecret] == "" { - envData[constants.EnvKeyJwtSecret], _, err = crypto.NewHMACKey(algo, clientID) - if err != nil { - return err - } - } - } - if osJwtSecret != "" && envData[constants.EnvKeyJwtSecret] != osJwtSecret { - envData[constants.EnvKeyJwtSecret] = osJwtSecret - } - } - - if crypto.IsRSA(algo) || crypto.IsECDSA(algo) { - privateKey, publicKey := "", "" - - if val, ok := envData[constants.EnvKeyJwtPrivateKey]; !ok || val == "" { - privateKey = osJwtPrivateKey - } - if osJwtPrivateKey != "" && privateKey != osJwtPrivateKey { - privateKey = osJwtPrivateKey - } - - if val, ok := envData[constants.EnvKeyJwtPublicKey]; !ok || val == "" { - publicKey = osJwtPublicKey - } - if osJwtPublicKey != "" && publicKey != osJwtPublicKey { - publicKey = osJwtPublicKey - } - - // if algo is RSA / ECDSA, then we need to have both private and public key - // if either of them is not present generate new keys - if privateKey == "" || publicKey == "" { - if crypto.IsRSA(algo) { - _, privateKey, publicKey, _, err = crypto.NewRSAKey(algo, clientID) - if err != nil { - return err - } - } else if crypto.IsECDSA(algo) { - _, privateKey, publicKey, _, err = crypto.NewECDSAKey(algo, clientID) - if err != nil { - return err - } - } - } else { - // parse keys to make sure they are valid - if crypto.IsRSA(algo) { - _, err = crypto.ParseRsaPrivateKeyFromPemStr(privateKey) - if err != nil { - return err - } - - _, err := crypto.ParseRsaPublicKeyFromPemStr(publicKey) - if err != nil { - return err - } - - } else if crypto.IsECDSA(algo) { - _, err = crypto.ParseEcdsaPrivateKeyFromPemStr(privateKey) - if err != nil { - return err - } - - _, err := crypto.ParseEcdsaPublicKeyFromPemStr(publicKey) - if err != nil { - return err - } - } - } - - envData[constants.EnvKeyJwtPrivateKey] = privateKey - envData[constants.EnvKeyJwtPublicKey] = publicKey - - } - - if val, ok := envData[constants.EnvKeyJwtRoleClaim]; !ok || val == "" { - envData[constants.EnvKeyJwtRoleClaim] = osJwtRoleClaim - - if envData[constants.EnvKeyJwtRoleClaim] == "" { - envData[constants.EnvKeyJwtRoleClaim] = "roles" - } - } - if osJwtRoleClaim != "" && envData[constants.EnvKeyJwtRoleClaim] != osJwtRoleClaim { - envData[constants.EnvKeyJwtRoleClaim] = osJwtRoleClaim - } - - if val, ok := envData[constants.EnvKeyCustomAccessTokenScript]; !ok || val == "" { - envData[constants.EnvKeyCustomAccessTokenScript] = osCustomAccessTokenScript - } - if osCustomAccessTokenScript != "" && envData[constants.EnvKeyCustomAccessTokenScript] != osCustomAccessTokenScript { - envData[constants.EnvKeyCustomAccessTokenScript] = osCustomAccessTokenScript - } - - if val, ok := envData[constants.EnvKeyGoogleClientID]; !ok || val == "" { - envData[constants.EnvKeyGoogleClientID] = osGoogleClientID - } - if osGoogleClientID != "" && envData[constants.EnvKeyGoogleClientID] != osGoogleClientID { - envData[constants.EnvKeyGoogleClientID] = osGoogleClientID - } - - if val, ok := envData[constants.EnvKeyGoogleClientSecret]; !ok || val == "" { - envData[constants.EnvKeyGoogleClientSecret] = osGoogleClientSecret - } - if osGoogleClientSecret != "" && envData[constants.EnvKeyGoogleClientSecret] != osGoogleClientSecret { - envData[constants.EnvKeyGoogleClientSecret] = osGoogleClientSecret - } - - if val, ok := envData[constants.EnvKeyGithubClientID]; !ok || val == "" { - envData[constants.EnvKeyGithubClientID] = osGithubClientID - } - if osGithubClientID != "" && envData[constants.EnvKeyGithubClientID] != osGithubClientID { - envData[constants.EnvKeyGithubClientID] = osGithubClientID - } - - if val, ok := envData[constants.EnvKeyGithubClientSecret]; !ok || val == "" { - envData[constants.EnvKeyGithubClientSecret] = osGithubClientSecret - } - if osGithubClientSecret != "" && envData[constants.EnvKeyGithubClientSecret] != osGithubClientSecret { - envData[constants.EnvKeyGithubClientSecret] = osGithubClientSecret - } - - if val, ok := envData[constants.EnvKeyFacebookClientID]; !ok || val == "" { - envData[constants.EnvKeyFacebookClientID] = osFacebookClientID - } - if osFacebookClientID != "" && envData[constants.EnvKeyFacebookClientID] != osFacebookClientID { - envData[constants.EnvKeyFacebookClientID] = osFacebookClientID - } - - if val, ok := envData[constants.EnvKeyFacebookClientSecret]; !ok || val == "" { - envData[constants.EnvKeyFacebookClientSecret] = osFacebookClientSecret - } - if osFacebookClientSecret != "" && envData[constants.EnvKeyFacebookClientSecret] != osFacebookClientSecret { - envData[constants.EnvKeyFacebookClientSecret] = osFacebookClientSecret - } - - if val, ok := envData[constants.EnvKeyLinkedInClientID]; !ok || val == "" { - envData[constants.EnvKeyLinkedInClientID] = osLinkedInClientID - } - if osLinkedInClientID != "" && envData[constants.EnvKeyLinkedInClientID] != osLinkedInClientID { - envData[constants.EnvKeyLinkedInClientID] = osLinkedInClientID - } - - if val, ok := envData[constants.EnvKeyLinkedInClientSecret]; !ok || val == "" { - envData[constants.EnvKeyLinkedInClientSecret] = osLinkedInClientSecret - } - if osLinkedInClientSecret != "" && envData[constants.EnvKeyLinkedInClientSecret] != osLinkedInClientSecret { - envData[constants.EnvKeyLinkedInClientSecret] = osLinkedInClientSecret - } - - if val, ok := envData[constants.EnvKeyAppleClientID]; !ok || val == "" { - envData[constants.EnvKeyAppleClientID] = osAppleClientID - } - if osAppleClientID != "" && envData[constants.EnvKeyAppleClientID] != osAppleClientID { - envData[constants.EnvKeyAppleClientID] = osAppleClientID - } - - if val, ok := envData[constants.EnvKeyAppleClientSecret]; !ok || val == "" { - envData[constants.EnvKeyAppleClientSecret] = osAppleClientSecret - } - if osAppleClientSecret != "" && envData[constants.EnvKeyAppleClientSecret] != osAppleClientSecret { - envData[constants.EnvKeyAppleClientSecret] = osAppleClientSecret - } - - if val, ok := envData[constants.EnvKeyTwitterClientID]; !ok || val == "" { - envData[constants.EnvKeyTwitterClientID] = osTwitterClientID - } - if osTwitterClientID != "" && envData[constants.EnvKeyTwitterClientID] != osTwitterClientID { - envData[constants.EnvKeyTwitterClientID] = osTwitterClientID - } - - if val, ok := envData[constants.EnvKeyTwitterClientSecret]; !ok || val == "" { - envData[constants.EnvKeyTwitterClientSecret] = osTwitterClientSecret - } - if osTwitterClientSecret != "" && 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.EnvKeyTwitchClientID]; !ok || val == "" { - envData[constants.EnvKeyTwitchClientID] = osTwitchClientID - } - if osTwitchClientID != "" && envData[constants.EnvKeyTwitchClientID] != osTwitchClientID { - envData[constants.EnvKeyTwitchClientID] = osTwitchClientID - } - - if val, ok := envData[constants.EnvKeyTwitchClientSecret]; !ok || val == "" { - envData[constants.EnvKeyTwitchClientSecret] = osTwitchClientSecret - } - if osTwitchClientSecret != "" && envData[constants.EnvKeyTwitchClientSecret] != osTwitchClientSecret { - envData[constants.EnvKeyTwitchClientSecret] = osTwitchClientSecret - } - - if val, ok := envData[constants.EnvKeyRobloxClientID]; !ok || val == "" { - envData[constants.EnvKeyRobloxClientID] = osRobloxClientID - } - if osRobloxClientID != "" && envData[constants.EnvKeyRobloxClientID] != osRobloxClientID { - envData[constants.EnvKeyRobloxClientID] = osRobloxClientID - } - - if val, ok := envData[constants.EnvKeyRobloxClientSecret]; !ok || val == "" { - envData[constants.EnvKeyRobloxClientSecret] = osRobloxClientSecret - } - if osRobloxClientSecret != "" && envData[constants.EnvKeyRobloxClientSecret] != osRobloxClientSecret { - envData[constants.EnvKeyRobloxClientSecret] = osRobloxClientSecret - } - - if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" { - envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/") - } - if osResetPasswordURL != "" && envData[constants.EnvKeyResetPasswordURL] != osResetPasswordURL { - envData[constants.EnvKeyResetPasswordURL] = osResetPasswordURL - } - - if val, ok := envData[constants.EnvKeyOrganizationName]; !ok || val == "" { - envData[constants.EnvKeyOrganizationName] = osOrganizationName - } - if osOrganizationName != "" && envData[constants.EnvKeyOrganizationName] != osOrganizationName { - envData[constants.EnvKeyOrganizationName] = osOrganizationName - } - - if val, ok := envData[constants.EnvKeyOrganizationLogo]; !ok || val == "" { - envData[constants.EnvKeyOrganizationLogo] = osOrganizationLogo - } - if osOrganizationLogo != "" && envData[constants.EnvKeyOrganizationLogo] != osOrganizationLogo { - envData[constants.EnvKeyOrganizationLogo] = osOrganizationLogo - } - - if _, ok := envData[constants.EnvKeyAppCookieSecure]; !ok { - if osAppCookieSecure == "" { - envData[constants.EnvKeyAppCookieSecure] = true - } else { - envData[constants.EnvKeyAppCookieSecure] = osAppCookieSecure == "true" - } - } - if osAppCookieSecure != "" { - boolValue, err := strconv.ParseBool(osAppCookieSecure) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyAppCookieSecure].(bool) { - envData[constants.EnvKeyAppCookieSecure] = boolValue - } - } - - if _, ok := envData[constants.EnvKeyAdminCookieSecure]; !ok { - if osAdminCookieSecure == "" { - envData[constants.EnvKeyAdminCookieSecure] = true - } else { - envData[constants.EnvKeyAdminCookieSecure] = osAdminCookieSecure == "true" - } - } - if osAdminCookieSecure != "" { - boolValue, err := strconv.ParseBool(osAdminCookieSecure) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyAdminCookieSecure].(bool) { - envData[constants.EnvKeyAdminCookieSecure] = boolValue - } - } - - if _, ok := envData[constants.EnvKeyDisableBasicAuthentication]; !ok { - envData[constants.EnvKeyDisableBasicAuthentication] = osDisableBasicAuthentication == "true" - } - if osDisableBasicAuthentication != "" { - boolValue, err := strconv.ParseBool(osDisableBasicAuthentication) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisableBasicAuthentication].(bool) { - envData[constants.EnvKeyDisableBasicAuthentication] = boolValue - } - } - - if _, 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 { - envData[constants.EnvKeyDisableEmailVerification] = osDisableEmailVerification == "true" - } - if osDisableEmailVerification != "" { - boolValue, err := strconv.ParseBool(osDisableEmailVerification) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisableEmailVerification].(bool) { - envData[constants.EnvKeyDisableEmailVerification] = boolValue - } - } - - if _, ok := envData[constants.EnvKeyDisableMagicLinkLogin]; !ok { - envData[constants.EnvKeyDisableMagicLinkLogin] = osDisableMagicLinkLogin == "true" - } - if osDisableMagicLinkLogin != "" { - boolValue, err := strconv.ParseBool(osDisableMagicLinkLogin) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisableMagicLinkLogin] { - envData[constants.EnvKeyDisableMagicLinkLogin] = boolValue - } - } - - if _, ok := envData[constants.EnvKeyDisableLoginPage]; !ok { - envData[constants.EnvKeyDisableLoginPage] = osDisableLoginPage == "true" - } - if osDisableLoginPage != "" { - boolValue, err := strconv.ParseBool(osDisableLoginPage) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisableLoginPage].(bool) { - envData[constants.EnvKeyDisableLoginPage] = boolValue - } - } - - if _, ok := envData[constants.EnvKeyDisableSignUp]; !ok { - envData[constants.EnvKeyDisableSignUp] = osDisableSignUp == "true" - } - if osDisableSignUp != "" { - boolValue, err := strconv.ParseBool(osDisableSignUp) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisableSignUp].(bool) { - envData[constants.EnvKeyDisableSignUp] = boolValue - } - } - - if _, ok := envData[constants.EnvKeyDisableRedisForEnv]; !ok { - envData[constants.EnvKeyDisableRedisForEnv] = osDisableRedisForEnv == "true" - } - if osDisableRedisForEnv != "" { - boolValue, err := strconv.ParseBool(osDisableRedisForEnv) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisableRedisForEnv].(bool) { - envData[constants.EnvKeyDisableRedisForEnv] = boolValue - } - } - - if _, ok := envData[constants.EnvKeyDisableStrongPassword]; !ok { - envData[constants.EnvKeyDisableStrongPassword] = osDisableStrongPassword == "true" - } - if osDisableStrongPassword != "" { - boolValue, err := strconv.ParseBool(osDisableStrongPassword) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisableStrongPassword].(bool) { - envData[constants.EnvKeyDisableStrongPassword] = boolValue - } - } - - if _, ok := envData[constants.EnvKeyEnforceMultiFactorAuthentication]; !ok { - envData[constants.EnvKeyEnforceMultiFactorAuthentication] = osEnforceMultiFactorAuthentication == "true" - } - if osEnforceMultiFactorAuthentication != "" { - boolValue, err := strconv.ParseBool(osEnforceMultiFactorAuthentication) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) { - envData[constants.EnvKeyEnforceMultiFactorAuthentication] = boolValue - } - } - - if _, ok := envData[constants.EnvKeyDisableMultiFactorAuthentication]; !ok { - envData[constants.EnvKeyDisableMultiFactorAuthentication] = osDisableMultiFactorAuthentication == "true" - } - if osDisableMultiFactorAuthentication != "" { - boolValue, err := strconv.ParseBool(osDisableMultiFactorAuthentication) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) { - envData[constants.EnvKeyDisableMultiFactorAuthentication] = boolValue - } - } - - // no need to add nil check as its already done above - if envData[constants.EnvKeySmtpHost] == "" || envData[constants.EnvKeySmtpUsername] == "" || envData[constants.EnvKeySmtpPassword] == "" || envData[constants.EnvKeySenderEmail] == "" && envData[constants.EnvKeySmtpPort] == "" { - envData[constants.EnvKeyDisableEmailVerification] = true - envData[constants.EnvKeyDisableMagicLinkLogin] = true - envData[constants.EnvKeyIsEmailServiceEnabled] = false - envData[constants.EnvKeyDisableMailOTPLogin] = true - } - - if envData[constants.EnvKeySmtpHost] != "" && envData[constants.EnvKeySmtpUsername] != "" && envData[constants.EnvKeySmtpPassword] != "" && envData[constants.EnvKeySenderEmail] != "" && envData[constants.EnvKeySmtpPort] != "" { - envData[constants.EnvKeyIsEmailServiceEnabled] = true - } - - if envData[constants.EnvKeyDisableEmailVerification].(bool) { - envData[constants.EnvKeyDisableMagicLinkLogin] = true - } - - if val, ok := envData[constants.EnvKeyAllowedOrigins]; !ok || val == "" { - envData[constants.EnvKeyAllowedOrigins] = osAllowedOrigins - if envData[constants.EnvKeyAllowedOrigins] == "" { - envData[constants.EnvKeyAllowedOrigins] = "*" - } - } - if osAllowedOrigins != "" && envData[constants.EnvKeyAllowedOrigins] != osAllowedOrigins { - envData[constants.EnvKeyAllowedOrigins] = osAllowedOrigins - } - - if val, ok := envData[constants.EnvKeyRoles]; !ok || val == "" { - envData[constants.EnvKeyRoles] = osRoles - if envData[constants.EnvKeyRoles] == "" { - envData[constants.EnvKeyRoles] = "user" - } - } - if osRoles != "" && envData[constants.EnvKeyRoles] != osRoles { - envData[constants.EnvKeyRoles] = osRoles - } - roles := strings.Split(envData[constants.EnvKeyRoles].(string), ",") - - if val, ok := envData[constants.EnvKeyDefaultRoles]; !ok || val == "" { - envData[constants.EnvKeyDefaultRoles] = osDefaultRoles - if envData[constants.EnvKeyDefaultRoles] == "" { - envData[constants.EnvKeyDefaultRoles] = "user" - } - } - if osDefaultRoles != "" && envData[constants.EnvKeyDefaultRoles] != osDefaultRoles { - envData[constants.EnvKeyDefaultRoles] = osDefaultRoles - } - defaultRoles := strings.Split(envData[constants.EnvKeyDefaultRoles].(string), ",") - if len(defaultRoles) == 0 { - defaultRoles = []string{roles[0]} - } - - for _, role := range defaultRoles { - if !utils.StringSliceContains(roles, role) { - return fmt.Errorf("Default role %s is not defined in roles", role) - } - } - - if val, ok := envData[constants.EnvKeyProtectedRoles]; !ok || val == "" { - envData[constants.EnvKeyProtectedRoles] = osProtectedRoles - } - if osProtectedRoles != "" && 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 - } - - if val, ok := envData[constants.EnvKeyTwilioAPISecret]; !ok || val == "" { - envData[constants.EnvKeyTwilioAPISecret] = osTwilioApiSecret - } - if osTwilioApiSecret != "" && envData[constants.EnvKeyTwilioAPISecret] != osTwilioApiSecret { - envData[constants.EnvKeyTwilioAPISecret] = osTwilioApiSecret - } - - if val, ok := envData[constants.EnvKeyTwilioAPIKey]; !ok || val == "" { - envData[constants.EnvKeyTwilioAPIKey] = osTwilioApiKey - } - if osTwilioApiKey != "" && envData[constants.EnvKeyTwilioAPIKey] != osTwilioApiKey { - envData[constants.EnvKeyTwilioAPIKey] = osTwilioApiKey - } - - if val, ok := envData[constants.EnvKeyTwilioAccountSID]; !ok || val == "" { - envData[constants.EnvKeyTwilioAccountSID] = osTwilioAccountSid - } - if osTwilioAccountSid != "" && envData[constants.EnvKeyTwilioAccountSID] != osTwilioAccountSid { - envData[constants.EnvKeyTwilioAccountSID] = osTwilioAccountSid - } - - if val, ok := envData[constants.EnvKeyTwilioSender]; !ok || val == "" { - envData[constants.EnvKeyTwilioSender] = osTwilioSender - } - if osTwilioSender != "" && envData[constants.EnvKeyTwilioSender] != osTwilioSender { - envData[constants.EnvKeyTwilioSender] = osTwilioSender - } - - if _, ok := envData[constants.EnvKeyDisablePhoneVerification]; !ok { - envData[constants.EnvKeyDisablePhoneVerification] = osDisablePhoneVerification == "false" - } - if osDisablePhoneVerification != "" { - boolValue, err := strconv.ParseBool(osDisablePhoneVerification) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisablePhoneVerification] { - envData[constants.EnvKeyDisablePhoneVerification] = boolValue - } - } - - if envData[constants.EnvKeyTwilioAPIKey] == "" || envData[constants.EnvKeyTwilioAPISecret] == "" || envData[constants.EnvKeyTwilioAccountSID] == "" || envData[constants.EnvKeyTwilioSender] == "" { - envData[constants.EnvKeyDisablePhoneVerification] = true - envData[constants.EnvKeyIsSMSServiceEnabled] = false - } - if envData[constants.EnvKeyTwilioAPIKey] != "" && envData[constants.EnvKeyTwilioAPISecret] != "" && envData[constants.EnvKeyTwilioAccountSID] != "" && envData[constants.EnvKeyTwilioSender] != "" { - envData[constants.EnvKeyDisablePhoneVerification] = false - envData[constants.EnvKeyIsSMSServiceEnabled] = true - } - - if _, ok := envData[constants.EnvKeyDisablePlayGround]; !ok { - envData[constants.EnvKeyDisablePlayGround] = osDisablePlayground == "true" - } - if osDisablePlayground != "" { - boolValue, err := strconv.ParseBool(osDisablePlayground) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisablePlayGround].(bool) { - envData[constants.EnvKeyDisablePlayGround] = boolValue - } - } - // TODO: remove after beta launch - envData[constants.EnvKeyDisableTOTPLogin] = true - if _, ok := envData[constants.EnvKeyDisableTOTPLogin]; !ok { - envData[constants.EnvKeyDisableTOTPLogin] = osDisableTOTPLogin == "true" - } - if osDisableTOTPLogin != "" { - boolValue, err := strconv.ParseBool(osDisableTOTPLogin) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisableTOTPLogin].(bool) { - envData[constants.EnvKeyDisableTOTPLogin] = boolValue - } - } - - if _, ok := envData[constants.EnvKeyDisableMailOTPLogin]; !ok { - envData[constants.EnvKeyDisableMailOTPLogin] = osDisableMailOTPLogin == "true" - } - if osDisableMailOTPLogin != "" { - boolValue, err := strconv.ParseBool(osDisableMailOTPLogin) - if err != nil { - return err - } - if boolValue != envData[constants.EnvKeyDisableMailOTPLogin].(bool) { - envData[constants.EnvKeyDisableMailOTPLogin] = boolValue - } - } - - err = memorystore.Provider.UpdateEnvStore(envData) - if err != nil { - log.Debug("Error while updating env store: ", err) - return err - } - return nil -} diff --git a/server/env/persist_env.go b/server/env/persist_env.go deleted file mode 100644 index a594d78eb..000000000 --- a/server/env/persist_env.go +++ /dev/null @@ -1,268 +0,0 @@ -package env - -import ( - "context" - "encoding/json" - "os" - "reflect" - "strconv" - "strings" - - "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/utils" -) - -func fixBackwardCompatibility(data map[string]interface{}) (bool, map[string]interface{}) { - result := data - // check if env data is stored in older format - hasOlderFormat := false - if _, ok := result["bool_env"]; ok { - for key, value := range result["bool_env"].(map[string]interface{}) { - result[key] = value - } - hasOlderFormat = true - delete(result, "bool_env") - } - - if _, ok := result["string_env"]; ok { - for key, value := range result["string_env"].(map[string]interface{}) { - result[key] = value - } - hasOlderFormat = true - delete(result, "string_env") - } - - if _, ok := result["slice_env"]; ok { - for key, value := range result["slice_env"].(map[string]interface{}) { - typeOfValue := reflect.TypeOf(value) - if strings.Contains(typeOfValue.String(), "[]string") { - result[key] = strings.Join(value.([]string), ",") - } - if strings.Contains(typeOfValue.String(), "[]interface") { - result[key] = strings.Join(utils.ConvertInterfaceToStringSlice(value), ",") - } - } - hasOlderFormat = true - delete(result, "slice_env") - } - - return hasOlderFormat, result -} - -// GetEnvData returns the env data from database -func GetEnvData() (map[string]interface{}, error) { - var result map[string]interface{} - ctx := context.Background() - env, err := db.Provider.GetEnv(ctx) - // config not found in db - if err != nil || env == nil { - log.Debug("Error while getting env data from db: ", err) - return result, err - } - - encryptionKey := env.Hash - decryptedEncryptionKey, err := crypto.DecryptB64(encryptionKey) - if err != nil { - log.Debug("Error while decrypting encryption key: ", err) - return result, err - } - - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey) - b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData) - if err != nil { - log.Debug("Error while decrypting env data from B64: ", err) - return result, err - } - - decryptedConfigs, err := crypto.DecryptAESEnv([]byte(b64DecryptedConfig)) - if err != nil { - log.Debug("Error while decrypting env data from AES: ", err) - return result, err - } - - err = json.Unmarshal(decryptedConfigs, &result) - if err != nil { - log.Debug("Error while unmarshalling env data: ", err) - return result, err - } - - hasOlderFormat, result := fixBackwardCompatibility(result) - - if hasOlderFormat { - err = memorystore.Provider.UpdateEnvStore(result) - if err != nil { - log.Debug("Error while updating env store: ", err) - return result, err - } - - } - - return result, err -} - -// PersistEnv persists the environment variables to the database -func PersistEnv() error { - ctx := context.Background() - env, err := db.Provider.GetEnv(ctx) - // config not found in db - if err != nil || env == nil { - // AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid - hash := uuid.New().String()[:36-4] - err := memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, hash) - if err != nil { - log.Debug("Error while updating encryption env variable: ", err) - return err - } - encodedHash := crypto.EncryptB64(hash) - res, err := memorystore.Provider.GetEnvStore() - if err != nil { - log.Debug("Error while getting env store: ", err) - return err - } - encryptedConfig, err := crypto.EncryptEnvData(res) - if err != nil { - log.Debug("Error while encrypting env data: ", err) - return err - } - env = &models.Env{ - Hash: encodedHash, - EnvData: encryptedConfig, - } - _, err = db.Provider.AddEnv(ctx, env) - if err != nil { - log.Debug("Error while persisting env data to db: ", err) - return err - } - } else { - // decrypt the config data from db - // decryption can be done using the hash stored in db - encryptionKey := env.Hash - decryptedEncryptionKey, err := crypto.DecryptB64(encryptionKey) - if err != nil { - log.Debug("Error while decrypting encryption key: ", err) - return err - } - - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey) - - b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData) - if err != nil { - log.Debug("Error while decrypting env data from B64: ", err) - return err - } - - decryptedConfigs, err := crypto.DecryptAESEnv([]byte(b64DecryptedConfig)) - if err != nil { - log.Debug("Error while decrypting env data from AES: ", err) - return err - } - - // temp store variable - storeData := map[string]interface{}{} - - err = json.Unmarshal(decryptedConfigs, &storeData) - if err != nil { - log.Debug("Error while un-marshalling env data: ", err) - return err - } - - hasOlderFormat, result := fixBackwardCompatibility(storeData) - if hasOlderFormat { - err = memorystore.Provider.UpdateEnvStore(result) - if err != nil { - log.Debug("Error while updating env store: ", err) - return err - } - - } - - // if env is changed via env file or OS env - // give that higher preference and update db, but we don't recommend it - - hasChanged := false - for key, value := range storeData { - // don't override unexposed envs - // check only for derivative keys - // No need to check for ENCRYPTION_KEY which special key we use for encrypting config data - // as we have removed it from json - if key != constants.EnvKeyEncryptionKey { - envValue := strings.TrimSpace(os.Getenv(key)) - if envValue != "" { - switch key { - case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyIsSMSServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure, constants.EnvKeyDisablePhoneVerification, constants.EnvKeyDisablePlayGround, constants.EnvKeyDisableTOTPLogin, constants.EnvKeyDisableMailOTPLogin: - if envValueBool, err := strconv.ParseBool(envValue); err == nil { - if value.(bool) != envValueBool { - storeData[key] = envValueBool - hasChanged = true - } - } - default: - if value != nil && value.(string) != envValue { - storeData[key] = envValue - hasChanged = true - } - } - } - } - } - - // handle derivative cases like disabling email verification & magic login - // in case SMTP is off but env is set to true - if storeData[constants.EnvKeySmtpHost] == "" || storeData[constants.EnvKeySmtpUsername] == "" || storeData[constants.EnvKeySmtpPassword] == "" || storeData[constants.EnvKeySenderEmail] == "" && storeData[constants.EnvKeySmtpPort] == "" { - storeData[constants.EnvKeyIsEmailServiceEnabled] = false - - if val, ok := storeData[constants.EnvKeyDisableEmailVerification]; ok && val != nil && !val.(bool) { - storeData[constants.EnvKeyDisableEmailVerification] = true - hasChanged = true - } - - if val, ok := storeData[constants.EnvKeyDisableMagicLinkLogin]; ok && val != nil && !val.(bool) { - storeData[constants.EnvKeyDisableMagicLinkLogin] = true - hasChanged = true - } - - if val, ok := storeData[constants.EnvKeyDisableMailOTPLogin]; ok && val != nil && !val.(bool) { - storeData[constants.EnvKeyDisableMailOTPLogin] = true - hasChanged = true - } - } - - err = memorystore.Provider.UpdateEnvStore(storeData) - if err != nil { - log.Debug("Error while updating env store: ", err) - return err - } - - jwk, err := crypto.GenerateJWKBasedOnEnv() - if err != nil { - log.Debug("Error while generating JWK: ", err) - return err - } - // updating jwk - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJWK, jwk) - - if hasChanged { - encryptedConfig, err := crypto.EncryptEnvData(storeData) - if err != nil { - log.Debug("Error while encrypting env data: ", err) - return err - } - - env.EnvData = encryptedConfig - _, err = db.Provider.UpdateEnv(ctx, env) - if err != nil { - log.Debug("Failed to Update Config: ", err) - return err - } - } - } - - return nil -} diff --git a/server/handlers/dashboard.go b/server/handlers/dashboard.go deleted file mode 100644 index 55d1534de..000000000 --- a/server/handlers/dashboard.go +++ /dev/null @@ -1,26 +0,0 @@ -package handlers - -import ( - "net/http" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/gin-gonic/gin" -) - -// DashboardHandler is the handler for the /dashboard route -func DashboardHandler() gin.HandlerFunc { - return func(c *gin.Context) { - isOnboardingCompleted := false - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - if err != nil || adminSecret != "" { - isOnboardingCompleted = true - } - - c.HTML(http.StatusOK, "dashboard.tmpl", gin.H{ - "data": map[string]interface{}{ - "isOnboardingCompleted": isOnboardingCompleted, - }, - }) - } -} diff --git a/server/handlers/graphql.go b/server/handlers/graphql.go deleted file mode 100644 index 367a9569a..000000000 --- a/server/handlers/graphql.go +++ /dev/null @@ -1,19 +0,0 @@ -package handlers - -import ( - "github.com/99designs/gqlgen/graphql/handler" - "github.com/authorizerdev/authorizer/server/graph" - "github.com/authorizerdev/authorizer/server/graph/generated" - "github.com/gin-gonic/gin" -) - -// GraphqlHandler is the main handler that handels all the graphql requests -func GraphqlHandler() gin.HandlerFunc { - // NewExecutableSchema and Config are in the generated.go file - // Resolver is in the resolver.go file - h := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{}})) - - return func(c *gin.Context) { - h.ServeHTTP(c.Writer, c.Request) - } -} diff --git a/server/handlers/jwks.go b/server/handlers/jwks.go deleted file mode 100644 index 1d71967d6..000000000 --- a/server/handlers/jwks.go +++ /dev/null @@ -1,38 +0,0 @@ -package handlers - -import ( - "encoding/json" - - "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -func JWKsHandler() gin.HandlerFunc { - return func(c *gin.Context) { - var data map[string]string - jwk, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJWK) - if err != nil { - log.Debug("Error getting JWK from memorystore: ", err) - c.JSON(500, gin.H{ - "error": err.Error(), - }) - return - } - err = json.Unmarshal([]byte(jwk), &data) - if err != nil { - log.Debug("Failed to parse JWK: ", err) - c.JSON(500, gin.H{ - "error": err.Error(), - }) - return - } - c.JSON(200, gin.H{ - "keys": []map[string]string{ - data, - }, - }) - } -} diff --git a/server/handlers/oauth_login.go b/server/handlers/oauth_login.go deleted file mode 100644 index b41485f0a..000000000 --- a/server/handlers/oauth_login.go +++ /dev/null @@ -1,296 +0,0 @@ -package handlers - -import ( - "net/http" - "strings" - - "golang.org/x/oauth2" - - "github.com/gin-gonic/gin" - "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/oauth" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" -) - -// OAuthLoginHandler set host in the oauth state that is useful for redirecting to oauth_callback -func OAuthLoginHandler() gin.HandlerFunc { - return func(c *gin.Context) { - hostname := parsers.GetHost(c) - // deprecating redirectURL instead use redirect_uri - redirectURI := strings.TrimSpace(c.Query("redirectURL")) - if redirectURI == "" { - redirectURI = strings.TrimSpace(c.Query("redirect_uri")) - } - roles := strings.TrimSpace(c.Query("roles")) - state := strings.TrimSpace(c.Query("state")) - scopeString := strings.TrimSpace(c.Query("scope")) - - if redirectURI == "" { - log.Debug("redirect_uri is empty") - c.JSON(400, gin.H{ - "error": "invalid redirect uri", - }) - return - } - - if state == "" { - log.Debug("state is empty. creating a new state") - state = uuid.New().String() - } - - var scope []string - if scopeString == "" { - scope = []string{"openid", "profile", "email"} - } else { - scope = strings.Split(scopeString, " ") - } - - if roles != "" { - // validate role - rolesSplit := strings.Split(roles, ",") - - // use protected roles verification for admin login only. - // though if not associated with user, it will be rejected from oauth_callback - rolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRoles) - roles := []string{} - if err != nil { - log.Debug("Error getting roles: ", err) - rolesString = "" - } else { - roles = strings.Split(rolesString, ",") - } - - protectedRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyProtectedRoles) - protectedRoles := []string{} - if err != nil { - log.Debug("Error getting protected roles: ", err) - protectedRolesString = "" - } else { - protectedRoles = strings.Split(protectedRolesString, ",") - } - - if !validators.IsValidRoles(rolesSplit, append([]string{}, append(roles, protectedRoles...)...)) { - log.Debug("Invalid roles: ", roles) - c.JSON(400, gin.H{ - "error": "invalid role", - }) - return - } - } else { - defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - log.Debug("Error getting default roles: ", err) - c.JSON(400, gin.H{ - "error": "invalid role", - }) - return - } - roles = defaultRoles - - } - - oauthStateString := state + "___" + redirectURI + "___" + roles + "___" + strings.Join(scope, " ") - - provider := c.Param("oauth_provider") - isProviderConfigured := true - switch provider { - case constants.AuthRecipeMethodGoogle: - if oauth.OAuthProviders.GoogleConfig == nil { - log.Debug("Google OAuth provider is not configured") - isProviderConfigured = false - break - } - err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodGoogle) - 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.GoogleConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodGoogle - url := oauth.OAuthProviders.GoogleConfig.AuthCodeURL(oauthStateString) - c.Redirect(http.StatusTemporaryRedirect, url) - case constants.AuthRecipeMethodGithub: - if oauth.OAuthProviders.GithubConfig == nil { - log.Debug("Github OAuth provider is not configured") - isProviderConfigured = false - break - } - err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodGithub) - if err != nil { - log.Debug("Error setting state: ", err) - c.JSON(500, gin.H{ - "error": "internal server error", - }) - return - } - oauth.OAuthProviders.GithubConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodGithub - url := oauth.OAuthProviders.GithubConfig.AuthCodeURL(oauthStateString) - c.Redirect(http.StatusTemporaryRedirect, url) - case constants.AuthRecipeMethodFacebook: - if oauth.OAuthProviders.FacebookConfig == nil { - log.Debug("Facebook OAuth provider is not configured") - isProviderConfigured = false - break - } - err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodFacebook) - if err != nil { - log.Debug("Error setting state: ", err) - c.JSON(500, gin.H{ - "error": "internal server error", - }) - return - } - oauth.OAuthProviders.FacebookConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodFacebook - url := oauth.OAuthProviders.FacebookConfig.AuthCodeURL(oauthStateString) - c.Redirect(http.StatusTemporaryRedirect, url) - case constants.AuthRecipeMethodLinkedIn: - if oauth.OAuthProviders.LinkedInConfig == nil { - log.Debug("Linkedin OAuth provider is not configured") - isProviderConfigured = false - break - } - err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodLinkedIn) - if err != nil { - log.Debug("Error setting state: ", err) - c.JSON(500, gin.H{ - "error": "internal server error", - }) - return - } - oauth.OAuthProviders.LinkedInConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodLinkedIn - url := oauth.OAuthProviders.LinkedInConfig.AuthCodeURL(oauthStateString) - c.Redirect(http.StatusTemporaryRedirect, url) - case constants.AuthRecipeMethodTwitter: - if oauth.OAuthProviders.TwitterConfig == nil { - log.Debug("Twitter OAuth provider is not configured") - isProviderConfigured = false - break - } - - verifier, challenge := utils.GenerateCodeChallenge() - - err := memorystore.Provider.SetState(oauthStateString, verifier) - if err != nil { - log.Debug("Error setting state: ", err) - c.JSON(500, gin.H{ - "error": "internal server error", - }) - return - } - oauth.OAuthProviders.TwitterConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodTwitter - url := oauth.OAuthProviders.TwitterConfig.AuthCodeURL(oauthStateString, oauth2.SetAuthURLParam("code_challenge", challenge), oauth2.SetAuthURLParam("code_challenge_method", "S256")) - c.Redirect(http.StatusTemporaryRedirect, url) - - case constants.AuthRecipeMethodDiscord: - if oauth.OAuthProviders.DiscordConfig == nil { - log.Debug("Discord OAuth provider is not configured") - isProviderConfigured = false - break - } - err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodDiscord) - if err != nil { - log.Debug("Error setting state: ", err) - c.JSON(500, gin.H{ - "error": "internal server error", - }) - return - } - oauth.OAuthProviders.DiscordConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodDiscord - url := oauth.OAuthProviders.DiscordConfig.AuthCodeURL(oauthStateString) - c.Redirect(http.StatusTemporaryRedirect, url) - case constants.AuthRecipeMethodApple: - if oauth.OAuthProviders.AppleConfig == nil { - log.Debug("Apple OAuth provider is not configured") - isProviderConfigured = false - break - } - err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodApple) - if err != nil { - log.Debug("Error setting state: ", err) - c.JSON(500, gin.H{ - "error": "internal server error", - }) - return - } - oauth.OAuthProviders.AppleConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodApple - // there is scope encoding issue with oauth2 and how apple expects, hence added scope manually - // check: https://github.com/golang/oauth2/issues/449 - url := oauth.OAuthProviders.AppleConfig.AuthCodeURL(oauthStateString, oauth2.SetAuthURLParam("response_mode", "form_post")) + "&scope=name email" - 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) - case constants.AuthRecipeMethodTwitch: - if oauth.OAuthProviders.TwitchConfig == nil { - log.Debug("Twitch OAuth provider is not configured") - isProviderConfigured = false - break - } - err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodTwitch) - 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.TwitchConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodTwitch - url := oauth.OAuthProviders.TwitchConfig.AuthCodeURL(oauthStateString) - c.Redirect(http.StatusTemporaryRedirect, url) - case constants.AuthRecipeMethodRoblox: - if oauth.OAuthProviders.RobloxConfig == nil { - log.Debug("RobloxConfig OAuth provider is not configured") - isProviderConfigured = false - break - } - err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodRoblox) - 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.RobloxConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodRoblox - url := oauth.OAuthProviders.RobloxConfig.AuthCodeURL(oauthStateString) - c.Redirect(http.StatusTemporaryRedirect, url) - default: - log.Debug("Invalid oauth provider: ", provider) - c.JSON(422, gin.H{ - "message": "Invalid oauth provider", - }) - } - - if !isProviderConfigured { - c.JSON(422, gin.H{ - "message": provider + " not configured", - }) - } - } -} diff --git a/server/handlers/playground.go b/server/handlers/playground.go deleted file mode 100644 index 14ce52fc2..000000000 --- a/server/handlers/playground.go +++ /dev/null @@ -1,44 +0,0 @@ -package handlers - -import ( - "net/http" - - "github.com/99designs/gqlgen/graphql/playground" - "github.com/gin-gonic/gin" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" -) - -// PlaygroundHandler is the handler for the /playground route -func PlaygroundHandler() gin.HandlerFunc { - return func(c *gin.Context) { - var h http.HandlerFunc - - disablePlayground, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePlayGround) - if err != nil { - log.Debug("error while getting disable playground value") - disablePlayground = false - } - - // if env set to false, then check if logged in as super admin, if logged in then return graphql else 401 error - // if env set to true, then disabled the playground with 404 error - if !disablePlayground { - if token.IsSuperAdmin(c) { - h = playground.Handler("GraphQL", "/graphql") - } else { - log.Debug("not logged in as super admin") - c.JSON(http.StatusUnauthorized, gin.H{"error": "not logged in as super admin"}) - return - } - } else { - log.Debug("playground is disabled") - c.JSON(http.StatusNotFound, gin.H{"error": "playground is disabled"}) - return - } - h.ServeHTTP(c.Writer, c.Request) - } -} diff --git a/server/handlers/revoke_refresh_token.go b/server/handlers/revoke_refresh_token.go deleted file mode 100644 index 366efd72c..000000000 --- a/server/handlers/revoke_refresh_token.go +++ /dev/null @@ -1,76 +0,0 @@ -package handlers - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" -) - -// RevokeRefreshTokenHandler handler to revoke refresh token -func RevokeRefreshTokenHandler() gin.HandlerFunc { - return func(gc *gin.Context) { - var reqBody map[string]string - if err := gc.BindJSON(&reqBody); err != nil { - log.Debug("Error binding JSON: ", err) - gc.JSON(http.StatusBadRequest, gin.H{ - "error": "error_binding_json", - "error_description": err.Error(), - }) - return - } - // get client ID - clientID := strings.TrimSpace(reqBody["client_id"]) // kept for backward compatibility // else we expect to be present as header - if clientID == "" { - clientID = gc.Request.Header.Get("x-authorizer-client-id") - } - // get fingerprint hash - refreshToken := strings.TrimSpace(reqBody["refresh_token"]) - - if clientID == "" { - log.Debug("Client ID is empty") - gc.JSON(http.StatusBadRequest, gin.H{ - "error": "client_id_required", - "error_description": "The client id is required", - }) - return - } - - if client, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); client != clientID || err != nil { - log.Debug("Client ID is invalid: ", clientID) - gc.JSON(http.StatusBadRequest, gin.H{ - "error": "invalid_client_id", - "error_description": "The client id is invalid", - }) - return - } - - claims, err := token.ParseJWTToken(refreshToken) - if err != nil { - log.Debug("Client ID is invalid: ", clientID) - gc.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - "error_description": "Failed to parse jwt", - }) - return - } - - userID := claims["sub"].(string) - loginMethod := claims["login_method"] - sessionToken := userID - if loginMethod != nil && loginMethod != "" { - sessionToken = loginMethod.(string) + ":" + userID - } - - memorystore.Provider.DeleteUserSession(sessionToken, claims["nonce"].(string)) - - gc.JSON(http.StatusOK, gin.H{ - "message": "Token revoked successfully", - }) - } -} diff --git a/server/logs/logs.go b/server/logs/logs.go deleted file mode 100644 index 924548c4c..000000000 --- a/server/logs/logs.go +++ /dev/null @@ -1,61 +0,0 @@ -package logs - -import ( - "os" - - "github.com/sirupsen/logrus" - log "github.com/sirupsen/logrus" -) - -// LogUTCFormatter hels in setting UTC time format for the logs -type LogUTCFormatter struct { - log.Formatter -} - -// Format helps fomratting time to UTC -func (u LogUTCFormatter) Format(e *log.Entry) ([]byte, error) { - e.Time = e.Time.UTC() - return u.Formatter.Format(e) -} - -func InitLog(cliLogLevel string) *log.Logger { - - // log instance for gin server - log := logrus.New() - log.SetFormatter(LogUTCFormatter{&logrus.JSONFormatter{}}) - - if cliLogLevel == "" { - cliLogLevel = os.Getenv("LOG_LEVEL") - } - - var logLevel logrus.Level - switch cliLogLevel { - case "debug": - logLevel = logrus.DebugLevel - case "info": - logLevel = logrus.InfoLevel - case "warn": - logLevel = logrus.WarnLevel - case "error": - logLevel = logrus.ErrorLevel - case "fatal": - logLevel = logrus.FatalLevel - case "panic": - logLevel = logrus.PanicLevel - default: - logLevel = logrus.InfoLevel - } - // set log level globally - logrus.SetLevel(logLevel) - - // set log level for go-gin middleware - log.SetLevel(logLevel) - - // show file path in log for debug or other log levels. - if logLevel != logrus.InfoLevel { - logrus.SetReportCaller(true) - log.SetReportCaller(true) - } - - return log -} diff --git a/server/main.go b/server/main.go deleted file mode 100644 index 0348d2aa8..000000000 --- a/server/main.go +++ /dev/null @@ -1,89 +0,0 @@ -package main - -import ( - "flag" - "github.com/authorizerdev/authorizer/server/authenticators" - - "github.com/authorizerdev/authorizer/server/cli" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/env" - "github.com/authorizerdev/authorizer/server/logs" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/oauth" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/routes" - "github.com/sirupsen/logrus" -) - -// VERSION is used to define the version of authorizer from build tags -var VERSION string - -func main() { - cli.ARG_DB_URL = flag.String("database_url", "", "Database connection string") - cli.ARG_DB_TYPE = flag.String("database_type", "", "Database type, possible values are postgres,mysql,sqlite") - cli.ARG_ENV_FILE = flag.String("env_file", "", "Env file path") - cli.ARG_LOG_LEVEL = flag.String("log_level", "", "Log level, possible values are debug,info,warn,error,fatal,panic") - cli.ARG_REDIS_URL = flag.String("redis_url", "", "Redis connection string") - flag.Parse() - - // global log level - logrus.SetFormatter(logs.LogUTCFormatter{&logrus.JSONFormatter{}}) - - constants.VERSION = VERSION - - // initialize required envs (mainly db, env file path and redis) - err := memorystore.InitRequiredEnv() - if err != nil { - logrus.Fatal("Error while initializing required envs: ", err) - } - - log := logs.InitLog(refs.StringValue(cli.ARG_LOG_LEVEL)) - - // initialize memory store - err = memorystore.InitMemStore() - if err != nil { - log.Fatal("Error while initializing memory store: ", err) - } - - // initialize db provider - err = db.InitDB() - if err != nil { - log.Fatalln("Error while initializing db: ", err) - } - - // initialize all envs - // (get if present from db else construct from os env + defaults) - err = env.InitAllEnv() - if err != nil { - log.Fatalln("Error while initializing env: ", err) - } - - // persist all envs - err = env.PersistEnv() - if err != nil { - log.Fatalln("Error while persisting env: ", err) - } - - // initialize oauth providers based on env - err = oauth.InitOAuth() - if err != nil { - log.Fatalln("Error while initializing oauth: ", err) - } - - err = authenticators.InitTOTPStore() - if err != nil { - log.Fatalln("Error while initializing authenticator: ", err) - } - - router := routes.InitRouter(log) - log.Info("Starting Authorizer: ", VERSION) - port, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyPort) - log.Info("Authorizer running at PORT: ", port) - if err != nil { - log.Info("Error while getting port from env using default port 8080: ", err) - port = "8080" - } - - router.Run(":" + port) -} diff --git a/server/memorystore/memory_store.go b/server/memorystore/memory_store.go deleted file mode 100644 index a143d041c..000000000 --- a/server/memorystore/memory_store.go +++ /dev/null @@ -1,87 +0,0 @@ -package memorystore - -import ( - "encoding/json" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore/providers" - "github.com/authorizerdev/authorizer/server/memorystore/providers/inmemory" - "github.com/authorizerdev/authorizer/server/memorystore/providers/redis" -) - -// Provider returns the current database provider -var Provider providers.Provider - -// InitMemStore initializes the memory store -func InitMemStore() error { - var err error - - defaultEnvs := map[string]interface{}{ - // string envs - constants.EnvKeyJwtRoleClaim: "role", - constants.EnvKeyOrganizationName: "Authorizer", - constants.EnvKeyOrganizationLogo: "https://www.authorizer.dev/images/logo.png", - - // boolean envs - constants.EnvKeyDisableBasicAuthentication: false, - constants.EnvKeyDisableMobileBasicAuthentication: false, - constants.EnvKeyDisableMagicLinkLogin: false, - constants.EnvKeyDisableEmailVerification: false, - constants.EnvKeyDisableLoginPage: false, - constants.EnvKeyDisableSignUp: false, - constants.EnvKeyDisableStrongPassword: false, - constants.EnvKeyIsEmailServiceEnabled: false, - constants.EnvKeyIsSMSServiceEnabled: false, - constants.EnvKeyEnforceMultiFactorAuthentication: false, - constants.EnvKeyDisableMultiFactorAuthentication: false, - constants.EnvKeyDisableTOTPLogin: false, - constants.EnvKeyAppCookieSecure: true, - constants.EnvKeyAdminCookieSecure: true, - constants.EnvKeyDisablePlayGround: true, - constants.EnvKeyDisableMailOTPLogin: true, - } - - requiredEnvs := RequiredEnvStoreObj.GetRequiredEnv() - requiredEnvMap := make(map[string]interface{}) - requiredEnvBytes, err := json.Marshal(requiredEnvs) - if err != nil { - log.Debug("Error while marshalling required envs: ", err) - return err - } - err = json.Unmarshal(requiredEnvBytes, &requiredEnvMap) - if err != nil { - log.Debug("Error while unmarshalling required envs: ", err) - return err - } - - // merge default envs with required envs - for key, val := range requiredEnvMap { - defaultEnvs[key] = val - } - - redisURL := requiredEnvs.RedisURL - if redisURL != "" && !requiredEnvs.DisableRedisForEnv { - log.Info("Initializing Redis memory store") - Provider, err = redis.NewRedisProvider(redisURL) - if err != nil { - return err - } - - // set default envs in redis - Provider.UpdateEnvStore(defaultEnvs) - - return nil - } - - log.Info("using in memory store to save sessions") - // if redis url is not set use in memory store - Provider, err = inmemory.NewInMemoryProvider() - if err != nil { - return err - } - // set default envs in local env - Provider.UpdateEnvStore(defaultEnvs) - return nil -} diff --git a/server/memorystore/providers/inmemory/provider.go b/server/memorystore/providers/inmemory/provider.go deleted file mode 100644 index e726502a1..000000000 --- a/server/memorystore/providers/inmemory/provider.go +++ /dev/null @@ -1,26 +0,0 @@ -package inmemory - -import ( - "sync" - - "github.com/authorizerdev/authorizer/server/memorystore/providers/inmemory/stores" -) - -type provider struct { - mutex sync.Mutex - sessionStore *stores.SessionStore - mfasessionStore *stores.SessionStore - stateStore *stores.StateStore - envStore *stores.EnvStore -} - -// NewInMemoryStore returns a new in-memory store. -func NewInMemoryProvider() (*provider, error) { - return &provider{ - mutex: sync.Mutex{}, - envStore: stores.NewEnvStore(), - sessionStore: stores.NewSessionStore(), - mfasessionStore: stores.NewSessionStore(), - stateStore: stores.NewStateStore(), - }, nil -} diff --git a/server/memorystore/providers/inmemory/provider_test.go b/server/memorystore/providers/inmemory/provider_test.go deleted file mode 100644 index 99446a19e..000000000 --- a/server/memorystore/providers/inmemory/provider_test.go +++ /dev/null @@ -1,14 +0,0 @@ -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) -} diff --git a/server/memorystore/providers/inmemory/stores/env_store.go b/server/memorystore/providers/inmemory/stores/env_store.go deleted file mode 100644 index 46a909abc..000000000 --- a/server/memorystore/providers/inmemory/stores/env_store.go +++ /dev/null @@ -1,52 +0,0 @@ -package stores - -import ( - "sync" -) - -// EnvStore struct to store the env variables -type EnvStore struct { - mutex sync.Mutex - store map[string]interface{} -} - -// NewEnvStore create a new env store -func NewEnvStore() *EnvStore { - return &EnvStore{ - mutex: sync.Mutex{}, - store: make(map[string]interface{}), - } -} - -// UpdateEnvStore to update the whole env store object -func (e *EnvStore) UpdateStore(store map[string]interface{}) { - e.mutex.Lock() - defer e.mutex.Unlock() - - // just override the keys + new keys - for key, value := range store { - e.store[key] = value - } -} - -// GetStore returns the env store -func (e *EnvStore) GetStore() map[string]interface{} { - e.mutex.Lock() - defer e.mutex.Unlock() - return e.store -} - -// Get returns the value of the key in evn store -func (e *EnvStore) Get(key string) interface{} { - e.mutex.Lock() - defer e.mutex.Unlock() - return e.store[key] -} - -// Set sets the value of the key in env store -func (e *EnvStore) Set(key string, value interface{}) { - e.mutex.Lock() - defer e.mutex.Unlock() - - e.store[key] = value -} diff --git a/server/memorystore/providers/provider_tests.go b/server/memorystore/providers/provider_tests.go deleted file mode 100644 index 47f4dba66..000000000 --- a/server/memorystore/providers/provider_tests.go +++ /dev/null @@ -1,126 +0,0 @@ -package providers - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -// ProviderTests runs all provider tests -func ProviderTests(t *testing.T, p Provider) { - - err := p.SetUserSession("auth_provider:123", "session_token_key", "test_hash123", time.Now().Add(60*time.Second).Unix()) - assert.NoError(t, err) - err = p.SetUserSession("auth_provider:123", "access_token_key", "test_jwt123", time.Now().Add(60*time.Second).Unix()) - assert.NoError(t, err) - // Same user multiple session - err = p.SetUserSession("auth_provider:123", "session_token_key1", "test_hash1123", time.Now().Add(60*time.Second).Unix()) - assert.NoError(t, err) - err = p.SetUserSession("auth_provider:123", "access_token_key1", "test_jwt1123", time.Now().Add(60*time.Second).Unix()) - assert.NoError(t, err) - // Different user session - err = p.SetUserSession("auth_provider:124", "session_token_key", "test_hash124", time.Now().Add(5*time.Second).Unix()) - assert.NoError(t, err) - err = p.SetUserSession("auth_provider:124", "access_token_key", "test_jwt124", time.Now().Add(5*time.Second).Unix()) - assert.NoError(t, err) - // Different provider session - err = p.SetUserSession("auth_provider1:124", "session_token_key", "test_hash124", time.Now().Add(60*time.Second).Unix()) - assert.NoError(t, err) - err = p.SetUserSession("auth_provider1:124", "access_token_key", "test_jwt124", time.Now().Add(60*time.Second).Unix()) - assert.NoError(t, err) - // Different provider session - err = p.SetUserSession("auth_provider1:123", "session_token_key", "test_hash1123", time.Now().Add(60*time.Second).Unix()) - assert.NoError(t, err) - err = p.SetUserSession("auth_provider1:123", "access_token_key", "test_jwt1123", time.Now().Add(60*time.Second).Unix()) - assert.NoError(t, err) - // Get session - key, err := p.GetUserSession("auth_provider:123", "session_token_key") - assert.NoError(t, err) - assert.Equal(t, "test_hash123", key) - key, err = p.GetUserSession("auth_provider:123", "access_token_key") - assert.NoError(t, err) - assert.Equal(t, "test_jwt123", key) - key, err = p.GetUserSession("auth_provider:124", "session_token_key") - assert.NoError(t, err) - assert.Equal(t, "test_hash124", key) - key, err = p.GetUserSession("auth_provider:124", "access_token_key") - assert.NoError(t, err) - assert.Equal(t, "test_jwt124", key) - // Expire some tokens and make sure they are empty - time.Sleep(5 * time.Second) - key, err = p.GetUserSession("auth_provider:124", "session_token_key") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider:124", "access_token_key") - assert.Empty(t, key) - assert.Error(t, err) - // Delete user session - err = p.DeleteUserSession("auth_provider:123", "key") - assert.NoError(t, err) - err = p.DeleteUserSession("auth_provider:123", "key") - assert.NoError(t, err) - key, err = p.GetUserSession("auth_provider:123", "key") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider:123", "access_token_key") - assert.Empty(t, key) - assert.Error(t, err) - // Delete all user session - err = p.DeleteAllUserSessions("123") - assert.NoError(t, err) - err = p.DeleteAllUserSessions("123") - assert.NoError(t, err) - key, err = p.GetUserSession("auth_provider:123", "session_token_key1") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider:123", "access_token_key1") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider1:123", "session_token_key") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider1:123", "access_token_key") - assert.Empty(t, key) - assert.Error(t, err) - // Delete namespace - err = p.DeleteSessionForNamespace("auth_provider") - assert.NoError(t, err) - err = p.DeleteSessionForNamespace("auth_provider1") - assert.NoError(t, err) - key, err = p.GetUserSession("auth_provider:123", "session_token_key1") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider:123", "access_token_key1") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider1:123", "session_token_key") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider1:123", "access_token_key") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider:124", "session_token_key1") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider:124", "access_token_key1") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider1:124", "session_token_key") - assert.Empty(t, key) - assert.Error(t, err) - key, err = p.GetUserSession("auth_provider1:124", "access_token_key") - assert.Empty(t, key) - assert.Error(t, err) - - err = p.SetMfaSession("auth_provider:123", "session123", time.Now().Add(60*time.Second).Unix()) - assert.NoError(t, err) - key, err = p.GetMfaSession("auth_provider:123", "session123") - assert.NoError(t, err) - assert.Equal(t, "auth_provider:123", key) - err = p.DeleteMfaSession("auth_provider:123", "session123") - assert.NoError(t, err) - key, err = p.GetMfaSession("auth_provider:123", "session123") - assert.Error(t, err) - assert.Empty(t, key) -} diff --git a/server/memorystore/providers/redis/provider_test.go b/server/memorystore/providers/redis/provider_test.go deleted file mode 100644 index 280616cfb..000000000 --- a/server/memorystore/providers/redis/provider_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package redis - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/authorizerdev/authorizer/server/memorystore/providers" -) - -func TestRedisProvider(t *testing.T) { - p, err := NewRedisProvider("redis://127.0.0.1:6379") - assert.NoError(t, err) - providers.ProviderTests(t, p) -} diff --git a/server/memorystore/providers/redis/store.go b/server/memorystore/providers/redis/store.go deleted file mode 100644 index a1b21db65..000000000 --- a/server/memorystore/providers/redis/store.go +++ /dev/null @@ -1,220 +0,0 @@ -package redis - -import ( - "fmt" - "strconv" - "time" - - "github.com/authorizerdev/authorizer/server/constants" - log "github.com/sirupsen/logrus" -) - -var ( - // state store prefix - stateStorePrefix = "authorizer_state:" - // env store prefix - envStorePrefix = "authorizer_env" -) - -const mfaSessionPrefix = "mfa_sess_" - -// SetUserSession sets the user session for given user identifier in form recipe:user_id -func (c *provider) SetUserSession(userId, key, token string, expiration int64) error { - currentTime := time.Now() - expireTime := time.Unix(expiration, 0) - duration := expireTime.Sub(currentTime) - err := c.store.Set(c.ctx, fmt.Sprintf("%s:%s", userId, key), token, duration).Err() - if err != nil { - log.Debug("Error saving user session to redis: ", err) - return err - } - return nil -} - -// GetUserSession returns the user session from redis store. -func (c *provider) GetUserSession(userId, key string) (string, error) { - data, err := c.store.Get(c.ctx, fmt.Sprintf("%s:%s", userId, key)).Result() - if err != nil { - return "", err - } - return data, nil -} - -// DeleteUserSession deletes the user session from redis store. -func (c *provider) DeleteUserSession(userId, key string) error { - if err := c.store.Del(c.ctx, fmt.Sprintf("%s:%s", userId, constants.TokenTypeSessionToken+"_"+key)).Err(); err != nil { - log.Debug("Error deleting user session from redis: ", err) - // continue - } - if err := c.store.Del(c.ctx, fmt.Sprintf("%s:%s", userId, constants.TokenTypeAccessToken+"_"+key)).Err(); err != nil { - log.Debug("Error deleting user session from redis: ", err) - // continue - } - if err := c.store.Del(c.ctx, fmt.Sprintf("%s:%s", userId, constants.TokenTypeRefreshToken+"_"+key)).Err(); err != nil { - log.Debug("Error deleting user session from redis: ", err) - // continue - } - return nil -} - -// DeleteAllUserSessions deletes all the user session from redis -func (c *provider) DeleteAllUserSessions(userID string) error { - res := c.store.Keys(c.ctx, fmt.Sprintf("*%s*", userID)) - if res.Err() != nil { - log.Debug("Error getting all user sessions from redis: ", res.Err()) - return res.Err() - } - keys := res.Val() - for _, key := range keys { - err := c.store.Del(c.ctx, key).Err() - if err != nil { - log.Debug("Error deleting all user sessions from redis: ", err) - continue - } - } - return nil -} - -// DeleteSessionForNamespace to delete session for a given namespace example google,github -func (c *provider) DeleteSessionForNamespace(namespace string) error { - res := c.store.Keys(c.ctx, fmt.Sprintf("%s:*", namespace)) - if res.Err() != nil { - log.Debug("Error getting all user sessions from redis: ", res.Err()) - return res.Err() - } - keys := res.Val() - for _, key := range keys { - err := c.store.Del(c.ctx, key).Err() - if err != nil { - log.Debug("Error deleting all user sessions from redis: ", err) - continue - } - } - return nil -} - -// SetMfaSession sets the mfa session with key and value of userId -func (c *provider) SetMfaSession(userId, key string, expiration int64) error { - currentTime := time.Now() - expireTime := time.Unix(expiration, 0) - duration := expireTime.Sub(currentTime) - err := c.store.Set(c.ctx, fmt.Sprintf("%s%s:%s", mfaSessionPrefix, userId, key), userId, duration).Err() - if err != nil { - log.Debug("Error saving user session to redis: ", err) - return err - } - return nil -} - -// GetMfaSession returns value of given mfa session -func (c *provider) GetMfaSession(userId, key string) (string, error) { - data, err := c.store.Get(c.ctx, fmt.Sprintf("%s%s:%s", mfaSessionPrefix, userId, key)).Result() - if err != nil { - return "", err - } - return data, nil -} - -// DeleteMfaSession deletes given mfa session from in-memory store. -func (c *provider) DeleteMfaSession(userId, key string) error { - if err := c.store.Del(c.ctx, fmt.Sprintf("%s%s:%s", mfaSessionPrefix, userId, key)).Err(); err != nil { - log.Debug("Error deleting user session from redis: ", err) - // continue - } - return nil -} - -// SetState sets the state in redis store. -func (c *provider) SetState(key, value string) error { - err := c.store.Set(c.ctx, stateStorePrefix+key, value, 0).Err() - if err != nil { - log.Debug("Error saving redis token: ", err) - return err - } - - return nil -} - -// GetState gets the state from redis store. -func (c *provider) GetState(key string) (string, error) { - data, err := c.store.Get(c.ctx, stateStorePrefix+key).Result() - if err != nil { - log.Debug("error getting token from redis store: ", err) - return "", err - } - - return data, err -} - -// RemoveState removes the state from redis store. -func (c *provider) RemoveState(key string) error { - err := c.store.Del(c.ctx, stateStorePrefix+key).Err() - if err != nil { - log.Fatalln("Error deleting redis token: ", err) - return err - } - - return nil -} - -// UpdateEnvStore to update the whole env store object -func (c *provider) UpdateEnvStore(store map[string]interface{}) error { - for key, value := range store { - err := c.store.HSet(c.ctx, envStorePrefix, key, value).Err() - if err != nil { - return err - } - } - return nil -} - -// GetEnvStore returns the whole env store object -func (c *provider) GetEnvStore() (map[string]interface{}, error) { - res := make(map[string]interface{}) - data, err := c.store.HGetAll(c.ctx, envStorePrefix).Result() - if err != nil { - return nil, err - } - for key, value := range data { - if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableMobileBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled || key == constants.EnvKeyIsSMSServiceEnabled || key == constants.EnvKeyEnforceMultiFactorAuthentication || key == constants.EnvKeyDisableMultiFactorAuthentication || key == constants.EnvKeyAppCookieSecure || key == constants.EnvKeyAdminCookieSecure || key == constants.EnvKeyDisablePlayGround || key == constants.EnvKeyDisableTOTPLogin || key == constants.EnvKeyDisableMailOTPLogin { - boolValue, err := strconv.ParseBool(value) - if err != nil { - return res, err - } - res[key] = boolValue - } else { - res[key] = value - } - } - return res, nil -} - -// UpdateEnvVariable to update the particular env variable -func (c *provider) UpdateEnvVariable(key string, value interface{}) error { - err := c.store.HSet(c.ctx, envStorePrefix, key, value).Err() - if err != nil { - log.Debug("Error saving redis token: ", err) - return err - } - return nil -} - -// GetStringStoreEnvVariable to get the string env variable from env store -func (c *provider) GetStringStoreEnvVariable(key string) (string, error) { - data, err := c.store.HGet(c.ctx, envStorePrefix, key).Result() - if err != nil { - return "", nil - } - - return data, nil -} - -// GetBoolStoreEnvVariable to get the bool env variable from env store -func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) { - data, err := c.store.HGet(c.ctx, envStorePrefix, key).Result() - if err != nil { - return false, nil - } - - return data == "1", nil -} diff --git a/server/memorystore/required_env_store.go b/server/memorystore/required_env_store.go deleted file mode 100644 index 1bd105f37..000000000 --- a/server/memorystore/required_env_store.go +++ /dev/null @@ -1,171 +0,0 @@ -package memorystore - -import ( - "errors" - "os" - "strings" - "sync" - - "github.com/joho/godotenv" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/cli" - "github.com/authorizerdev/authorizer/server/constants" -) - -// RequiredEnv holds information about required envs -type RequiredEnv struct { - EnvPath string `json:"ENV_PATH"` - DatabaseURL string `json:"DATABASE_URL"` - DatabaseType string `json:"DATABASE_TYPE"` - DatabaseName string `json:"DATABASE_NAME"` - DatabaseHost string `json:"DATABASE_HOST"` - DatabasePort string `json:"DATABASE_PORT"` - DatabaseUsername string `json:"DATABASE_USERNAME"` - DatabasePassword string `json:"DATABASE_PASSWORD"` - DatabaseCert string `json:"DATABASE_CERT"` - DatabaseCertKey string `json:"DATABASE_CERT_KEY"` - DatabaseCACert string `json:"DATABASE_CA_CERT"` - RedisURL string `json:"REDIS_URL"` - DisableRedisForEnv bool `json:"DISABLE_REDIS_FOR_ENV"` - // AWS Related Envs - AwsRegion string `json:"AWS_REGION"` - AwsAccessKeyID string `json:"AWS_ACCESS_KEY_ID"` - AwsSecretAccessKey string `json:"AWS_SECRET_ACCESS_KEY"` - // Couchbase related envs - CouchbaseBucket string `json:"COUCHBASE_BUCKET"` - CouchbaseScope string `json:"COUCHBASE_SCOPE"` - CouchbaseBucketRAMQuotaMB string `json:"COUCHBASE_BUCKET_RAM_QUOTA"` -} - -// RequiredEnvStore is a simple in-memory store for sessions. -type RequiredEnvStore struct { - mutex sync.Mutex - requiredEnv RequiredEnv -} - -// GetRequiredEnv to get required env -func (r *RequiredEnvStore) GetRequiredEnv() RequiredEnv { - r.mutex.Lock() - defer r.mutex.Unlock() - - return r.requiredEnv -} - -// SetRequiredEnv to set required env -func (r *RequiredEnvStore) SetRequiredEnv(requiredEnv RequiredEnv) { - r.mutex.Lock() - defer r.mutex.Unlock() - r.requiredEnv = requiredEnv -} - -var RequiredEnvStoreObj *RequiredEnvStore - -// InitRequiredEnv to initialize EnvData and throw error if required env are not present -// This includes env that only configurable via env vars and not the ui -func InitRequiredEnv() error { - envPath := os.Getenv(constants.EnvKeyEnvPath) - - if envPath == "" { - if envPath == "" { - envPath = `.env` - } - } - - if cli.ARG_ENV_FILE != nil && *cli.ARG_ENV_FILE != "" { - envPath = *cli.ARG_ENV_FILE - } - log.Info("env path: ", envPath) - - err := godotenv.Load(envPath) - if err != nil { - log.Infof("using OS env instead of %s file", envPath) - } - - dbURL := os.Getenv(constants.EnvKeyDatabaseURL) - dbType := os.Getenv(constants.EnvKeyDatabaseType) - dbName := os.Getenv(constants.EnvKeyDatabaseName) - dbPort := os.Getenv(constants.EnvKeyDatabasePort) - dbHost := os.Getenv(constants.EnvKeyDatabaseHost) - dbUsername := os.Getenv(constants.EnvKeyDatabaseUsername) - dbPassword := os.Getenv(constants.EnvKeyDatabasePassword) - dbCert := os.Getenv(constants.EnvKeyDatabaseCert) - dbCertKey := os.Getenv(constants.EnvKeyDatabaseCertKey) - dbCACert := os.Getenv(constants.EnvKeyDatabaseCACert) - redisURL := os.Getenv(constants.EnvKeyRedisURL) - disableRedisForEnv := os.Getenv(constants.EnvKeyDisableRedisForEnv) == "true" - awsRegion := os.Getenv(constants.EnvAwsRegion) - awsAccessKeyID := os.Getenv(constants.EnvAwsAccessKeyID) - awsSecretAccessKey := os.Getenv(constants.EnvAwsSecretAccessKey) - couchbaseBucket := os.Getenv(constants.EnvCouchbaseBucket) - couchbaseScope := os.Getenv(constants.EnvCouchbaseScope) - couchbaseBucketRAMQuotaMB := os.Getenv(constants.EnvCouchbaseBucketRAMQuotaMB) - - if strings.TrimSpace(redisURL) == "" { - if cli.ARG_REDIS_URL != nil && *cli.ARG_REDIS_URL != "" { - redisURL = *cli.ARG_REDIS_URL - } - } - - // set default db name for non sql dbs - if dbName == "" { - dbName = "authorizer" - } - - if strings.TrimSpace(dbType) == "" { - if cli.ARG_DB_TYPE != nil && *cli.ARG_DB_TYPE != "" { - dbType = strings.TrimSpace(*cli.ARG_DB_TYPE) - } - - if dbType == "" { - log.Debug("DATABASE_TYPE is not set") - return errors.New("invalid database type. DATABASE_TYPE is empty") - } - } - - if strings.TrimSpace(dbURL) == "" { - if cli.ARG_DB_URL != nil && *cli.ARG_DB_URL != "" { - dbURL = strings.TrimSpace(*cli.ARG_DB_URL) - } - - // In dynamoDB these field are not always mandatory - if dbType != constants.DbTypeDynamoDB && dbURL == "" && dbPort == "" && dbHost == "" && dbUsername == "" && dbPassword == "" { - log.Debug("DATABASE_URL is not set") - return errors.New("invalid database url. DATABASE_URL is required") - } - } - - if dbName == "" { - if dbName == "" { - dbName = "authorizer" - } - } - - requiredEnv := RequiredEnv{ - EnvPath: envPath, - DatabaseURL: dbURL, - DatabaseType: dbType, - DatabaseName: dbName, - DatabaseHost: dbHost, - DatabasePort: dbPort, - DatabaseUsername: dbUsername, - DatabasePassword: dbPassword, - DatabaseCert: dbCert, - DatabaseCertKey: dbCertKey, - DatabaseCACert: dbCACert, - RedisURL: redisURL, - DisableRedisForEnv: disableRedisForEnv, - AwsRegion: awsRegion, - AwsAccessKeyID: awsAccessKeyID, - AwsSecretAccessKey: awsSecretAccessKey, - CouchbaseBucket: couchbaseBucket, - CouchbaseScope: couchbaseScope, - CouchbaseBucketRAMQuotaMB: couchbaseBucketRAMQuotaMB, - } - - RequiredEnvStoreObj = &RequiredEnvStore{ - requiredEnv: requiredEnv, - } - - return nil -} diff --git a/server/middlewares/context.go b/server/middlewares/context.go deleted file mode 100644 index 8da697de0..000000000 --- a/server/middlewares/context.go +++ /dev/null @@ -1,16 +0,0 @@ -package middlewares - -import ( - "context" - - "github.com/gin-gonic/gin" -) - -// GinContextToContextMiddleware is a middleware to add gin context in context -func GinContextToContextMiddleware() gin.HandlerFunc { - return func(c *gin.Context) { - ctx := context.WithValue(c.Request.Context(), "GinContextKey", c) - c.Request = c.Request.WithContext(ctx) - c.Next() - } -} diff --git a/server/middlewares/log.go b/server/middlewares/log.go deleted file mode 100644 index 357b4b2b4..000000000 --- a/server/middlewares/log.go +++ /dev/null @@ -1,78 +0,0 @@ -package middlewares - -import ( - "fmt" - "math" - "net/http" - "os" - "time" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" -) - -var timeFormat = "02/Jan/2006:15:04:05 -0700" - -// Logger is the logrus logger handler -func Logger(logger logrus.FieldLogger, notLogged ...string) gin.HandlerFunc { - hostname, err := os.Hostname() - if err != nil { - hostname = "unknown" - } - - var skip map[string]struct{} - - if length := len(notLogged); length > 0 { - skip = make(map[string]struct{}, length) - - for _, p := range notLogged { - skip[p] = struct{}{} - } - } - - return func(c *gin.Context) { - // other handler can change c.Path so: - path := c.Request.URL.Path - start := time.Now() - c.Next() - stop := time.Since(start) - latency := int(math.Ceil(float64(stop.Nanoseconds()) / 1000000.0)) - statusCode := c.Writer.Status() - clientIP := c.ClientIP() - clientUserAgent := c.Request.UserAgent() - referer := c.Request.Referer() - dataLength := c.Writer.Size() - if dataLength < 0 { - dataLength = 0 - } - - if _, ok := skip[path]; ok { - return - } - - entry := logger.WithFields(logrus.Fields{ - "hostname": hostname, - "statusCode": statusCode, - "latency": latency, // time to process - "clientIP": clientIP, - "method": c.Request.Method, - "path": path, - "referer": referer, - "dataLength": dataLength, - "userAgent": clientUserAgent, - }) - - if len(c.Errors) > 0 { - entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String()) - } else { - msg := fmt.Sprintf("%s - %s [%s] \"%s %s\" %d %d \"%s\" \"%s\" (%dms)", clientIP, hostname, time.Now().Format(timeFormat), c.Request.Method, path, statusCode, dataLength, referer, clientUserAgent, latency) - if statusCode >= http.StatusInternalServerError { - entry.Error(msg) - } else if statusCode >= http.StatusBadRequest { - entry.Warn(msg) - } else { - entry.Info(msg) - } - } - } -} diff --git a/server/oauth/oauth.go b/server/oauth/oauth.go deleted file mode 100644 index 8f64feea9..000000000 --- a/server/oauth/oauth.go +++ /dev/null @@ -1,276 +0,0 @@ -package oauth - -import ( - "context" - "fmt" - - "golang.org/x/oauth2" - "google.golang.org/appengine/log" - - facebookOAuth2 "golang.org/x/oauth2/facebook" - githubOAuth2 "golang.org/x/oauth2/github" - linkedInOAuth2 "golang.org/x/oauth2/linkedin" - microsoftOAuth2 "golang.org/x/oauth2/microsoft" - twitchOAuth2 "golang.org/x/oauth2/twitch" - - "github.com/coreos/go-oidc/v3/oidc" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -const ( - microsoftCommonTenant = "common" -) - -// OAuthProviders is a struct that contains reference all the OAuth providers -type OAuthProvider struct { - GoogleConfig *oauth2.Config - GithubConfig *oauth2.Config - FacebookConfig *oauth2.Config - LinkedInConfig *oauth2.Config - AppleConfig *oauth2.Config - DiscordConfig *oauth2.Config - TwitterConfig *oauth2.Config - MicrosoftConfig *oauth2.Config - TwitchConfig *oauth2.Config - RobloxConfig *oauth2.Config -} - -// OIDCProviders is a struct that contains reference all the OpenID providers -type OIDCProvider struct { - GoogleOIDC *oidc.Provider - MicrosoftOIDC *oidc.Provider - TwitchOIDC *oidc.Provider -} - -var ( - // OAuthProviders is a global variable that contains instance for all enabled the OAuth providers - OAuthProviders OAuthProvider - // OIDCProviders is a global variable that contains instance for all enabled the OpenID providers - OIDCProviders OIDCProvider -) - -// InitOAuth initializes the OAuth providers based on EnvData -func InitOAuth() error { - ctx := context.Background() - googleClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientID) - if err != nil { - googleClientID = "" - } - googleClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientSecret) - if err != nil { - googleClientSecret = "" - } - if googleClientID != "" && googleClientSecret != "" { - p, err := oidc.NewProvider(ctx, "https://accounts.google.com") - if err != nil { - return err - } - OIDCProviders.GoogleOIDC = p - OAuthProviders.GoogleConfig = &oauth2.Config{ - ClientID: googleClientID, - ClientSecret: googleClientSecret, - RedirectURL: "/oauth_callback/google", - Endpoint: OIDCProviders.GoogleOIDC.Endpoint(), - Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, - } - } - - githubClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGithubClientID) - if err != nil { - githubClientID = "" - } - githubClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGithubClientSecret) - if err != nil { - githubClientSecret = "" - } - if githubClientID != "" && githubClientSecret != "" { - OAuthProviders.GithubConfig = &oauth2.Config{ - ClientID: githubClientID, - ClientSecret: githubClientSecret, - RedirectURL: "/oauth_callback/github", - Endpoint: githubOAuth2.Endpoint, - Scopes: []string{"read:user", "user:email"}, - } - } - - facebookClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientID) - if err != nil { - facebookClientID = "" - } - facebookClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientSecret) - if err != nil { - facebookClientSecret = "" - } - if facebookClientID != "" && facebookClientSecret != "" { - OAuthProviders.FacebookConfig = &oauth2.Config{ - ClientID: facebookClientID, - ClientSecret: facebookClientSecret, - RedirectURL: "/oauth_callback/facebook", - Endpoint: facebookOAuth2.Endpoint, - Scopes: []string{"public_profile", "email"}, - } - } - - linkedInClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyLinkedInClientID) - if err != nil { - linkedInClientID = "" - } - linkedInClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyLinkedInClientSecret) - if err != nil { - linkedInClientSecret = "" - } - if linkedInClientID != "" && linkedInClientSecret != "" { - OAuthProviders.LinkedInConfig = &oauth2.Config{ - ClientID: linkedInClientID, - ClientSecret: linkedInClientSecret, - RedirectURL: "/oauth_callback/linkedin", - Endpoint: linkedInOAuth2.Endpoint, - Scopes: []string{"r_liteprofile", "r_emailaddress"}, - } - } - - appleClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppleClientID) - if err != nil { - appleClientID = "" - } - appleClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppleClientSecret) - if err != nil { - appleClientSecret = "" - } - if appleClientID != "" && appleClientSecret != "" { - OAuthProviders.AppleConfig = &oauth2.Config{ - ClientID: appleClientID, - ClientSecret: appleClientSecret, - RedirectURL: "/oauth_callback/apple", - Endpoint: oauth2.Endpoint{ - AuthURL: "https://appleid.apple.com/auth/authorize", - TokenURL: "https://appleid.apple.com/auth/token", - }, - } - } - - discordClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDiscordClientID) - if err != nil { - discordClientID = "" - } - discordClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDiscordClientSecret) - if err != nil { - discordClientSecret = "" - } - if discordClientID != "" && discordClientSecret != "" { - OAuthProviders.DiscordConfig = &oauth2.Config{ - ClientID: discordClientID, - ClientSecret: discordClientSecret, - RedirectURL: "/oauth_callback/discord", - Endpoint: oauth2.Endpoint{ - AuthURL: "https://discord.com/oauth2/authorize", - TokenURL: "https://discord.com/api/oauth2/token", - }, - Scopes: []string{"identify", "email"}, - } - } - - twitterClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitterClientID) - if err != nil { - twitterClientID = "" - } - twitterClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitterClientSecret) - if err != nil { - twitterClientSecret = "" - } - if twitterClientID != "" && twitterClientSecret != "" { - OAuthProviders.TwitterConfig = &oauth2.Config{ - ClientID: twitterClientID, - ClientSecret: twitterClientSecret, - RedirectURL: "/oauth_callback/twitter", - Endpoint: oauth2.Endpoint{ - // Endpoint is currently not yet part of oauth2-package. See https://go-review.googlesource.com/c/oauth2/+/350889 for status - AuthURL: "https://twitter.com/i/oauth2/authorize", - TokenURL: "https://api.twitter.com/2/oauth2/token", - AuthStyle: oauth2.AuthStyleInHeader, - }, - Scopes: []string{"tweet.read", "users.read"}, - } - } - - microsoftClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyMicrosoftClientID) - if err != nil { - microsoftClientID = "" - } - microsoftClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyMicrosoftClientSecret) - if err != nil { - microsoftClientSecret = "" - } - microsoftActiveDirTenantID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyMicrosoftActiveDirectoryTenantID) - if err != nil || microsoftActiveDirTenantID == "" { - microsoftActiveDirTenantID = microsoftCommonTenant - } - if microsoftClientID != "" && microsoftClientSecret != "" { - if microsoftActiveDirTenantID == microsoftCommonTenant { - ctx = oidc.InsecureIssuerURLContext(ctx, fmt.Sprintf("https://login.microsoftonline.com/%s/v2.0", microsoftActiveDirTenantID)) - } - p, err := oidc.NewProvider(ctx, fmt.Sprintf("https://login.microsoftonline.com/%s/v2.0", microsoftActiveDirTenantID)) - if err != nil { - log.Debugf(ctx, "Error while creating OIDC provider for Microsoft: %v", err) - return err - } - OIDCProviders.MicrosoftOIDC = p - OAuthProviders.MicrosoftConfig = &oauth2.Config{ - ClientID: microsoftClientID, - ClientSecret: microsoftClientSecret, - RedirectURL: "/oauth_callback/microsoft", - Endpoint: microsoftOAuth2.AzureADEndpoint(microsoftActiveDirTenantID), - Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, - } - } - - twitchClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitchClientID) - if err != nil { - twitchClientID = "" - } - twitchClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitchClientSecret) - if err != nil { - twitchClientSecret = "" - } - - if twitchClientID != "" && twitchClientSecret != "" { - p, err := oidc.NewProvider(ctx, "https://id.twitch.tv/oauth2") - if err != nil { - log.Debugf(ctx, "Error while creating OIDC provider for Twitch: %v", err) - return err - } - - OIDCProviders.TwitchOIDC = p - OAuthProviders.TwitchConfig = &oauth2.Config{ - ClientID: twitchClientID, - ClientSecret: twitchClientSecret, - RedirectURL: "/oauth_callback/twitch", - Endpoint: twitchOAuth2.Endpoint, - Scopes: []string{oidc.ScopeOpenID}, - } - } - - robloxClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRobloxClientID) - if err != nil { - robloxClientID = "" - } - robloxClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRobloxClientSecret) - if err != nil { - robloxClientSecret = "" - } - if robloxClientID != "" && robloxClientSecret != "" { - OAuthProviders.RobloxConfig = &oauth2.Config{ - ClientID: robloxClientID, - ClientSecret: robloxClientSecret, - RedirectURL: "/oauth_callback/roblox", - Endpoint: oauth2.Endpoint{ - AuthURL: "https://apis.roblox.com/oauth/v1/authorize", - TokenURL: "https://apis.roblox.com/oauth/v1/token", - }, - Scopes: []string{oidc.ScopeOpenID, "profile"}, - } - } - return nil -} diff --git a/server/resolvers/add_email_template.go b/server/resolvers/add_email_template.go deleted file mode 100644 index 487edc25d..000000000 --- a/server/resolvers/add_email_template.go +++ /dev/null @@ -1,64 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" - log "github.com/sirupsen/logrus" -) - -// AddEmailTemplateResolver resolver for add email template mutation -func AddEmailTemplateResolver(ctx context.Context, params model.AddEmailTemplateRequest) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return nil, fmt.Errorf("unauthorized") - } - - if !validators.IsValidEmailTemplateEventName(params.EventName) { - log.Debug("Invalid Event Name: ", params.EventName) - return nil, fmt.Errorf("invalid event name %s", params.EventName) - } - - if strings.TrimSpace(params.Subject) == "" { - return nil, fmt.Errorf("empty subject not allowed") - } - - if strings.TrimSpace(params.Template) == "" { - return nil, fmt.Errorf("empty template not allowed") - } - - var design string - - if params.Design == nil || strings.TrimSpace(refs.StringValue(params.Design)) == "" { - design = "" - } - - _, err = db.Provider.AddEmailTemplate(ctx, &models.EmailTemplate{ - EventName: params.EventName, - Template: params.Template, - Subject: params.Subject, - Design: design, - }) - if err != nil { - log.Debug("Failed to add email template: ", err) - return nil, err - } - - return &model.Response{ - Message: `Email template added successfully`, - }, nil -} diff --git a/server/resolvers/admin_login.go b/server/resolvers/admin_login.go deleted file mode 100644 index 23965bbbf..000000000 --- a/server/resolvers/admin_login.go +++ /dev/null @@ -1,47 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/utils" -) - -// AdminLoginResolver is a resolver for admin login mutation -func AdminLoginResolver(ctx context.Context, params model.AdminLoginInput) (*model.Response, error) { - var res *model.Response - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - if err != nil { - log.Debug("Error getting admin secret: ", err) - return res, err - } - if params.AdminSecret != adminSecret { - log.Debug("Admin secret is not correct") - return res, fmt.Errorf(`invalid admin secret`) - } - - hashedKey, err := crypto.EncryptPassword(adminSecret) - if err != nil { - return res, err - } - cookie.SetAdminCookie(gc, hashedKey) - - res = &model.Response{ - Message: "admin logged in successfully", - } - return res, nil -} diff --git a/server/resolvers/admin_logout.go b/server/resolvers/admin_logout.go deleted file mode 100644 index 64befe02f..000000000 --- a/server/resolvers/admin_logout.go +++ /dev/null @@ -1,36 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// AdminLogoutResolver is a resolver for admin logout mutation -func AdminLogoutResolver(ctx context.Context) (*model.Response, error) { - var res *model.Response - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Admin is not logged in") - return res, fmt.Errorf("unauthorized") - } - - cookie.DeleteAdminCookie(gc) - - res = &model.Response{ - Message: "admin logged out successfully", - } - return res, nil -} diff --git a/server/resolvers/admin_session.go b/server/resolvers/admin_session.go deleted file mode 100644 index d5cb8d10c..000000000 --- a/server/resolvers/admin_session.go +++ /dev/null @@ -1,49 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// AdminSessionResolver is a resolver for admin session query -func AdminSessionResolver(ctx context.Context) (*model.Response, error) { - var res *model.Response - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return res, fmt.Errorf("unauthorized") - } - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - if err != nil { - log.Debug("Error getting admin secret: ", err) - return res, fmt.Errorf("unauthorized") - } - hashedKey, err := crypto.EncryptPassword(adminSecret) - if err != nil { - log.Debug("Failed to encrypt key: ", err) - return res, err - } - cookie.SetAdminCookie(gc, hashedKey) - - res = &model.Response{ - Message: "admin logged in successfully", - } - return res, nil -} diff --git a/server/resolvers/admin_signup.go b/server/resolvers/admin_signup.go deleted file mode 100644 index c1dd5c177..000000000 --- a/server/resolvers/admin_signup.go +++ /dev/null @@ -1,90 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/utils" -) - -// AdminSignupResolver is a resolver for admin signup mutation -func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) { - var res *model.Response - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - if strings.TrimSpace(params.AdminSecret) == "" { - log.Debug("Admin secret is empty") - err = fmt.Errorf("please select secure admin secret") - return res, err - } - - if len(params.AdminSecret) < 6 { - log.Debug("Admin secret is too short") - err = fmt.Errorf("admin secret must be at least 6 characters") - return res, err - } - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - if err != nil { - log.Debug("Error getting admin secret: ", err) - adminSecret = "" - } - - if adminSecret != "" { - log.Debug("Admin secret is already set") - err = fmt.Errorf("admin sign up already completed") - return res, err - } - - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyAdminSecret, params.AdminSecret) - // consvert EnvData to JSON - storeData, err := memorystore.Provider.GetEnvStore() - if err != nil { - log.Debug("Error getting env store: ", err) - return res, err - } - - env, err := db.Provider.GetEnv(ctx) - if err != nil { - log.Debug("Failed to get env: ", err) - return res, err - } - - envData, err := crypto.EncryptEnvData(storeData) - if err != nil { - log.Debug("Failed to encrypt envstore: ", err) - return res, err - } - - env.EnvData = envData - if _, err := db.Provider.UpdateEnv(ctx, env); err != nil { - log.Debug("Failed to update env: ", err) - return res, err - } - - hashedKey, err := crypto.EncryptPassword(params.AdminSecret) - if err != nil { - log.Debug("Failed to encrypt admin session key: ", err) - return res, err - } - cookie.SetAdminCookie(gc, hashedKey) - - res = &model.Response{ - Message: "admin signed up successfully", - } - return res, nil -} diff --git a/server/resolvers/deactivate_account.go b/server/resolvers/deactivate_account.go deleted file mode 100644 index 539575c59..000000000 --- a/server/resolvers/deactivate_account.go +++ /dev/null @@ -1,52 +0,0 @@ -package resolvers - -import ( - "context" - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - log "github.com/sirupsen/logrus" -) - -// DeactivateAccountResolver is the resolver for the deactivate_account field. -func DeactivateAccountResolver(ctx context.Context) (*model.Response, error) { - var res *model.Response - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - tokenData, err := token.GetUserIDFromSessionOrAccessToken(gc) - if err != nil { - log.Debug("Failed GetUserIDFromSessionOrAccessToken: ", err) - return res, err - } - log := log.WithFields(log.Fields{ - "user_id": tokenData.UserID, - }) - user, err := db.Provider.GetUserByID(ctx, tokenData.UserID) - if err != nil { - log.Debug("Failed to get user by id: ", err) - return res, err - } - now := time.Now().Unix() - user.RevokedTimestamp = &now - user, err = db.Provider.UpdateUser(ctx, user) - if err != nil { - log.Debug("Failed to update user: ", err) - return res, err - } - go func() { - memorystore.Provider.DeleteAllUserSessions(user.ID) - utils.RegisterEvent(ctx, constants.UserDeactivatedWebhookEvent, "", user) - }() - res = &model.Response{ - Message: `user account deactivated successfully`, - } - return res, nil -} diff --git a/server/resolvers/delete_email_template.go b/server/resolvers/delete_email_template.go deleted file mode 100644 index 92a6172d0..000000000 --- a/server/resolvers/delete_email_template.go +++ /dev/null @@ -1,49 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - log "github.com/sirupsen/logrus" -) - -// DeleteEmailTemplateResolver resolver to delete email template and its relevant logs -func DeleteEmailTemplateResolver(ctx context.Context, params model.DeleteEmailTemplateRequest) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return nil, fmt.Errorf("unauthorized") - } - - if params.ID == "" { - log.Debug("email template is required") - return nil, fmt.Errorf("email template ID required") - } - - log := log.WithField("email_template_id", params.ID) - - emailTemplate, err := db.Provider.GetEmailTemplateByID(ctx, params.ID) - if err != nil { - log.Debug("failed to get email template: ", err) - return nil, err - } - - err = db.Provider.DeleteEmailTemplate(ctx, emailTemplate) - if err != nil { - log.Debug("failed to delete email template: ", err) - return nil, err - } - - return &model.Response{ - Message: "Email templated deleted successfully", - }, nil -} diff --git a/server/resolvers/delete_user.go b/server/resolvers/delete_user.go deleted file mode 100644 index e6ccf62d8..000000000 --- a/server/resolvers/delete_user.go +++ /dev/null @@ -1,100 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// DeleteUserResolver is a resolver for delete user mutation -func DeleteUserResolver(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) { - var res *model.Response - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return res, fmt.Errorf("unauthorized") - } - - log := log.WithFields(log.Fields{ - "email": params.Email, - }) - - user, err := db.Provider.GetUserByEmail(ctx, params.Email) - if err != nil { - log.Debug("Failed to get user from DB: ", err) - return res, err - } - - err = db.Provider.DeleteUser(ctx, user) - if err != nil { - log.Debug("Failed to delete user: ", err) - return res, err - } - - res = &model.Response{ - Message: `user deleted successfully`, - } - - go func() { - // delete otp for given email - otp, err := db.Provider.GetOTPByEmail(ctx, refs.StringValue(user.Email)) - if err != nil { - log.Infof("No OTP found for email (%s): %v", user.Email, err) - // continue - } else { - err := db.Provider.DeleteOTP(ctx, otp) - if err != nil { - log.Debugf("Failed to delete otp for given email (%s): %v", refs.StringValue(user.Email), err) - // continue - } - } - - // delete otp for given phone number - otp, err = db.Provider.GetOTPByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)) - if err != nil { - log.Infof("No OTP found for email (%s): %v", refs.StringValue(user.Email), err) - // continue - } else { - err := db.Provider.DeleteOTP(ctx, otp) - if err != nil { - log.Debugf("Failed to delete otp for given phone (%s): %v", refs.StringValue(user.PhoneNumber), err) - // continue - } - } - - // delete verification requests for given email - for _, vt := range constants.VerificationTypes { - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, refs.StringValue(user.Email), vt) - if err != nil { - log.Infof("No verification verification request found for email: %s, verification_request_type: %s. %v", refs.StringValue(user.Email), vt, err) - // continue - } else { - err := db.Provider.DeleteVerificationRequest(ctx, verificationRequest) - if err != nil { - log.Debugf("Failed to DeleteVerificationRequest for email: %s, verification_request_type: %s. %v", refs.StringValue(user.Email), vt, err) - // continue - } - } - } - - memorystore.Provider.DeleteAllUserSessions(user.ID) - utils.RegisterEvent(ctx, constants.UserDeletedWebhookEvent, "", user) - }() - - return res, nil -} diff --git a/server/resolvers/delete_webhook.go b/server/resolvers/delete_webhook.go deleted file mode 100644 index 917d50259..000000000 --- a/server/resolvers/delete_webhook.go +++ /dev/null @@ -1,49 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - log "github.com/sirupsen/logrus" -) - -// DeleteWebhookResolver resolver to delete webhook and its relevant logs -func DeleteWebhookResolver(ctx context.Context, params model.WebhookRequest) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return nil, fmt.Errorf("unauthorized") - } - - if params.ID == "" { - log.Debug("webhookID is required") - return nil, fmt.Errorf("webhook ID required") - } - - log := log.WithField("webhook_id", params.ID) - - webhook, err := db.Provider.GetWebhookByID(ctx, params.ID) - if err != nil { - log.Debug("failed to get webhook: ", err) - return nil, err - } - - err = db.Provider.DeleteWebhook(ctx, webhook) - if err != nil { - log.Debug("failed to delete webhook: ", err) - return nil, err - } - - return &model.Response{ - Message: "Webhook deleted successfully", - }, nil -} diff --git a/server/resolvers/email_templates.go b/server/resolvers/email_templates.go deleted file mode 100644 index 0e1ee6639..000000000 --- a/server/resolvers/email_templates.go +++ /dev/null @@ -1,34 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - log "github.com/sirupsen/logrus" -) - -// EmailTemplatesResolver resolver for getting the list of email templates based on pagination -func EmailTemplatesResolver(ctx context.Context, params *model.PaginatedInput) (*model.EmailTemplates, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return nil, fmt.Errorf("unauthorized") - } - - pagination := utils.GetPagination(params) - emailTemplates, err := db.Provider.ListEmailTemplate(ctx, pagination) - if err != nil { - log.Debug("failed to get email templates: ", err) - return nil, err - } - return emailTemplates, nil -} diff --git a/server/resolvers/enable_access.go b/server/resolvers/enable_access.go deleted file mode 100644 index 8e245b856..000000000 --- a/server/resolvers/enable_access.go +++ /dev/null @@ -1,56 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// EnableAccessResolver is a resolver for enabling user access -func EnableAccessResolver(ctx context.Context, params model.UpdateAccessInput) (*model.Response, error) { - var res *model.Response - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin.") - return res, fmt.Errorf("unauthorized") - } - - log := log.WithFields(log.Fields{ - "user_id": params.UserID, - }) - - user, err := db.Provider.GetUserByID(ctx, params.UserID) - if err != nil { - log.Debug("Failed to get user from DB: ", err) - return res, err - } - - user.RevokedTimestamp = nil - - user, err = db.Provider.UpdateUser(ctx, user) - if err != nil { - log.Debug("Failed to update user: ", err) - return res, err - } - - res = &model.Response{ - Message: `user access enabled successfully`, - } - - go utils.RegisterEvent(ctx, constants.UserAccessEnabledWebhookEvent, "", user) - - return res, nil -} diff --git a/server/resolvers/env.go b/server/resolvers/env.go deleted file mode 100644 index f95e1f771..000000000 --- a/server/resolvers/env.go +++ /dev/null @@ -1,228 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// EnvResolver is a resolver for config query -// This is admin only query -func EnvResolver(ctx context.Context) (*model.Env, error) { - res := &model.Env{} - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin.") - return res, fmt.Errorf("unauthorized") - } - - // get clone of store - store, err := memorystore.Provider.GetEnvStore() - if err != nil { - log.Debug("Failed to get env store: ", err) - return res, err - } - - if val, ok := store[constants.EnvKeyAccessTokenExpiryTime]; ok { - res.AccessTokenExpiryTime = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyAdminSecret]; ok { - res.AdminSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyClientID]; ok { - res.ClientID = val.(string) - } - if val, ok := store[constants.EnvKeyClientSecret]; ok { - res.ClientSecret = val.(string) - } - if val, ok := store[constants.EnvKeyDatabaseURL]; ok { - res.DatabaseURL = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyDatabaseName]; ok { - res.DatabaseName = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyDatabaseType]; ok { - res.DatabaseType = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyDatabaseUsername]; ok { - res.DatabaseUsername = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyDatabasePassword]; ok { - res.DatabasePassword = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyDatabaseHost]; ok { - res.DatabaseHost = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyDatabasePort]; ok { - res.DatabasePort = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyCustomAccessTokenScript]; ok { - res.CustomAccessTokenScript = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeySmtpHost]; ok { - res.SMTPHost = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeySmtpPort]; ok { - res.SMTPPort = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeySmtpUsername]; ok { - res.SMTPUsername = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeySmtpPassword]; ok { - res.SMTPPassword = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeySenderEmail]; ok { - res.SenderEmail = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeySenderName]; ok { - res.SenderName = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeySmtpLocalName]; ok { - res.SMTPLocalName = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyJwtType]; ok { - res.JwtType = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyJwtSecret]; ok { - res.JwtSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyJwtRoleClaim]; ok { - res.JwtRoleClaim = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyJwtPublicKey]; ok { - res.JwtPublicKey = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyJwtPrivateKey]; ok { - res.JwtPrivateKey = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyAppURL]; ok { - res.AppURL = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyRedisURL]; ok { - res.RedisURL = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyResetPasswordURL]; ok { - res.ResetPasswordURL = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyGoogleClientID]; ok { - res.GoogleClientID = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyGoogleClientSecret]; ok { - res.GoogleClientSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyFacebookClientID]; ok { - res.FacebookClientID = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyFacebookClientSecret]; ok { - res.FacebookClientSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyGithubClientID]; ok { - res.GithubClientID = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyGithubClientSecret]; ok { - res.GithubClientSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyLinkedInClientID]; ok { - res.LinkedinClientID = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyLinkedInClientSecret]; ok { - res.LinkedinClientSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyAppleClientID]; ok { - res.AppleClientID = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyAppleClientSecret]; ok { - res.AppleClientSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyDiscordClientID]; ok { - res.DiscordClientID = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyDiscordClientSecret]; ok { - res.DiscordClientSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyTwitterClientID]; ok { - res.TwitterClientID = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyTwitterClientSecret]; ok { - res.TwitterClientSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyMicrosoftClientID]; ok { - res.MicrosoftClientID = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyMicrosoftClientSecret]; ok { - res.MicrosoftClientSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyMicrosoftActiveDirectoryTenantID]; ok { - res.MicrosoftActiveDirectoryTenantID = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyTwitchClientID]; ok { - res.TwitchClientID = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyTwitchClientSecret]; ok { - res.TwitchClientSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyRobloxClientID]; ok { - res.RobloxClientID = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyRobloxClientSecret]; ok { - res.RobloxClientSecret = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyOrganizationName]; ok { - res.OrganizationName = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyOrganizationLogo]; ok { - res.OrganizationLogo = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyDefaultAuthorizeResponseType]; ok { - res.DefaultAuthorizeResponseType = refs.NewStringRef(val.(string)) - } - if val, ok := store[constants.EnvKeyDefaultAuthorizeResponseMode]; ok { - res.DefaultAuthorizeResponseMode = refs.NewStringRef(val.(string)) - } - - // string slice vars - res.AllowedOrigins = strings.Split(store[constants.EnvKeyAllowedOrigins].(string), ",") - res.Roles = strings.Split(store[constants.EnvKeyRoles].(string), ",") - res.DefaultRoles = strings.Split(store[constants.EnvKeyDefaultRoles].(string), ",") - // since protected role is optional default split gives array with empty string - protectedRoles := strings.Split(store[constants.EnvKeyProtectedRoles].(string), ",") - res.ProtectedRoles = []string{} - for _, role := range protectedRoles { - if strings.Trim(role, " ") != "" { - res.ProtectedRoles = append(res.ProtectedRoles, strings.Trim(role, " ")) - } - } - - // bool vars - res.DisableEmailVerification = store[constants.EnvKeyDisableEmailVerification].(bool) - res.DisableBasicAuthentication = store[constants.EnvKeyDisableBasicAuthentication].(bool) - res.DisableMobileBasicAuthentication = store[constants.EnvKeyDisableMobileBasicAuthentication].(bool) - res.DisableMagicLinkLogin = store[constants.EnvKeyDisableMagicLinkLogin].(bool) - res.DisableLoginPage = store[constants.EnvKeyDisableLoginPage].(bool) - res.DisableSignUp = store[constants.EnvKeyDisableSignUp].(bool) - res.DisableStrongPassword = store[constants.EnvKeyDisableStrongPassword].(bool) - res.EnforceMultiFactorAuthentication = store[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) - res.DisableMultiFactorAuthentication = store[constants.EnvKeyDisableMultiFactorAuthentication].(bool) - res.AdminCookieSecure = store[constants.EnvKeyAdminCookieSecure].(bool) - res.AppCookieSecure = store[constants.EnvKeyAppCookieSecure].(bool) - res.DisablePlayground = store[constants.EnvKeyDisablePlayGround].(bool) - res.DisableMailOtpLogin = store[constants.EnvKeyDisableMailOTPLogin].(bool) - res.DisableTotpLogin = store[constants.EnvKeyDisableTOTPLogin].(bool) - - return res, nil -} diff --git a/server/resolvers/forgot_password.go b/server/resolvers/forgot_password.go deleted file mode 100644 index 624955e7b..000000000 --- a/server/resolvers/forgot_password.go +++ /dev/null @@ -1,169 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - mailService "github.com/authorizerdev/authorizer/server/email" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/smsproviders" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// ForgotPasswordResolver is a resolver for forgot password mutation -func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInput) (*model.ForgotPasswordResponse, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) - if err != nil { - log.Debug("Error getting basic auth disabled: ", err) - isBasicAuthDisabled = true - } - isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) - if err != nil { - log.Debug("Error getting email verification disabled: ", err) - isEmailVerificationDisabled = true - } - - isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication) - if err != nil { - log.Debug("Error getting mobile basic auth disabled: ", err) - isMobileBasicAuthDisabled = true - } - isMobileVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) - if err != nil { - log.Debug("Error getting mobile verification disabled: ", err) - isMobileVerificationDisabled = true - } - - email := refs.StringValue(params.Email) - phoneNumber := refs.StringValue(params.PhoneNumber) - if email == "" && phoneNumber == "" { - log.Debug("Email or phone number is required") - return nil, fmt.Errorf(`email or phone number is required`) - } - log := log.WithFields(log.Fields{ - "email": refs.StringValue(params.Email), - "phone_number": refs.StringValue(params.PhoneNumber), - }) - isEmailLogin := email != "" - isMobileLogin := phoneNumber != "" - if isBasicAuthDisabled && isEmailLogin && !isEmailVerificationDisabled { - log.Debug("Basic authentication is disabled.") - return nil, fmt.Errorf(`basic authentication is disabled for this instance`) - } - if isMobileBasicAuthDisabled && isMobileLogin && !isMobileVerificationDisabled { - log.Debug("Mobile basic authentication is disabled.") - return nil, fmt.Errorf(`mobile basic authentication is disabled for this instance`) - } - var user *models.User - if isEmailLogin { - user, err = db.Provider.GetUserByEmail(ctx, email) - } else { - user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber) - } - if err != nil { - log.Debug("Failed to get user: ", err) - return nil, fmt.Errorf(`bad user credentials`) - } - hostname := parsers.GetHost(gc) - _, nonceHash, err := utils.GenerateNonce() - if err != nil { - log.Debug("Failed to generate nonce: ", err) - return nil, err - } - if user.RevokedTimestamp != nil { - log.Debug("User access is revoked") - return nil, fmt.Errorf(`user access has been revoked`) - } - if isEmailLogin { - redirectURI := "" - // give higher preference to params redirect uri - if strings.TrimSpace(refs.StringValue(params.RedirectURI)) != "" { - redirectURI = refs.StringValue(params.RedirectURI) - } else { - redirectURI, err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL) - if err != nil { - log.Debug("ResetPasswordURL not found using default app url: ", err) - redirectURI = hostname + "/app/reset-password" - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, redirectURI) - } - } - verificationToken, err := token.CreateVerificationToken(email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURI) - if err != nil { - log.Debug("Failed to create verification token", err) - return nil, err - } - _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ - Token: verificationToken, - Identifier: constants.VerificationTypeForgotPassword, - ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), - Email: email, - Nonce: nonceHash, - RedirectURI: redirectURI, - }) - if err != nil { - log.Debug("Failed to add verification request", err) - return nil, err - } - // execute it as go routine so that we can reduce the api latency - go mailService.SendEmail([]string{email}, constants.VerificationTypeForgotPassword, map[string]interface{}{ - "user": user.ToMap(), - "organization": utils.GetOrganization(), - "verification_url": utils.GetForgotPasswordURL(verificationToken, redirectURI), - }) - return &model.ForgotPasswordResponse{ - Message: `Please check your inbox! We have sent a password reset link.`, - }, nil - } - if isMobileLogin { - expiresAt := time.Now().Add(1 * time.Minute).Unix() - otp := utils.GenerateOTP() - otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{ - Email: refs.StringValue(user.Email), - PhoneNumber: refs.StringValue(user.PhoneNumber), - Otp: otp, - ExpiresAt: expiresAt, - }) - if err != nil { - log.Debug("Failed to add otp: ", err) - return nil, err - } - mfaSession := uuid.NewString() - err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt) - if err != nil { - log.Debug("Failed to add mfasession: ", err) - return nil, err - } - cookie.SetMfaSession(gc, mfaSession) - smsBody := strings.Builder{} - smsBody.WriteString("Your verification code is: ") - smsBody.WriteString(otpData.Otp) - if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil { - log.Debug("Failed to send sms: ", err) - // continue - } - return &model.ForgotPasswordResponse{ - Message: "Please enter the OTP sent to your phone number and change your password.", - ShouldShowMobileOtpScreen: refs.NewBoolRef(true), - }, nil - } - return nil, fmt.Errorf(`email or phone number verification needs to be enabled`) -} diff --git a/server/resolvers/generate_jwt_keys.go b/server/resolvers/generate_jwt_keys.go deleted file mode 100644 index 323e006e8..000000000 --- a/server/resolvers/generate_jwt_keys.go +++ /dev/null @@ -1,71 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - log "github.com/sirupsen/logrus" -) - -// GenerateJWTKeysResolver mutation to generate new jwt keys -func GenerateJWTKeysResolver(ctx context.Context, params model.GenerateJWTKeysInput) (*model.GenerateJWTKeysResponse, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return nil, fmt.Errorf("unauthorized") - } - - clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) - if err != nil { - log.Debug("Error getting client id: ", err) - return nil, err - } - if crypto.IsHMACA(params.Type) { - secret, _, err := crypto.NewHMACKey(params.Type, clientID) - if err != nil { - log.Debug("Failed to generate new HMAC key: ", err) - return nil, err - } - return &model.GenerateJWTKeysResponse{ - Secret: &secret, - }, nil - } - - if crypto.IsRSA(params.Type) { - _, privateKey, publicKey, _, err := crypto.NewRSAKey(params.Type, clientID) - if err != nil { - log.Debug("Failed to generate new RSA key: ", err) - return nil, err - } - return &model.GenerateJWTKeysResponse{ - PrivateKey: &privateKey, - PublicKey: &publicKey, - }, nil - } - - if crypto.IsECDSA(params.Type) { - _, privateKey, publicKey, _, err := crypto.NewECDSAKey(params.Type, clientID) - if err != nil { - log.Debug("Failed to generate new ECDSA key: ", err) - return nil, err - } - return &model.GenerateJWTKeysResponse{ - PrivateKey: &privateKey, - PublicKey: &publicKey, - }, nil - } - - log.Debug("Invalid algorithm: ", params.Type) - return nil, fmt.Errorf("invalid algorithm") -} diff --git a/server/resolvers/invite_members.go b/server/resolvers/invite_members.go deleted file mode 100644 index 86aac44d9..000000000 --- a/server/resolvers/invite_members.go +++ /dev/null @@ -1,202 +0,0 @@ -package resolvers - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - emailservice "github.com/authorizerdev/authorizer/server/email" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" -) - -// InviteMembersResolver resolver to invite members -func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput) (*model.InviteMembersResponse, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin.") - return nil, errors.New("unauthorized") - } - - // this feature is only allowed if email server is configured - EnvKeyIsEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled) - if err != nil { - log.Debug("Error getting email verification disabled: ", err) - EnvKeyIsEmailServiceEnabled = false - } - - if !EnvKeyIsEmailServiceEnabled { - log.Debug("Email server is not configured") - return nil, errors.New("email sending is disabled") - } - - isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) - if err != nil { - log.Debug("Failed to get is basic auth disabled") - return nil, err - } - isMagicLinkLoginDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMagicLinkLogin) - if err != nil { - log.Debug("Failed to get is magic link login disabled") - return nil, err - } - if isBasicAuthDisabled && isMagicLinkLoginDisabled { - log.Debug("Basic authentication and Magic link login is disabled.") - return nil, errors.New("either basic authentication or magic link login is required") - } - - // filter valid emails - emails := []string{} - for _, email := range params.Emails { - if validators.IsValidEmail(email) { - emails = append(emails, email) - } - } - - if len(emails) == 0 { - log.Debug("No valid email addresses") - return nil, errors.New("no valid emails found") - } - - // TODO: optimise to use like query instead of looping through emails and getting user individually - // for each emails check if emails exists in db - newEmails := []string{} - for _, email := range emails { - _, err := db.Provider.GetUserByEmail(ctx, email) - if err != nil { - log.Debugf("User with %s email not found, so inviting user", email) - newEmails = append(newEmails, email) - } else { - log.Debugf("User with %s email already exists, so not inviting user", email) - } - } - - if len(newEmails) == 0 { - log.Debug("No new emails found.") - return nil, errors.New("all emails already exist") - } - - // invite new emails - for _, email := range newEmails { - - defaultRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - defaultRoles := []string{} - if err != nil { - log.Debug("Error getting default roles: ", err) - defaultRolesString = "" - } else { - defaultRoles = strings.Split(defaultRolesString, ",") - } - - user := &models.User{ - Email: refs.NewStringRef(email), - Roles: strings.Join(defaultRoles, ","), - } - hostname := parsers.GetHost(gc) - verifyEmailURL := hostname + "/verify_email" - appURL := parsers.GetAppURL(gc) - - redirectURL := appURL - if params.RedirectURI != nil { - redirectURL = *params.RedirectURI - } - - _, nonceHash, err := utils.GenerateNonce() - if err != nil { - return nil, err - } - - verificationToken, err := token.CreateVerificationToken(email, constants.VerificationTypeInviteMember, hostname, nonceHash, redirectURL) - if err != nil { - log.Debug("Failed to create verification token: ", err) - } - - verificationRequest := &models.VerificationRequest{ - Token: verificationToken, - ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), - Email: email, - Nonce: nonceHash, - RedirectURI: redirectURL, - } - - // use magic link login if that option is on - if !isMagicLinkLoginDisabled { - user.SignupMethods = constants.AuthRecipeMethodMagicLinkLogin - verificationRequest.Identifier = constants.VerificationTypeMagicLinkLogin - } else { - // use basic authentication if that option is on - user.SignupMethods = constants.AuthRecipeMethodBasicAuth - verificationRequest.Identifier = constants.VerificationTypeInviteMember - - isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication) - if err != nil { - log.Debug("MFA service not enabled: ", err) - isMFAEnforced = false - } - - if isMFAEnforced { - user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) - } - verifyEmailURL = appURL + "/setup-password" - - } - - user, err = db.Provider.AddUser(ctx, user) - if err != nil { - log.Debugf("Error adding user: %s, err: %v", email, err) - return nil, err - } - - _, err = db.Provider.AddVerificationRequest(ctx, verificationRequest) - if err != nil { - log.Debugf("Error adding verification request: %s, err: %v", email, err) - return nil, err - } - - // exec it as go routine so that we can reduce the api latency - go emailservice.SendEmail([]string{refs.StringValue(user.Email)}, constants.VerificationTypeInviteMember, map[string]interface{}{ - "user": user.ToMap(), - "organization": utils.GetOrganization(), - "verification_url": utils.GetInviteVerificationURL(verifyEmailURL, verificationToken, redirectURL), - }) - } - - InvitedUsers := []*model.User{} - - for _, email := range newEmails { - user, err := db.Provider.GetUserByEmail(ctx, email) - - if err != nil { - log.Debugf("err: %s", err.Error()) - return nil, err - } - - InvitedUsers = append(InvitedUsers, &model.User{ - Email: user.Email, - ID: user.ID, - }) - - } - - return &model.InviteMembersResponse{ - Message: fmt.Sprintf("%d user(s) invited successfully.", len(newEmails)), - Users: InvitedUsers, - }, nil -} diff --git a/server/resolvers/login.go b/server/resolvers/login.go deleted file mode 100644 index 159c18e26..000000000 --- a/server/resolvers/login.go +++ /dev/null @@ -1,423 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/google/uuid" - "golang.org/x/crypto/bcrypt" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/authenticators" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - mailService "github.com/authorizerdev/authorizer/server/email" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/smsproviders" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" -) - -// LoginResolver is a resolver for login mutation -// User can login with email or phone number, but not both -func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) { - var res *model.AuthResponse - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) - if err != nil { - log.Debug("Error getting basic auth disabled: ", err) - isBasicAuthDisabled = true - } - - isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication) - if err != nil { - log.Debug("Error getting mobile basic auth disabled: ", err) - isMobileBasicAuthDisabled = true - } - - email := refs.StringValue(params.Email) - phoneNumber := refs.StringValue(params.PhoneNumber) - if email == "" && phoneNumber == "" { - log.Debug("Email or phone number is required") - return res, fmt.Errorf(`email or phone number is required`) - } - log := log.WithFields(log.Fields{ - "email": refs.StringValue(params.Email), - "phone_number": refs.StringValue(params.PhoneNumber), - }) - isEmailLogin := email != "" - isMobileLogin := phoneNumber != "" - if isBasicAuthDisabled { - log.Debug("Basic authentication is disabled.") - return res, fmt.Errorf(`basic authentication is disabled for this instance`) - } - if isMobileBasicAuthDisabled && isMobileLogin { - log.Debug("Mobile basic authentication is disabled.") - return res, fmt.Errorf(`mobile basic authentication is disabled for this instance`) - } - var user *models.User - if isEmailLogin { - user, err = db.Provider.GetUserByEmail(ctx, email) - } else { - user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber) - } - if err != nil { - log.Debug("Failed to get user: ", err) - return res, fmt.Errorf(`user not found`) - } - if user.RevokedTimestamp != nil { - log.Debug("User access is revoked") - return res, fmt.Errorf(`user access has been revoked`) - } - isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled) - if err != nil || !isEmailServiceEnabled { - log.Debug("Email service not enabled: ", err) - } - isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled) - if err != nil || !isSMSServiceEnabled { - log.Debug("SMS service not enabled: ", err) - } - // If multi factor authentication is enabled and we need to generate OTP for mail / sms based MFA - generateOTP := func(expiresAt int64) (*models.OTP, error) { - otp := utils.GenerateOTP() - otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{ - Email: refs.StringValue(user.Email), - PhoneNumber: refs.StringValue(user.PhoneNumber), - Otp: otp, - ExpiresAt: expiresAt, - }) - if err != nil { - log.Debug("Failed to add otp: ", err) - return nil, err - } - return otpData, nil - } - setOTPMFaSession := func(expiresAt int64) error { - mfaSession := uuid.NewString() - err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt) - if err != nil { - log.Debug("Failed to add mfasession: ", err) - return err - } - cookie.SetMfaSession(gc, mfaSession) - return nil - } - if isEmailLogin { - if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodBasicAuth) { - log.Debug("User signup method is not basic auth") - return res, fmt.Errorf(`user has not signed up email & password`) - } - - if user.EmailVerifiedAt == nil { - // Check if email service is enabled - // Send email verification via otp - if !isEmailServiceEnabled { - log.Debug("User email is not verified and email service is not enabled") - return res, fmt.Errorf(`email not verified`) - } else { - if vreq, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup); err == nil && vreq != nil { - // if verification request exists and not expired then return - // if verification request exists and expired then delete it and proceed - if vreq.ExpiresAt <= time.Now().Unix() { - if err := db.Provider.DeleteVerificationRequest(ctx, vreq); err != nil { - log.Debug("Failed to delete verification request: ", err) - // continue with the flow - } - } else { - log.Debug("Verification request exists. Please verify email") - return res, fmt.Errorf(`email verification pending`) - } - } - expiresAt := time.Now().Add(1 * time.Minute).Unix() - otpData, err := generateOTP(expiresAt) - if err != nil { - log.Debug("Failed to generate otp: ", err) - return nil, err - } - if err := setOTPMFaSession(expiresAt); err != nil { - log.Debug("Failed to set mfa session: ", err) - return nil, err - } - go func() { - // exec it as go routine so that we can reduce the api latency - if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{ - "user": user.ToMap(), - "organization": utils.GetOrganization(), - "otp": otpData.Otp, - }); err != nil { - log.Debug("Failed to send otp email: ", err) - } - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) - }() - return &model.AuthResponse{ - Message: "Please check email inbox for the OTP", - ShouldShowEmailOtpScreen: refs.NewBoolRef(isEmailLogin), - }, nil - } - } - } else { - if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth) { - log.Debug("User signup method is not mobile basic auth") - return res, fmt.Errorf(`user has not signed up with phone number & password`) - } - - if user.PhoneNumberVerifiedAt == nil { - if !isSMSServiceEnabled { - log.Debug("User phone number is not verified") - return res, fmt.Errorf(`phone number is not verified and sms service is not enabled`) - } else { - expiresAt := time.Now().Add(1 * time.Minute).Unix() - otpData, err := generateOTP(expiresAt) - if err != nil { - log.Debug("Failed to generate otp: ", err) - return nil, err - } - if err := setOTPMFaSession(expiresAt); err != nil { - log.Debug("Failed to set mfa session: ", err) - return nil, err - } - go func() { - smsBody := strings.Builder{} - smsBody.WriteString("Your verification code is: ") - smsBody.WriteString(otpData.Otp) - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil { - log.Debug("Failed to send sms: ", err) - } - }() - return &model.AuthResponse{ - Message: "Please check text message for the OTP", - ShouldShowMobileOtpScreen: refs.NewBoolRef(isMobileLogin), - }, nil - } - } - } - err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(params.Password)) - if err != nil { - log.Debug("Failed to compare password: ", err) - return res, fmt.Errorf(`bad user credentials`) - } - defaultRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - roles := []string{} - if err != nil { - log.Debug("Error getting default roles: ", err) - defaultRolesString = "" - } else { - roles = strings.Split(defaultRolesString, ",") - } - currentRoles := strings.Split(user.Roles, ",") - if len(params.Roles) > 0 { - if !validators.IsValidRoles(params.Roles, currentRoles) { - log.Debug("Invalid roles: ", params.Roles) - return res, fmt.Errorf(`invalid roles`) - } - roles = params.Roles - } - scope := []string{"openid", "email", "profile"} - if params.Scope != nil && len(scope) > 0 { - scope = params.Scope - } - - isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication) - if err != nil || !isMFADisabled { - log.Debug("MFA service not enabled: ", err) - } - - isTOTPLoginDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin) - if err != nil || !isTOTPLoginDisabled { - log.Debug("totp service not enabled: ", err) - } - - isMailOTPDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMailOTPLogin) - if err != nil || !isMailOTPDisabled { - log.Debug("mail OTP service not enabled: ", err) - } - - isSMSOTPDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) - if err != nil || !isSMSOTPDisabled { - log.Debug("sms OTP service not enabled: ", err) - } - - // If multi factor authentication is enabled and is email based login and email otp is enabled - if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isMailOTPDisabled && isEmailServiceEnabled && isEmailLogin { - expiresAt := time.Now().Add(1 * time.Minute).Unix() - otpData, err := generateOTP(expiresAt) - if err != nil { - log.Debug("Failed to generate otp: ", err) - return nil, err - } - if err := setOTPMFaSession(expiresAt); err != nil { - log.Debug("Failed to set mfa session: ", err) - return nil, err - } - go func() { - // exec it as go routine so that we can reduce the api latency - if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{ - "user": user.ToMap(), - "organization": utils.GetOrganization(), - "otp": otpData.Otp, - }); err != nil { - log.Debug("Failed to send otp email: ", err) - } - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) - }() - return &model.AuthResponse{ - Message: "Please check email inbox for the OTP", - ShouldShowEmailOtpScreen: refs.NewBoolRef(isMobileLogin), - }, nil - } - // If multi factor authentication is enabled and is sms based login and sms otp is enabled - if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isSMSOTPDisabled && isSMSServiceEnabled && isMobileLogin { - expiresAt := time.Now().Add(1 * time.Minute).Unix() - otpData, err := generateOTP(expiresAt) - if err != nil { - log.Debug("Failed to generate otp: ", err) - return nil, err - } - if err := setOTPMFaSession(expiresAt); err != nil { - log.Debug("Failed to set mfa session: ", err) - return nil, err - } - go func() { - smsBody := strings.Builder{} - smsBody.WriteString("Your verification code is: ") - smsBody.WriteString(otpData.Otp) - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil { - log.Debug("Failed to send sms: ", err) - } - }() - return &model.AuthResponse{ - Message: "Please check text message for the OTP", - ShouldShowMobileOtpScreen: refs.NewBoolRef(isMobileLogin), - }, nil - } - // If mfa enabled and also totp enabled - if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isTOTPLoginDisabled { - expiresAt := time.Now().Add(3 * time.Minute).Unix() - if err := setOTPMFaSession(expiresAt); err != nil { - log.Debug("Failed to set mfa session: ", err) - return nil, err - } - authenticator, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, user.ID, constants.EnvKeyTOTPAuthenticator) - if err != nil || authenticator == nil || authenticator.VerifiedAt == nil { - // generate totp - // Generate a base64 URL and initiate the registration for TOTP - authConfig, err := authenticators.Provider.Generate(ctx, user.ID) - if err != nil { - log.Debug("error while generating base64 url: ", err) - return nil, err - } - recoveryCodes := []*string{} - for _, code := range authConfig.RecoveryCodes { - recoveryCodes = append(recoveryCodes, refs.NewStringRef(code)) - } - // when user is first time registering for totp - res = &model.AuthResponse{ - Message: `Proceed to totp verification screen`, - ShouldShowTotpScreen: refs.NewBoolRef(true), - AuthenticatorScannerImage: refs.NewStringRef(authConfig.ScannerImage), - AuthenticatorSecret: refs.NewStringRef(authConfig.Secret), - AuthenticatorRecoveryCodes: recoveryCodes, - } - return res, nil - } else { - //when user is already register for totp - res = &model.AuthResponse{ - Message: `Proceed to totp screen`, - ShouldShowTotpScreen: refs.NewBoolRef(true), - } - return res, nil - } - } - - code := "" - codeChallenge := "" - nonce := "" - if params.State != nil { - // Get state from store - authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State)) - if authorizeState != "" { - authorizeStateSplit := strings.Split(authorizeState, "@@") - if len(authorizeStateSplit) > 1 { - code = authorizeStateSplit[0] - codeChallenge = authorizeStateSplit[1] - } else { - nonce = authorizeState - } - go memorystore.Provider.RemoveState(refs.StringValue(params.State)) - } - } - - if nonce == "" { - nonce = uuid.New().String() - } - authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth, nonce, code) - if err != nil { - log.Debug("Failed to create auth token", err) - return res, err - } - - // TODO add to other login options as well - // Code challenge could be optional if PKCE flow is not used - if code != "" { - if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { - log.Debug("SetState failed: ", err) - return res, err - } - } - - expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() - if expiresIn <= 0 { - expiresIn = 1 - } - - res = &model.AuthResponse{ - Message: `Logged in successfully`, - AccessToken: &authToken.AccessToken.Token, - IDToken: &authToken.IDToken.Token, - ExpiresIn: &expiresIn, - User: user.AsAPIUser(), - } - - cookie.SetSession(gc, authToken.FingerPrintHash) - sessionStoreKey := constants.AuthRecipeMethodBasicAuth + ":" + user.ID - memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) - memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) - - if authToken.RefreshToken != nil { - res.RefreshToken = &authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) - } - - go func() { - // Register event - if isEmailLogin { - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) - } else { - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - } - // Record session - db.Provider.AddSession(ctx, &models.Session{ - UserID: user.ID, - UserAgent: utils.GetUserAgent(gc.Request), - IP: utils.GetIP(gc.Request), - }) - }() - - return res, nil -} diff --git a/server/resolvers/logout.go b/server/resolvers/logout.go deleted file mode 100644 index 0988e1696..000000000 --- a/server/resolvers/logout.go +++ /dev/null @@ -1,42 +0,0 @@ -package resolvers - -import ( - "context" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// LogoutResolver is a resolver for logout mutation -func LogoutResolver(ctx context.Context) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - tokenData, err := token.GetUserIDFromSessionOrAccessToken(gc) - if err != nil { - log.Debug("Failed GetUserIDFromSessionOrAccessToken: ", err) - return nil, err - } - - sessionKey := tokenData.UserID - if tokenData.LoginMethod != "" { - sessionKey = tokenData.LoginMethod + ":" + tokenData.UserID - } - - memorystore.Provider.DeleteUserSession(sessionKey, tokenData.Nonce) - cookie.DeleteSession(gc) - - res := &model.Response{ - Message: "Logged out successfully", - } - - return res, nil -} diff --git a/server/resolvers/magic_link_login.go b/server/resolvers/magic_link_login.go deleted file mode 100644 index 4edacdf98..000000000 --- a/server/resolvers/magic_link_login.go +++ /dev/null @@ -1,236 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/email" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" -) - -// MagicLinkLoginResolver is a resolver for magic link login mutation -func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) { - var res *model.Response - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - isMagicLinkLoginDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMagicLinkLogin) - if err != nil { - log.Debug("Error getting magic link login disabled: ", err) - isMagicLinkLoginDisabled = true - } - - if isMagicLinkLoginDisabled { - log.Debug("Magic link login is disabled.") - return res, fmt.Errorf(`magic link login is disabled for this instance`) - } - - params.Email = strings.ToLower(params.Email) - - if !validators.IsValidEmail(params.Email) { - log.Debug("Invalid email") - return res, fmt.Errorf(`invalid email address`) - } - - log := log.WithFields(log.Fields{ - "email": params.Email, - }) - - inputRoles := []string{} - - user := &models.User{ - Email: refs.NewStringRef(params.Email), - } - - // find user with email - existingUser, err := db.Provider.GetUserByEmail(ctx, params.Email) - if err != nil { - isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) - if err != nil { - log.Debug("Error getting signup disabled: ", err) - } - if isSignupDisabled { - log.Debug("Signup is disabled.") - return res, fmt.Errorf(`signup is disabled for this instance`) - } - - user.SignupMethods = constants.AuthRecipeMethodMagicLinkLogin - // define roles for new user - if len(params.Roles) > 0 { - // check if roles exists - rolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRoles) - roles := []string{} - if err != nil { - log.Debug("Error getting roles: ", err) - return res, err - } else { - roles = strings.Split(rolesString, ",") - } - if !validators.IsValidRoles(params.Roles, roles) { - log.Debug("Invalid roles: ", params.Roles) - return res, fmt.Errorf(`invalid roles`) - } else { - inputRoles = params.Roles - } - } else { - inputRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - log.Debug("Error getting default roles: ", err) - return res, fmt.Errorf(`invalid roles`) - } else { - inputRoles = strings.Split(inputRolesString, ",") - } - } - - user.Roles = strings.Join(inputRoles, ",") - user, _ = db.Provider.AddUser(ctx, user) - go utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodMagicLinkLogin, user) - } else { - user = existingUser - // There multiple scenarios with roles here in magic link login - // 1. user has access to protected roles + roles and trying to login - // 2. user has not signed up for one of the available role but trying to signup. - // Need to modify roles in this case - - if user.RevokedTimestamp != nil { - log.Debug("User access is revoked at: ", user.RevokedTimestamp) - return res, fmt.Errorf(`user access has been revoked`) - } - - // find the unassigned roles - if len(params.Roles) <= 0 { - inputRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - log.Debug("Error getting default roles: ", err) - return res, fmt.Errorf(`invalid default roles`) - } else { - inputRoles = strings.Split(inputRolesString, ",") - } - } - existingRoles := strings.Split(existingUser.Roles, ",") - unasignedRoles := []string{} - for _, ir := range inputRoles { - if !utils.StringSliceContains(existingRoles, ir) { - unasignedRoles = append(unasignedRoles, ir) - } - } - - if len(unasignedRoles) > 0 { - // check if it contains protected unassigned role - hasProtectedRole := false - protectedRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyProtectedRoles) - protectedRoles := []string{} - if err != nil { - log.Debug("Error getting protected roles: ", err) - return res, err - } else { - protectedRoles = strings.Split(protectedRolesString, ",") - } - for _, ur := range unasignedRoles { - if utils.StringSliceContains(protectedRoles, ur) { - hasProtectedRole = true - } - } - - if hasProtectedRole { - log.Debug("User is not assigned one of the protected roles", unasignedRoles) - return res, fmt.Errorf(`invalid roles`) - } else { - user.Roles = existingUser.Roles + "," + strings.Join(unasignedRoles, ",") - } - } else { - user.Roles = existingUser.Roles - } - - signupMethod := existingUser.SignupMethods - if !strings.Contains(signupMethod, constants.AuthRecipeMethodMagicLinkLogin) { - signupMethod = signupMethod + "," + constants.AuthRecipeMethodMagicLinkLogin - } - - user.SignupMethods = signupMethod - user, _ = db.Provider.UpdateUser(ctx, user) - if err != nil { - log.Debug("Failed to update user: ", err) - } - } - - hostname := parsers.GetHost(gc) - isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) - if err != nil { - log.Debug("Error getting email verification disabled: ", err) - isEmailVerificationDisabled = true - } - if !isEmailVerificationDisabled { - // insert verification request - _, nonceHash, err := utils.GenerateNonce() - if err != nil { - log.Debug("Failed to generate nonce: ", err) - return res, err - } - redirectURLParams := "&roles=" + strings.Join(inputRoles, ",") - if params.State != nil { - redirectURLParams = redirectURLParams + "&state=" + refs.StringValue(params.State) - } - if params.Scope != nil && len(params.Scope) > 0 { - redirectURLParams = redirectURLParams + "&scope=" + strings.Join(params.Scope, " ") - } - redirectURL := parsers.GetAppURL(gc) - if params.RedirectURI != nil { - redirectURL = *params.RedirectURI - } - - if strings.Contains(redirectURL, "?") { - redirectURL = redirectURL + "&" + redirectURLParams - } else { - redirectURL = redirectURL + "?" + strings.TrimPrefix(redirectURLParams, "&") - } - - verificationType := constants.VerificationTypeMagicLinkLogin - verificationToken, err := token.CreateVerificationToken(params.Email, verificationType, hostname, nonceHash, redirectURL) - if err != nil { - log.Debug("Failed to create verification token: ", err) - } - _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ - Token: verificationToken, - Identifier: verificationType, - ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), - Email: params.Email, - Nonce: nonceHash, - RedirectURI: redirectURL, - }) - if err != nil { - log.Debug("Failed to add verification request in db: ", err) - return res, err - } - - // exec it as go routine so that we can reduce the api latency - go email.SendEmail([]string{params.Email}, constants.VerificationTypeMagicLinkLogin, map[string]interface{}{ - "user": user.ToMap(), - "organization": utils.GetOrganization(), - "verification_url": utils.GetEmailVerificationURL(verificationToken, hostname, redirectURL), - }) - } - - res = &model.Response{ - Message: `Magic Link has been sent to your email. Please check your inbox!`, - } - - return res, nil -} diff --git a/server/resolvers/meta.go b/server/resolvers/meta.go deleted file mode 100644 index 9fb14c8b2..000000000 --- a/server/resolvers/meta.go +++ /dev/null @@ -1,196 +0,0 @@ -package resolvers - -import ( - "context" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -// MetaResolver is a resolver for meta query -func MetaResolver(ctx context.Context) (*model.Meta, error) { - clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) - if err != nil { - return nil, err - } - - googleClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientID) - if err != nil { - log.Debug("Failed to get Google Client ID from environment variable", err) - googleClientID = "" - } - - googleClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientSecret) - if err != nil { - log.Debug("Failed to get Google Client Secret from environment variable", err) - googleClientSecret = "" - } - - facebookClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientID) - if err != nil { - log.Debug("Failed to get Facebook Client ID from environment variable", err) - facebookClientID = "" - } - - facebookClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientSecret) - if err != nil { - log.Debug("Failed to get Facebook Client Secret from environment variable", err) - facebookClientSecret = "" - } - - linkedClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyLinkedInClientID) - if err != nil { - log.Debug("Failed to get LinkedIn Client ID from environment variable", err) - linkedClientID = "" - } - - linkedInClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyLinkedInClientSecret) - if err != nil { - log.Debug("Failed to get LinkedIn Client Secret from environment variable", err) - linkedInClientSecret = "" - } - - appleClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppleClientID) - if err != nil { - log.Debug("Failed to get Apple Client ID from environment variable", err) - appleClientID = "" - } - - appleClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppleClientSecret) - if err != nil { - log.Debug("Failed to get Apple Client Secret from environment variable", err) - appleClientSecret = "" - } - - githubClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGithubClientID) - if err != nil { - log.Debug("Failed to get Github Client ID from environment variable", err) - githubClientID = "" - } - - githubClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGithubClientSecret) - if err != nil { - log.Debug("Failed to get Github Client Secret from environment variable", err) - githubClientSecret = "" - } - - twitterClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitterClientID) - if err != nil { - log.Debug("Failed to get Twitter Client ID from environment variable", err) - twitterClientID = "" - } - - twitterClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitterClientSecret) - if err != nil { - log.Debug("Failed to get Twitter Client Secret from environment variable", err) - twitterClientSecret = "" - } - - microsoftClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyMicrosoftClientID) - if err != nil { - log.Debug("Failed to get Microsoft Client ID from environment variable", err) - microsoftClientID = "" - } - - microsoftClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyMicrosoftClientSecret) - if err != nil { - log.Debug("Failed to get Microsoft Client Secret from environment variable", err) - microsoftClientSecret = "" - } - - twitchClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitchClientID) - if err != nil { - log.Debug("Failed to get Twitch Client ID from environment variable", err) - microsoftClientID = "" - } - - twitchClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitchClientSecret) - if err != nil { - log.Debug("Failed to get Twitch Client Secret from environment variable", err) - microsoftClientSecret = "" - } - - robloxClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRobloxClientID) - if err != nil { - log.Debug("Failed to get Roblox Client ID from environment variable", err) - microsoftClientID = "" - } - - robloxClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRobloxClientSecret) - if err != nil { - log.Debug("Failed to get Roblox Client Secret from environment variable", err) - microsoftClientSecret = "" - } - - isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) - if err != nil { - log.Debug("Failed to get Disable Basic Authentication from environment variable", err) - isBasicAuthDisabled = true - } - isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication) - if err != nil { - log.Debug("Failed to get Disable Basic Authentication from environment variable", err) - isMobileBasicAuthDisabled = true - } - isMobileVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) - if err != nil { - log.Debug("Failed to get Disable Basic Authentication from environment variable", err) - isMobileVerificationDisabled = true - } - - isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) - if err != nil { - log.Debug("Failed to get Disable Email Verification from environment variable", err) - isEmailVerificationDisabled = true - } - - isMagicLinkLoginDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMagicLinkLogin) - if err != nil { - log.Debug("Failed to get Disable Magic Link Login from environment variable", err) - isMagicLinkLoginDisabled = true - } - - isSignUpDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) - if err != nil { - log.Debug("Failed to get Disable Signup from environment variable", err) - isSignUpDisabled = true - } - - isStrongPasswordDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableStrongPassword) - if err != nil { - log.Debug("Failed to get Disable Signup from environment variable", err) - isSignUpDisabled = true - } - - isMultiFactorAuthenticationEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication) - if err != nil { - log.Debug("Failed to get Disable Multi Factor Authentication from environment variable", err) - isSignUpDisabled = true - } - - metaInfo := model.Meta{ - Version: constants.VERSION, - ClientID: clientID, - IsGoogleLoginEnabled: googleClientID != "" && googleClientSecret != "", - IsGithubLoginEnabled: githubClientID != "" && githubClientSecret != "", - IsFacebookLoginEnabled: facebookClientID != "" && facebookClientSecret != "", - IsLinkedinLoginEnabled: linkedClientID != "" && linkedInClientSecret != "", - IsAppleLoginEnabled: appleClientID != "" && appleClientSecret != "", - IsTwitterLoginEnabled: twitterClientID != "" && twitterClientSecret != "", - IsMicrosoftLoginEnabled: microsoftClientID != "" && microsoftClientSecret != "", - IsBasicAuthenticationEnabled: !isBasicAuthDisabled, - IsEmailVerificationEnabled: !isEmailVerificationDisabled, - IsMagicLinkLoginEnabled: !isMagicLinkLoginDisabled, - IsSignUpEnabled: !isSignUpDisabled, - IsStrongPasswordEnabled: !isStrongPasswordDisabled, - IsMultiFactorAuthEnabled: !isMultiFactorAuthenticationEnabled, - IsMobileBasicAuthenticationEnabled: !isMobileBasicAuthDisabled, - IsPhoneVerificationEnabled: !isMobileVerificationDisabled, - IsTwitchLoginEnabled: twitchClientID != "" && twitchClientSecret != "", - IsRobloxLoginEnabled: robloxClientID != "" && robloxClientSecret != "", - } - return &metaInfo, nil -} diff --git a/server/resolvers/mobile_login.go b/server/resolvers/mobile_login.go deleted file mode 100644 index c3ab9348f..000000000 --- a/server/resolvers/mobile_login.go +++ /dev/null @@ -1,229 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/google/uuid" - log "github.com/sirupsen/logrus" - "golang.org/x/crypto/bcrypt" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/smsproviders" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" -) - -// MobileLoginResolver is a resolver for mobile login mutation -func MobileLoginResolver(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error) { - var res *model.AuthResponse - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication) - if err != nil { - log.Debug("Error getting mobile basic auth disabled: ", err) - isBasicAuthDisabled = true - } - - if isBasicAuthDisabled { - log.Debug("Basic authentication is disabled.") - return res, fmt.Errorf(`phone number based basic authentication is disabled for this instance`) - } - - log := log.WithFields(log.Fields{ - "phone_number": params.PhoneNumber, - }) - - user, err := db.Provider.GetUserByPhoneNumber(ctx, params.PhoneNumber) - if err != nil { - log.Debug("Failed to get user by phone number: ", err) - return res, fmt.Errorf(`bad user credentials`) - } - - if user.RevokedTimestamp != nil { - log.Debug("User access is revoked") - return res, fmt.Errorf(`user access has been revoked`) - } - - if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth) { - log.Debug("User signup method is not mobile basic auth") - return res, fmt.Errorf(`user has not signed up with phone number & password`) - } - - if user.PhoneNumberVerifiedAt == nil { - log.Debug("User phone number is not verified") - return res, fmt.Errorf(`phone number is not verified`) - } - - err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(params.Password)) - - if err != nil { - log.Debug("Failed to compare password: ", err) - return res, fmt.Errorf(`bad user credentials`) - } - - defaultRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - roles := []string{} - if err != nil { - log.Debug("Error getting default roles: ", err) - defaultRolesString = "" - } else { - roles = strings.Split(defaultRolesString, ",") - } - - currentRoles := strings.Split(user.Roles, ",") - if len(params.Roles) > 0 { - if !validators.IsValidRoles(params.Roles, currentRoles) { - log.Debug("Invalid roles: ", params.Roles) - return res, fmt.Errorf(`invalid roles`) - } - - roles = params.Roles - } - - disablePhoneVerification, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) - if err != nil { - log.Debug("Error getting disable phone verification: ", err) - } - if disablePhoneVerification { - now := time.Now().Unix() - user.PhoneNumberVerifiedAt = &now - } - isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled) - if err != nil || !isSMSServiceEnabled { - log.Debug("SMS service not enabled: ", err) - } - if disablePhoneVerification { - now := time.Now().Unix() - user.PhoneNumberVerifiedAt = &now - } - isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication) - if err != nil || !isMFADisabled { - log.Debug("MFA service not enabled: ", err) - } - if !disablePhoneVerification && isSMSServiceEnabled && !isMFADisabled { - duration, _ := time.ParseDuration("10m") - smsCode := utils.GenerateOTP() - - smsBody := strings.Builder{} - smsBody.WriteString("Your verification code is: ") - smsBody.WriteString(smsCode) - expires := time.Now().Add(duration).Unix() - _, err := db.Provider.UpsertOTP(ctx, &models.OTP{ - PhoneNumber: params.PhoneNumber, - Otp: smsCode, - ExpiresAt: expires, - }) - if err != nil { - log.Debug("error while upserting OTP: ", err.Error()) - return nil, err - } - - mfaSession := uuid.NewString() - err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expires) - if err != nil { - log.Debug("Failed to add mfasession: ", err) - return nil, err - } - cookie.SetMfaSession(gc, mfaSession) - - go func() { - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - smsproviders.SendSMS(params.PhoneNumber, smsBody.String()) - }() - return &model.AuthResponse{ - Message: "Please check the OTP", - ShouldShowMobileOtpScreen: refs.NewBoolRef(true), - }, nil - } - - scope := []string{"openid", "email", "profile"} - if params.Scope != nil && len(scope) > 0 { - scope = params.Scope - } - - code := "" - codeChallenge := "" - nonce := "" - if params.State != nil { - // Get state from store - authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State)) - if authorizeState != "" { - authorizeStateSplit := strings.Split(authorizeState, "@@") - if len(authorizeStateSplit) > 1 { - code = authorizeStateSplit[0] - codeChallenge = authorizeStateSplit[1] - } else { - nonce = authorizeState - } - go memorystore.Provider.RemoveState(refs.StringValue(params.State)) - } - } - - if nonce == "" { - nonce = uuid.New().String() - } - - authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code) - if err != nil { - log.Debug("Failed to create auth token", err) - return res, err - } - - // TODO add to other login options as well - // Code challenge could be optional if PKCE flow is not used - if code != "" { - if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { - log.Debug("SetState failed: ", err) - return res, err - } - } - - expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() - if expiresIn <= 0 { - expiresIn = 1 - } - - res = &model.AuthResponse{ - Message: `Logged in successfully`, - AccessToken: &authToken.AccessToken.Token, - IDToken: &authToken.IDToken.Token, - ExpiresIn: &expiresIn, - User: user.AsAPIUser(), - } - - cookie.SetSession(gc, authToken.FingerPrintHash) - sessionStoreKey := constants.AuthRecipeMethodMobileBasicAuth + ":" + user.ID - memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) - memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) - - if authToken.RefreshToken != nil { - res.RefreshToken = &authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) - } - - go func() { - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - db.Provider.AddSession(ctx, &models.Session{ - UserID: user.ID, - UserAgent: utils.GetUserAgent(gc.Request), - IP: utils.GetIP(gc.Request), - }) - }() - - return res, nil -} diff --git a/server/resolvers/mobile_signup.go b/server/resolvers/mobile_signup.go deleted file mode 100644 index 45594cacd..000000000 --- a/server/resolvers/mobile_signup.go +++ /dev/null @@ -1,312 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/smsproviders" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" -) - -// MobileSignupResolver is a resolver for mobile_basic_auth_signup mutation -func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error) { - var res *model.AuthResponse - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) - if err != nil { - log.Debug("Error getting signup disabled: ", err) - isSignupDisabled = true - } - if isSignupDisabled { - log.Debug("Signup is disabled") - return res, fmt.Errorf(`signup is disabled for this instance`) - } - - isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication) - if err != nil { - log.Debug("Error getting basic auth disabled: ", err) - isBasicAuthDisabled = true - } - - if isBasicAuthDisabled { - log.Debug("Mobile based Basic authentication is disabled") - return res, fmt.Errorf(`phone number based basic authentication is disabled for this instance`) - } - - if params.ConfirmPassword != params.Password { - log.Debug("Passwords do not match") - return res, fmt.Errorf(`password and confirm password does not match`) - } - - if err := validators.IsValidPassword(params.Password); err != nil { - log.Debug("Invalid password") - return res, err - } - - mobile := strings.TrimSpace(params.PhoneNumber) - if mobile == "" || len(mobile) < 10 { - log.Debug("Invalid phone number") - return res, fmt.Errorf("invalid phone number") - } - - emailInput := strings.ToLower(strings.TrimSpace(refs.StringValue(params.Email))) - - // if email is null set random dummy email for db constraint - - if emailInput != "" && !validators.IsValidEmail(emailInput) { - log.Debug("Invalid email: ", emailInput) - return res, fmt.Errorf(`invalid email address`) - } - - if emailInput == "" { - emailInput = mobile + "@authorizer.dev" - } - - log := log.WithFields(log.Fields{ - "email": emailInput, - "phone_number": mobile, - }) - // find user with email - existingUser, err := db.Provider.GetUserByPhoneNumber(ctx, mobile) - if err != nil { - log.Debug("Failed to get user by email: ", err) - } - if existingUser != nil { - if existingUser.PhoneNumberVerifiedAt != nil { - // email is verified - log.Debug("Phone number is already verified and signed up.") - return res, fmt.Errorf(`%s has already signed up`, mobile) - } else if existingUser.ID != "" && existingUser.PhoneNumberVerifiedAt == nil { - log.Debug("Phone number is already signed up. Verification pending...") - return res, fmt.Errorf("%s has already signed up. please complete the phone number verification process or reset the password", mobile) - } - } - - inputRoles := []string{} - if len(params.Roles) > 0 { - // check if roles exists - rolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRoles) - roles := []string{} - if err != nil { - log.Debug("Error getting roles: ", err) - return res, err - } else { - roles = strings.Split(rolesString, ",") - } - if !validators.IsValidRoles(params.Roles, roles) { - log.Debug("Invalid roles: ", params.Roles) - return res, fmt.Errorf(`invalid roles`) - } else { - inputRoles = params.Roles - } - } else { - inputRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - log.Debug("Error getting default roles: ", err) - return res, err - } else { - inputRoles = strings.Split(inputRolesString, ",") - } - } - - user := &models.User{ - Email: &emailInput, - PhoneNumber: &mobile, - } - - user.Roles = strings.Join(inputRoles, ",") - - password, _ := crypto.EncryptPassword(params.Password) - user.Password = &password - - if params.GivenName != nil { - user.GivenName = params.GivenName - } - - if params.FamilyName != nil { - user.FamilyName = params.FamilyName - } - - if params.MiddleName != nil { - user.MiddleName = params.MiddleName - } - - if params.Nickname != nil { - user.Nickname = params.Nickname - } - - if params.Gender != nil { - user.Gender = params.Gender - } - - if params.Birthdate != nil { - user.Birthdate = params.Birthdate - } - - if params.Picture != nil { - user.Picture = params.Picture - } - - if params.IsMultiFactorAuthEnabled != nil { - user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled - } - - isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication) - if err != nil { - log.Debug("MFA service not enabled: ", err) - isMFAEnforced = false - } - - if isMFAEnforced { - user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) - } - - disablePhoneVerification, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) - if disablePhoneVerification { - now := time.Now().Unix() - user.PhoneNumberVerifiedAt = &now - } - isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled) - if err != nil || !isSMSServiceEnabled { - log.Debug("SMS service not enabled: ", err) - } - - user.SignupMethods = constants.AuthRecipeMethodMobileBasicAuth - user, err = db.Provider.AddUser(ctx, user) - - if err != nil { - log.Debug("Failed to add user: ", err) - return res, err - } - if !disablePhoneVerification && isSMSServiceEnabled { - duration, _ := time.ParseDuration("10m") - smsCode := utils.GenerateOTP() - - smsBody := strings.Builder{} - smsBody.WriteString("Your verification code is: ") - smsBody.WriteString(smsCode) - - // TODO: For those who enabled the webhook to call their sms vendor separately - sending the otp to their api - if err != nil { - log.Debug("error while upserting user: ", err.Error()) - return nil, err - } - _, err = db.Provider.UpsertOTP(ctx, &models.OTP{ - PhoneNumber: mobile, - Otp: smsCode, - ExpiresAt: time.Now().Add(duration).Unix(), - }) - if err != nil { - log.Debug("error while upserting OTP: ", err.Error()) - return nil, err - } - go func() { - smsproviders.SendSMS(mobile, smsBody.String()) - utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) - }() - return &model.AuthResponse{ - Message: "Please check the OTP in your inbox", - ShouldShowMobileOtpScreen: refs.NewBoolRef(true), - }, nil - } - - roles := strings.Split(user.Roles, ",") - userToReturn := user.AsAPIUser() - - scope := []string{"openid", "email", "profile"} - if params.Scope != nil && len(scope) > 0 { - scope = params.Scope - } - - code := "" - codeChallenge := "" - nonce := "" - if params.State != nil { - // Get state from store - authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State)) - if authorizeState != "" { - authorizeStateSplit := strings.Split(authorizeState, "@@") - if len(authorizeStateSplit) > 1 { - code = authorizeStateSplit[0] - codeChallenge = authorizeStateSplit[1] - } else { - nonce = authorizeState - } - go memorystore.Provider.RemoveState(refs.StringValue(params.State)) - } - } - - if nonce == "" { - nonce = uuid.New().String() - } - - authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code) - if err != nil { - log.Debug("Failed to create auth token: ", err) - return res, err - } - - // Code challenge could be optional if PKCE flow is not used - if code != "" { - if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { - log.Debug("SetState failed: ", err) - return res, err - } - } - - expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() - if expiresIn <= 0 { - expiresIn = 1 - } - - res = &model.AuthResponse{ - Message: `Signed up successfully.`, - AccessToken: &authToken.AccessToken.Token, - ExpiresIn: &expiresIn, - User: userToReturn, - } - - sessionKey := constants.AuthRecipeMethodMobileBasicAuth + ":" + user.ID - cookie.SetSession(gc, 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, authToken.AccessToken.ExpiresAt) - - if authToken.RefreshToken != nil { - res.RefreshToken = &authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) - } - - go func() { - utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - // User is also logged in with signup - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - db.Provider.AddSession(ctx, &models.Session{ - UserID: user.ID, - UserAgent: utils.GetUserAgent(gc.Request), - IP: utils.GetIP(gc.Request), - }) - }() - - return res, nil -} diff --git a/server/resolvers/profile.go b/server/resolvers/profile.go deleted file mode 100644 index df7092ce8..000000000 --- a/server/resolvers/profile.go +++ /dev/null @@ -1,38 +0,0 @@ -package resolvers - -import ( - "context" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// ProfileResolver is a resolver for profile query -func ProfileResolver(ctx context.Context) (*model.User, error) { - var res *model.User - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - tokenData, err := token.GetUserIDFromSessionOrAccessToken(gc) - if err != nil { - log.Debug("Failed GetUserIDFromSessionOrAccessToken: ", err) - return res, err - } - log := log.WithFields(log.Fields{ - "user_id": tokenData.UserID, - }) - user, err := db.Provider.GetUserByID(ctx, tokenData.UserID) - if err != nil { - log.Debug("Failed to get user: ", err) - return res, err - } - - return user.AsAPIUser(), nil -} diff --git a/server/resolvers/resend_otp.go b/server/resolvers/resend_otp.go deleted file mode 100644 index 8b9ac842a..000000000 --- a/server/resolvers/resend_otp.go +++ /dev/null @@ -1,162 +0,0 @@ -package resolvers - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - mailService "github.com/authorizerdev/authorizer/server/email" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/smsproviders" - "github.com/authorizerdev/authorizer/server/utils" -) - -// ResendOTPResolver is a resolver for resend otp mutation -func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error) { - email := strings.ToLower(strings.Trim(refs.StringValue(params.Email), " ")) - phoneNumber := strings.Trim(refs.StringValue(params.PhoneNumber), " ") - log := log.WithFields(log.Fields{ - "email": email, - "phone_number": phoneNumber, - }) - if email == "" && phoneNumber == "" { - log.Debug("Email or phone number is required") - return nil, errors.New("email or phone number is required") - } - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - var user *models.User - var isEmailServiceEnabled, isSMSServiceEnabled bool - if email != "" { - isEmailServiceEnabled, err = memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled) - if err != nil || !isEmailServiceEnabled { - log.Debug("Email service not enabled: ", err) - return nil, errors.New("email service not enabled") - } - user, err = db.Provider.GetUserByEmail(ctx, email) - if err != nil { - log.Debug("Failed to get user by email: ", err) - return nil, fmt.Errorf(`user with this email/phone not found`) - } - } else { - isSMSServiceEnabled, err = memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled) - if err != nil || !isSMSServiceEnabled { - log.Debug("Email service not enabled: ", err) - return nil, errors.New("email service not enabled") - } - user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber) - if err != nil { - log.Debug("Failed to get user by phone: ", err) - return nil, fmt.Errorf(`user with this email/phone not found`) - } - } - if user.RevokedTimestamp != nil { - log.Debug("User access is revoked") - return nil, fmt.Errorf(`user access has been revoked`) - } - - if !refs.BoolValue(user.IsMultiFactorAuthEnabled) && user.EmailVerifiedAt != nil && user.PhoneNumberVerifiedAt != nil { - log.Debug("User multi factor authentication is not enabled") - return nil, fmt.Errorf(`multi factor authentication not enabled`) - } - - isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication) - if err != nil || isMFADisabled { - log.Debug("MFA service not enabled: ", err) - return nil, errors.New("multi factor authentication is disabled for this instance") - } - - // get otp by email or phone number - var otpData *models.OTP - if email != "" { - otpData, err = db.Provider.GetOTPByEmail(ctx, refs.StringValue(params.Email)) - } else { - otpData, err = db.Provider.GetOTPByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber)) - } - if err != nil { - log.Debug("Failed to get otp for given email: ", err) - return nil, err - } - if otpData == nil { - log.Debug("No otp found for given email: ", params.Email) - return &model.Response{ - Message: "Failed to get for given email", - }, errors.New("failed to get otp for given email") - } - // If multi factor authentication is enabled and we need to generate OTP for mail / sms based MFA - generateOTP := func(expiresAt int64) (*models.OTP, error) { - otp := utils.GenerateOTP() - otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{ - Email: refs.StringValue(user.Email), - PhoneNumber: refs.StringValue(user.PhoneNumber), - Otp: otp, - ExpiresAt: expiresAt, - }) - if err != nil { - log.Debug("Failed to add otp: ", err) - return nil, err - } - return otpData, nil - } - setOTPMFaSession := func(expiresAt int64) error { - mfaSession := uuid.NewString() - err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt) - if err != nil { - log.Debug("Failed to add mfasession: ", err) - return err - } - cookie.SetMfaSession(gc, mfaSession) - return nil - } - expiresAt := time.Now().Add(1 * time.Minute).Unix() - otpData, err = generateOTP(expiresAt) - if err != nil { - log.Debug("Failed to generate otp: ", err) - return nil, err - } - if err := setOTPMFaSession(expiresAt); err != nil { - log.Debug("Failed to set mfa session: ", err) - return nil, err - } - if email != "" { - go func() { - // exec it as go routine so that we can reduce the api latency - if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{ - "user": user.ToMap(), - "organization": utils.GetOrganization(), - "otp": otpData.Otp, - }); err != nil { - log.Debug("Failed to send otp email: ", err) - } - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) - }() - } else { - go func() { - smsBody := strings.Builder{} - smsBody.WriteString("Your verification code is: ") - smsBody.WriteString(otpData.Otp) - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil { - log.Debug("Failed to send sms: ", err) - } - }() - } - log.Info("OTP has been resent") - return &model.Response{ - Message: `OTP has been sent. Please check your inbox`, - }, nil -} diff --git a/server/resolvers/resend_verify_email.go b/server/resolvers/resend_verify_email.go deleted file mode 100644 index b5a789f56..000000000 --- a/server/resolvers/resend_verify_email.go +++ /dev/null @@ -1,94 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/email" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" -) - -// ResendVerifyEmailResolver is a resolver for resend verify email mutation -func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) { - var res *model.Response - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - params.Email = strings.ToLower(params.Email) - - if !validators.IsValidEmail(params.Email) { - log.Debug("Invalid email: ", params.Email) - return res, fmt.Errorf("invalid email") - } - - if !validators.IsValidVerificationIdentifier(params.Identifier) { - log.Debug("Invalid verification identifier: ", params.Identifier) - return res, fmt.Errorf("invalid identifier") - } - - user, err := db.Provider.GetUserByEmail(ctx, params.Email) - if err != nil { - return res, fmt.Errorf("invalid user") - } - - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, params.Email, params.Identifier) - if err != nil { - log.Debug("Failed to get verification request: ", err) - return res, fmt.Errorf(`verification request not found`) - } - - // delete current verification and create new one - err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest) - if err != nil { - log.Debug("Failed to delete verification request: ", err) - } - - hostname := parsers.GetHost(gc) - _, nonceHash, err := utils.GenerateNonce() - if err != nil { - log.Debug("Failed to generate nonce: ", err) - return res, err - } - - verificationToken, err := token.CreateVerificationToken(params.Email, params.Identifier, hostname, nonceHash, verificationRequest.RedirectURI) - if err != nil { - log.Debug("Failed to create verification token: ", err) - } - _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ - Token: verificationToken, - Identifier: params.Identifier, - ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), - Email: params.Email, - Nonce: nonceHash, - RedirectURI: verificationRequest.RedirectURI, - }) - if err != nil { - log.Debug("Failed to add verification request: ", err) - } - - // exec it as go routine so that we can reduce the api latency - go email.SendEmail([]string{params.Email}, params.Identifier, map[string]interface{}{ - "user": user.ToMap(), - "organization": utils.GetOrganization(), - "verification_url": utils.GetEmailVerificationURL(verificationToken, hostname, verificationRequest.RedirectURI), - }) - - res = &model.Response{ - Message: `Verification email has been sent. Please check your inbox`, - } - - return res, nil -} diff --git a/server/resolvers/reset_password.go b/server/resolvers/reset_password.go deleted file mode 100644 index 2efcd67fa..000000000 --- a/server/resolvers/reset_password.go +++ /dev/null @@ -1,185 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" -) - -// ResetPasswordResolver is a resolver for reset password mutation -func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) { - var res *model.Response - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - verifyingToken := refs.StringValue(params.Token) - otp := refs.StringValue(params.Otp) - if verifyingToken == "" && otp == "" { - log.Debug("Token or OTP is required") - return res, fmt.Errorf(`token or otp is required`) - } - isTokenVerification := verifyingToken != "" - isOtpVerification := otp != "" - if isOtpVerification && refs.StringValue(params.PhoneNumber) == "" { - log.Debug("Phone number is required") - return res, fmt.Errorf(`phone number is required`) - } - isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) - if err != nil { - log.Debug("Error getting basic auth disabled: ", err) - isBasicAuthDisabled = true - } - isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication) - if err != nil { - log.Debug("Error getting mobile basic auth disabled: ", err) - isBasicAuthDisabled = true - } - if isTokenVerification && isBasicAuthDisabled { - log.Debug("Basic authentication is disabled") - return res, fmt.Errorf(`basic authentication is disabled for this instance`) - } - if isOtpVerification && isMobileBasicAuthDisabled { - log.Debug("Mobile basic authentication is disabled") - return res, fmt.Errorf(`mobile basic authentication is disabled for this instance`) - } - email := "" - phoneNumber := refs.StringValue(params.PhoneNumber) - var user *models.User - var verificationRequest *models.VerificationRequest - var otpRequest *models.OTP - if isTokenVerification { - verificationRequest, err = db.Provider.GetVerificationRequestByToken(ctx, verifyingToken) - if err != nil { - log.Debug("Failed to get verification request: ", err) - return res, fmt.Errorf(`invalid token`) - } - // verify if token exists in db - hostname := parsers.GetHost(gc) - claim, err := token.ParseJWTToken(verifyingToken) - if err != nil { - log.Debug("Failed to parse token: ", err) - return res, fmt.Errorf(`invalid token`) - } - - if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil { - log.Debug("Failed to validate jwt claims: ", err) - return res, fmt.Errorf(`invalid token`) - } - email = claim["sub"].(string) - user, err = db.Provider.GetUserByEmail(ctx, email) - if err != nil { - log.Debug("Failed to get user: ", err) - return res, err - } - } - if isOtpVerification { - mfaSession, err := cookie.GetMfaSession(gc) - if err != nil { - log.Debug("Failed to get otp request by email: ", err) - return res, fmt.Errorf(`invalid session: %s`, err.Error()) - } - // Get user by phone number - user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber) - if err != nil { - log.Debug("Failed to get user by phone number: ", err) - return res, fmt.Errorf(`user not found`) - } - if _, err := memorystore.Provider.GetMfaSession(user.ID, mfaSession); err != nil { - log.Debug("Failed to get mfa session: ", err) - return res, fmt.Errorf(`invalid session: %s`, err.Error()) - } - otpRequest, err = db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber) - if err != nil { - log.Debug("Failed to get otp request by phone number: ", err) - return res, fmt.Errorf(`invalid otp`) - } - if otpRequest.Otp != otp { - log.Debug("Failed to verify otp request: Incorrect value") - return res, fmt.Errorf(`invalid otp`) - } - } - if params.Password != params.ConfirmPassword { - log.Debug("Passwords do not match") - return res, fmt.Errorf(`passwords don't match`) - } - if err := validators.IsValidPassword(params.Password); err != nil { - log.Debug("Invalid password") - return res, err - } - log := log.WithFields(log.Fields{ - "email": email, - "phone": phoneNumber, - }) - password, _ := crypto.EncryptPassword(params.Password) - user.Password = &password - signupMethod := user.SignupMethods - if !strings.Contains(signupMethod, constants.AuthRecipeMethodBasicAuth) && isTokenVerification { - signupMethod = signupMethod + "," + constants.AuthRecipeMethodBasicAuth - // helpful if user has not signed up with basic auth - if user.EmailVerifiedAt == nil { - now := time.Now().Unix() - user.EmailVerifiedAt = &now - } - } - if !strings.Contains(signupMethod, constants.AuthRecipeMethodMobileOTP) && isOtpVerification { - signupMethod = signupMethod + "," + constants.AuthRecipeMethodMobileOTP - // helpful if user has not signed up with basic auth - if user.PhoneNumberVerifiedAt == nil { - now := time.Now().Unix() - user.PhoneNumberVerifiedAt = &now - } - } - user.SignupMethods = signupMethod - isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication) - if err != nil { - log.Debug("MFA service not enabled: ", err) - isMFAEnforced = false - } - if isMFAEnforced { - user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) - } - _, err = db.Provider.UpdateUser(ctx, user) - if err != nil { - log.Debug("Failed to update user: ", err) - return res, err - } - if isTokenVerification { - // delete from verification table - err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest) - if err != nil { - log.Debug("Failed to delete verification request: ", err) - return res, err - } - } - if isOtpVerification { - // delete from otp table - err = db.Provider.DeleteOTP(ctx, otpRequest) - if err != nil { - log.Debug("Failed to delete otp request: ", err) - return res, err - } - } - res = &model.Response{ - Message: `Password updated successfully.`, - } - return res, nil -} diff --git a/server/resolvers/revoke.go b/server/resolvers/revoke.go deleted file mode 100644 index 694e36bee..000000000 --- a/server/resolvers/revoke.go +++ /dev/null @@ -1,16 +0,0 @@ -package resolvers - -import ( - "context" - - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -// RevokeResolver resolver to revoke refresh token -func RevokeResolver(ctx context.Context, params model.OAuthRevokeInput) (*model.Response, error) { - memorystore.Provider.RemoveState(params.RefreshToken) - return &model.Response{ - Message: "Token revoked", - }, nil -} diff --git a/server/resolvers/revoke_access.go b/server/resolvers/revoke_access.go deleted file mode 100644 index 12623975a..000000000 --- a/server/resolvers/revoke_access.go +++ /dev/null @@ -1,61 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// RevokeAccessResolver is a resolver for revoking user access -func RevokeAccessResolver(ctx context.Context, params model.UpdateAccessInput) (*model.Response, error) { - var res *model.Response - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return res, fmt.Errorf("unauthorized") - } - - log := log.WithFields(log.Fields{ - "user_id": params.UserID, - }) - user, err := db.Provider.GetUserByID(ctx, params.UserID) - if err != nil { - log.Debug("Failed to get user by ID: ", err) - return res, err - } - - now := time.Now().Unix() - user.RevokedTimestamp = &now - - user, err = db.Provider.UpdateUser(ctx, user) - if err != nil { - log.Debug("Failed to update user: ", err) - return res, err - } - - go func() { - memorystore.Provider.DeleteAllUserSessions(user.ID) - utils.RegisterEvent(ctx, constants.UserAccessRevokedWebhookEvent, "", user) - }() - - res = &model.Response{ - Message: `user access revoked successfully`, - } - - return res, nil -} diff --git a/server/resolvers/session.go b/server/resolvers/session.go deleted file mode 100644 index 964d1b506..000000000 --- a/server/resolvers/session.go +++ /dev/null @@ -1,110 +0,0 @@ -package resolvers - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// SessionResolver is a resolver for session query -// TODO allow validating with code and code verifier instead of cookie (PKCE flow) -func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*model.AuthResponse, error) { - var res *model.AuthResponse - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - sessionToken, err := cookie.GetSession(gc) - if err != nil { - log.Debug("Failed to get session token: ", err) - return res, errors.New("unauthorized") - } - - // get session from cookie - claims, err := token.ValidateBrowserSession(gc, sessionToken) - if err != nil { - log.Debug("Failed to validate session token: ", err) - return res, errors.New("unauthorized") - } - userID := claims.Subject - - log := log.WithFields(log.Fields{ - "user_id": userID, - }) - - user, err := db.Provider.GetUserByID(ctx, userID) - if err != nil { - return res, err - } - - // refresh token has "roles" as claim - claimRoleInterface := claims.Roles - claimRoles := []string{} - claimRoles = append(claimRoles, claimRoleInterface...) - - if params != nil && params.Roles != nil && len(params.Roles) > 0 { - for _, v := range params.Roles { - if !utils.StringSliceContains(claimRoles, v) { - log.Debug("User does not have required role: ", claimRoles, v) - return res, fmt.Errorf(`unauthorized`) - } - } - } - - scope := []string{"openid", "email", "profile"} - if params != nil && params.Scope != nil && len(scope) > 0 { - scope = params.Scope - } - - nonce := uuid.New().String() - authToken, err := token.CreateAuthToken(gc, user, claimRoles, scope, claims.LoginMethod, nonce, "") - if err != nil { - log.Debug("Failed to create auth token: ", err) - return res, err - } - - // rollover the session for security - sessionKey := userID - if claims.LoginMethod != "" { - sessionKey = claims.LoginMethod + ":" + userID - } - go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce) - - expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() - if expiresIn <= 0 { - expiresIn = 1 - } - - res = &model.AuthResponse{ - Message: `Session token refreshed`, - AccessToken: &authToken.AccessToken.Token, - ExpiresIn: &expiresIn, - IDToken: &authToken.IDToken.Token, - User: user.AsAPIUser(), - } - - cookie.SetSession(gc, 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, authToken.AccessToken.ExpiresAt) - - if authToken.RefreshToken != nil { - res.RefreshToken = &authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) - } - return res, nil -} diff --git a/server/resolvers/signup.go b/server/resolvers/signup.go deleted file mode 100644 index a42d24246..000000000 --- a/server/resolvers/signup.go +++ /dev/null @@ -1,403 +0,0 @@ -package resolvers - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "strings" - "time" - - "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - emailService "github.com/authorizerdev/authorizer/server/email" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/smsproviders" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" -) - -// SignupResolver is a resolver for signup mutation -func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) { - var res *model.AuthResponse - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) - if err != nil { - log.Debug("Error getting signup disabled: ", err) - isSignupDisabled = true - } - if isSignupDisabled { - log.Debug("Signup is disabled") - return res, fmt.Errorf(`signup is disabled for this instance`) - } - - isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) - if err != nil { - log.Debug("Error getting basic auth disabled: ", err) - isBasicAuthDisabled = true - } - isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication) - if err != nil { - log.Debug("Error getting mobile basic auth disabled: ", err) - isMobileBasicAuthDisabled = true - } - if params.ConfirmPassword != params.Password { - log.Debug("Passwords do not match") - return res, fmt.Errorf(`password and confirm password does not match`) - } - if err := validators.IsValidPassword(params.Password); err != nil { - log.Debug("Invalid password") - return res, err - } - email := strings.TrimSpace(refs.StringValue(params.Email)) - phoneNumber := strings.TrimSpace(refs.StringValue(params.PhoneNumber)) - if email == "" && phoneNumber == "" { - log.Debug("Email or phone number is required") - return res, fmt.Errorf(`email or phone number is required`) - } - isEmailSignup := email != "" - isMobileSignup := phoneNumber != "" - if isBasicAuthDisabled && isEmailSignup { - log.Debug("Basic authentication is disabled") - return res, fmt.Errorf(`basic authentication is disabled for this instance`) - } - if isMobileBasicAuthDisabled && isMobileSignup { - log.Debug("Mobile basic authentication is disabled") - return res, fmt.Errorf(`mobile basic authentication is disabled for this instance`) - } - if isEmailSignup && !validators.IsValidEmail(email) { - log.Debug("Invalid email: ", params.Email) - return res, fmt.Errorf(`invalid email address`) - } - if isMobileSignup && (phoneNumber == "" || len(phoneNumber) < 10) { - log.Debug("Invalid phone number: ", phoneNumber) - return res, fmt.Errorf(`invalid phone number`) - } - log := log.WithFields(log.Fields{ - "email": email, - "phone_number": phoneNumber, - }) - // find user with email / phone number - if isEmailSignup { - existingUser, err := db.Provider.GetUserByEmail(ctx, email) - if err != nil { - log.Debug("Failed to get user by email: ", err) - } - if existingUser != nil { - if existingUser.EmailVerifiedAt != nil { - // email is verified - log.Debug("Email is already verified and signed up.") - return res, fmt.Errorf(`%s has already signed up`, email) - } else if existingUser.ID != "" && existingUser.EmailVerifiedAt == nil { - log.Debug("Email is already signed up. Verification pending...") - return res, fmt.Errorf("%s has already signed up. please complete the email verification process or reset the password", email) - } - } - } else { - existingUser, err := db.Provider.GetUserByPhoneNumber(ctx, phoneNumber) - if err != nil { - log.Debug("Failed to get user by phone number: ", err) - } - if existingUser != nil { - if existingUser.PhoneNumberVerifiedAt != nil { - // email is verified - log.Debug("Phone number is already verified and signed up.") - return res, fmt.Errorf(`%s has already signed up`, phoneNumber) - } else if existingUser.ID != "" && existingUser.PhoneNumberVerifiedAt == nil { - log.Debug("Phone number is already signed up. Verification pending...") - return res, fmt.Errorf("%s has already signed up. please complete the phone number verification process or reset the password", phoneNumber) - } - } - } - - inputRoles := []string{} - if len(params.Roles) > 0 { - // check if roles exists - rolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRoles) - roles := []string{} - if err != nil { - log.Debug("Error getting roles: ", err) - return res, err - } else { - roles = strings.Split(rolesString, ",") - } - if !validators.IsValidRoles(params.Roles, roles) { - log.Debug("Invalid roles: ", params.Roles) - return res, fmt.Errorf(`invalid roles`) - } else { - inputRoles = params.Roles - } - } else { - inputRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - if err != nil { - log.Debug("Error getting default roles: ", err) - return res, err - } else { - inputRoles = strings.Split(inputRolesString, ",") - } - } - user := &models.User{} - user.Roles = strings.Join(inputRoles, ",") - password, _ := crypto.EncryptPassword(params.Password) - user.Password = &password - if email != "" { - user.SignupMethods = constants.AuthRecipeMethodBasicAuth - user.Email = &email - } - if params.GivenName != nil { - user.GivenName = params.GivenName - } - - if params.FamilyName != nil { - user.FamilyName = params.FamilyName - } - - if params.MiddleName != nil { - user.MiddleName = params.MiddleName - } - - if params.Nickname != nil { - user.Nickname = params.Nickname - } - - if params.Gender != nil { - user.Gender = params.Gender - } - - if params.Birthdate != nil { - user.Birthdate = params.Birthdate - } - - if phoneNumber != "" { - user.SignupMethods = constants.AuthRecipeMethodMobileBasicAuth - user.PhoneNumber = refs.NewStringRef(phoneNumber) - } - - if params.Picture != nil { - user.Picture = params.Picture - } - - if params.IsMultiFactorAuthEnabled != nil { - user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled - } - - isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication) - if err != nil { - log.Debug("MFA service not enabled: ", err) - isMFAEnforced = false - } - - if isMFAEnforced { - user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) - } - - if params.AppData != nil { - appDataString := "" - appDataBytes, err := json.Marshal(params.AppData) - if err != nil { - log.Debug("failed to marshall source app_data: ", err) - return nil, errors.New("malformed app_data") - } - appDataString = string(appDataBytes) - user.AppData = &appDataString - } - isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) - if err != nil { - log.Debug("Error getting email verification disabled: ", err) - isEmailVerificationDisabled = true - } - if isEmailVerificationDisabled && isEmailSignup { - now := time.Now().Unix() - user.EmailVerifiedAt = &now - } - disablePhoneVerification, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) - if disablePhoneVerification && isMobileSignup { - now := time.Now().Unix() - user.PhoneNumberVerifiedAt = &now - } - isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled) - if err != nil || !isSMSServiceEnabled { - log.Debug("SMS service not enabled: ", err) - } - user, err = db.Provider.AddUser(ctx, user) - if err != nil { - log.Debug("Failed to add user: ", err) - return res, err - } - roles := strings.Split(user.Roles, ",") - userToReturn := user.AsAPIUser() - hostname := parsers.GetHost(gc) - if !isEmailVerificationDisabled && isEmailSignup { - // insert verification request - _, nonceHash, err := utils.GenerateNonce() - if err != nil { - log.Debug("Failed to generate nonce: ", err) - return res, err - } - verificationType := constants.VerificationTypeBasicAuthSignup - redirectURL := parsers.GetAppURL(gc) - if params.RedirectURI != nil { - redirectURL = *params.RedirectURI - } - verificationToken, err := token.CreateVerificationToken(email, verificationType, hostname, nonceHash, redirectURL) - if err != nil { - log.Debug("Failed to create verification token: ", err) - return res, err - } - _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ - Token: verificationToken, - Identifier: verificationType, - ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), - Email: email, - Nonce: nonceHash, - RedirectURI: redirectURL, - }) - if err != nil { - log.Debug("Failed to add verification request: ", err) - return res, err - } - // exec it as go routine so that we can reduce the api latency - go func() { - // exec it as go routine so that we can reduce the api latency - emailService.SendEmail([]string{email}, constants.VerificationTypeBasicAuthSignup, map[string]interface{}{ - "user": user.ToMap(), - "organization": utils.GetOrganization(), - "verification_url": utils.GetEmailVerificationURL(verificationToken, hostname, redirectURL), - }) - utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) - }() - - return &model.AuthResponse{ - Message: `Verification email has been sent. Please check your inbox`, - User: userToReturn, - }, nil - } else if !disablePhoneVerification && isSMSServiceEnabled && isMobileSignup { - duration, _ := time.ParseDuration("10m") - smsCode := utils.GenerateOTP() - smsBody := strings.Builder{} - smsBody.WriteString("Your verification code is: ") - smsBody.WriteString(smsCode) - expiresAt := time.Now().Add(duration).Unix() - _, err = db.Provider.UpsertOTP(ctx, &models.OTP{ - PhoneNumber: phoneNumber, - Otp: smsCode, - ExpiresAt: expiresAt, - }) - if err != nil { - log.Debug("error while upserting OTP: ", err.Error()) - return nil, err - } - mfaSession := uuid.NewString() - err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt) - if err != nil { - log.Debug("Failed to add mfasession: ", err) - return nil, err - } - cookie.SetMfaSession(gc, mfaSession) - go func() { - smsproviders.SendSMS(phoneNumber, smsBody.String()) - utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - }() - return &model.AuthResponse{ - Message: "Please check the OTP in your inbox", - ShouldShowMobileOtpScreen: refs.NewBoolRef(true), - }, nil - } - scope := []string{"openid", "email", "profile"} - if params.Scope != nil && len(scope) > 0 { - scope = params.Scope - } - - code := "" - codeChallenge := "" - nonce := "" - if params.State != nil { - // Get state from store - authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State)) - if authorizeState != "" { - authorizeStateSplit := strings.Split(authorizeState, "@@") - if len(authorizeStateSplit) > 1 { - code = authorizeStateSplit[0] - codeChallenge = authorizeStateSplit[1] - } else { - nonce = authorizeState - } - go memorystore.Provider.RemoveState(refs.StringValue(params.State)) - } - } - - if nonce == "" { - nonce = uuid.New().String() - } - - authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth, nonce, code) - if err != nil { - log.Debug("Failed to create auth token: ", err) - return res, err - } - - // Code challenge could be optional if PKCE flow is not used - if code != "" { - if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { - log.Debug("SetState failed: ", err) - return res, err - } - } - - expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() - if expiresIn <= 0 { - expiresIn = 1 - } - - res = &model.AuthResponse{ - Message: `Signed up successfully.`, - AccessToken: &authToken.AccessToken.Token, - ExpiresIn: &expiresIn, - User: userToReturn, - } - - sessionKey := constants.AuthRecipeMethodBasicAuth + ":" + user.ID - cookie.SetSession(gc, 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, authToken.AccessToken.ExpiresAt) - - if authToken.RefreshToken != nil { - res.RefreshToken = &authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) - } - - go func() { - utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) - if isEmailSignup { - utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user) - } else { - utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user) - } - - db.Provider.AddSession(ctx, &models.Session{ - UserID: user.ID, - UserAgent: utils.GetUserAgent(gc.Request), - IP: utils.GetIP(gc.Request), - }) - }() - - return res, nil -} diff --git a/server/resolvers/update_env.go b/server/resolvers/update_env.go deleted file mode 100644 index 62bd33eea..000000000 --- a/server/resolvers/update_env.go +++ /dev/null @@ -1,436 +0,0 @@ -package resolvers - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "reflect" - "strings" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/oauth" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// check if login methods have been disabled -// remove the session tokens for those methods -func clearSessionIfRequired(currentData, updatedData map[string]interface{}) { - isCurrentBasicAuthEnabled := !currentData[constants.EnvKeyDisableBasicAuthentication].(bool) - isCurrentMobileBasicAuthEnabled := !currentData[constants.EnvKeyDisableMobileBasicAuthentication].(bool) - isCurrentMagicLinkLoginEnabled := !currentData[constants.EnvKeyDisableMagicLinkLogin].(bool) - isCurrentAppleLoginEnabled := currentData[constants.EnvKeyAppleClientID] != nil && currentData[constants.EnvKeyAppleClientSecret] != nil && currentData[constants.EnvKeyAppleClientID].(string) != "" && currentData[constants.EnvKeyAppleClientSecret].(string) != "" - isCurrentFacebookLoginEnabled := currentData[constants.EnvKeyFacebookClientID] != nil && currentData[constants.EnvKeyFacebookClientSecret] != nil && currentData[constants.EnvKeyFacebookClientID].(string) != "" && currentData[constants.EnvKeyFacebookClientSecret].(string) != "" - isCurrentGoogleLoginEnabled := currentData[constants.EnvKeyGoogleClientID] != nil && currentData[constants.EnvKeyGoogleClientSecret] != nil && currentData[constants.EnvKeyGoogleClientID].(string) != "" && currentData[constants.EnvKeyGoogleClientSecret].(string) != "" - isCurrentGithubLoginEnabled := currentData[constants.EnvKeyGithubClientID] != nil && currentData[constants.EnvKeyGithubClientSecret] != nil && currentData[constants.EnvKeyGithubClientID].(string) != "" && currentData[constants.EnvKeyGithubClientSecret].(string) != "" - isCurrentLinkedInLoginEnabled := currentData[constants.EnvKeyLinkedInClientID] != nil && currentData[constants.EnvKeyLinkedInClientSecret] != nil && currentData[constants.EnvKeyLinkedInClientID].(string) != "" && currentData[constants.EnvKeyLinkedInClientSecret].(string) != "" - isCurrentTwitterLoginEnabled := currentData[constants.EnvKeyTwitterClientID] != nil && currentData[constants.EnvKeyTwitterClientSecret] != nil && currentData[constants.EnvKeyTwitterClientID].(string) != "" && currentData[constants.EnvKeyTwitterClientSecret].(string) != "" - isCurrentMicrosoftLoginEnabled := currentData[constants.EnvKeyMicrosoftClientID] != nil && currentData[constants.EnvKeyMicrosoftClientSecret] != nil && currentData[constants.EnvKeyMicrosoftClientID].(string) != "" && currentData[constants.EnvKeyMicrosoftClientSecret].(string) != "" - isCurrentTwitchLoginEnabled := currentData[constants.EnvKeyTwitchClientID] != nil && currentData[constants.EnvKeyTwitchClientSecret] != nil && currentData[constants.EnvKeyTwitchClientID].(string) != "" && currentData[constants.EnvKeyTwitchClientSecret].(string) != "" - - isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool) - isUpdatedMobileBasicAuthEnabled := !updatedData[constants.EnvKeyDisableMobileBasicAuthentication].(bool) - isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool) - isUpdatedAppleLoginEnabled := updatedData[constants.EnvKeyAppleClientID] != nil && updatedData[constants.EnvKeyAppleClientSecret] != nil && updatedData[constants.EnvKeyAppleClientID].(string) != "" && updatedData[constants.EnvKeyAppleClientSecret].(string) != "" - isUpdatedFacebookLoginEnabled := updatedData[constants.EnvKeyFacebookClientID] != nil && updatedData[constants.EnvKeyFacebookClientSecret] != nil && updatedData[constants.EnvKeyFacebookClientID].(string) != "" && updatedData[constants.EnvKeyFacebookClientSecret].(string) != "" - isUpdatedGoogleLoginEnabled := updatedData[constants.EnvKeyGoogleClientID] != nil && updatedData[constants.EnvKeyGoogleClientSecret] != nil && updatedData[constants.EnvKeyGoogleClientID].(string) != "" && updatedData[constants.EnvKeyGoogleClientSecret].(string) != "" - isUpdatedGithubLoginEnabled := updatedData[constants.EnvKeyGithubClientID] != nil && updatedData[constants.EnvKeyGithubClientSecret] != nil && updatedData[constants.EnvKeyGithubClientID].(string) != "" && updatedData[constants.EnvKeyGithubClientSecret].(string) != "" - isUpdatedLinkedInLoginEnabled := updatedData[constants.EnvKeyLinkedInClientID] != nil && updatedData[constants.EnvKeyLinkedInClientSecret] != nil && updatedData[constants.EnvKeyLinkedInClientID].(string) != "" && updatedData[constants.EnvKeyLinkedInClientSecret].(string) != "" - isUpdatedTwitterLoginEnabled := updatedData[constants.EnvKeyTwitterClientID] != nil && updatedData[constants.EnvKeyTwitterClientSecret] != nil && updatedData[constants.EnvKeyTwitterClientID].(string) != "" && updatedData[constants.EnvKeyTwitterClientSecret].(string) != "" - isUpdatedMicrosoftLoginEnabled := updatedData[constants.EnvKeyMicrosoftClientID] != nil && updatedData[constants.EnvKeyMicrosoftClientSecret] != nil && updatedData[constants.EnvKeyMicrosoftClientID].(string) != "" && updatedData[constants.EnvKeyMicrosoftClientSecret].(string) != "" - isUpdatedTwitchLoginEnabled := updatedData[constants.EnvKeyTwitchClientID] != nil && updatedData[constants.EnvKeyTwitchClientSecret] != nil && updatedData[constants.EnvKeyTwitchClientID].(string) != "" && updatedData[constants.EnvKeyTwitchClientSecret].(string) != "" - - if isCurrentBasicAuthEnabled && !isUpdatedBasicAuthEnabled { - memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth) - } - - if isCurrentMobileBasicAuthEnabled && !isUpdatedMobileBasicAuthEnabled { - memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMobileBasicAuth) - } - - if isCurrentMagicLinkLoginEnabled && !isUpdatedMagicLinkLoginEnabled { - memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMagicLinkLogin) - } - - if isCurrentAppleLoginEnabled && !isUpdatedAppleLoginEnabled { - memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodApple) - } - - if isCurrentFacebookLoginEnabled && !isUpdatedFacebookLoginEnabled { - memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodFacebook) - } - - if isCurrentGoogleLoginEnabled && !isUpdatedGoogleLoginEnabled { - memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodGoogle) - } - - if isCurrentGithubLoginEnabled && !isUpdatedGithubLoginEnabled { - memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodGithub) - } - - if isCurrentLinkedInLoginEnabled && !isUpdatedLinkedInLoginEnabled { - memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodLinkedIn) - } - - if isCurrentTwitterLoginEnabled && !isUpdatedTwitterLoginEnabled { - memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodTwitter) - } - - if isCurrentMicrosoftLoginEnabled && !isUpdatedMicrosoftLoginEnabled { - memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMicrosoft) - } - - if isCurrentTwitchLoginEnabled && !isUpdatedTwitchLoginEnabled { - memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodTwitch) - } -} - -// updateRoles will update DB for user roles, if a role is deleted by admin -// then this function will those roles from user roles if exists -func updateRoles(ctx context.Context, deletedRoles []string) error { - data, err := db.Provider.ListUsers(ctx, &model.Pagination{ - Limit: 1, - Offset: 1, - }) - if err != nil { - return err - } - - allData, err := db.Provider.ListUsers(ctx, &model.Pagination{ - Limit: data.Pagination.Total, - }) - if err != nil { - return err - } - - chunkSize := 1000 - totalUsers := len(allData.Users) - - for start := 0; start < totalUsers; start += chunkSize { - end := start + chunkSize - if end > totalUsers { - end = totalUsers - } - - chunkUsers := allData.Users[start:end] - - for i := range chunkUsers { - roles := utils.DeleteFromArray(chunkUsers[i].Roles, deletedRoles) - if len(chunkUsers[i].Roles) != len(roles) { - updatedValues := map[string]interface{}{ - "roles": strings.Join(roles, ","), - "updated_at": time.Now().Unix(), - } - id := []string{chunkUsers[i].ID} - err = db.Provider.UpdateUsers(ctx, updatedValues, id) - if err != nil { - return err - } - } - } - } - return nil -} - -// UpdateEnvResolver is a resolver for update config mutation -// This is admin only mutation -func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model.Response, error) { - var res *model.Response - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return res, fmt.Errorf("unauthorized") - } - - currentData, err := memorystore.Provider.GetEnvStore() - if err != nil { - log.Debug("Failed to get env store: ", err) - return res, err - } - - // clone currentData in new var - // that will be updated based on the req - updatedData := make(map[string]interface{}) - for key, val := range currentData { - updatedData[key] = val - } - - isJWTUpdated := false - algo := updatedData[constants.EnvKeyJwtType].(string) - if params.JwtType != nil { - algo = *params.JwtType - if !crypto.IsHMACA(algo) && !crypto.IsECDSA(algo) && !crypto.IsRSA(algo) { - log.Debug("Invalid JWT type: ", algo) - return res, fmt.Errorf("invalid jwt type") - } - - updatedData[constants.EnvKeyJwtType] = algo - isJWTUpdated = true - } - - if params.JwtSecret != nil || params.JwtPublicKey != nil || params.JwtPrivateKey != nil { - isJWTUpdated = true - } - - if isJWTUpdated { - // use to reset when type is changed from rsa, edsa -> hmac or vice a versa - defaultSecret := "" - defaultPublicKey := "" - defaultPrivateKey := "" - // check if jwt secret is provided - if crypto.IsHMACA(algo) { - if params.JwtSecret == nil { - log.Debug("JWT secret is required for HMAC") - return res, fmt.Errorf("jwt secret is required for HMAC algorithm") - } - - // reset public key and private key - params.JwtPrivateKey = &defaultPrivateKey - params.JwtPublicKey = &defaultPublicKey - } - - if crypto.IsRSA(algo) { - if params.JwtPrivateKey == nil || params.JwtPublicKey == nil { - log.Debug("JWT private key and public key are required for RSA: ", *params.JwtPrivateKey, *params.JwtPublicKey) - return res, fmt.Errorf("jwt private and public key is required for RSA (PKCS1) / ECDSA algorithm") - } - - // reset the jwt secret - params.JwtSecret = &defaultSecret - _, err = crypto.ParseRsaPrivateKeyFromPemStr(*params.JwtPrivateKey) - if err != nil { - log.Debug("Invalid JWT private key: ", err) - return res, err - } - - _, err := crypto.ParseRsaPublicKeyFromPemStr(*params.JwtPublicKey) - if err != nil { - log.Debug("Invalid JWT public key: ", err) - return res, err - } - } - - if crypto.IsECDSA(algo) { - if params.JwtPrivateKey == nil || params.JwtPublicKey == nil { - log.Debug("JWT private key and public key are required for ECDSA: ", *params.JwtPrivateKey, *params.JwtPublicKey) - return res, fmt.Errorf("jwt private and public key is required for RSA (PKCS1) / ECDSA algorithm") - } - - // reset the jwt secret - params.JwtSecret = &defaultSecret - _, err = crypto.ParseEcdsaPrivateKeyFromPemStr(*params.JwtPrivateKey) - if err != nil { - log.Debug("Invalid JWT private key: ", err) - return res, err - } - - _, err := crypto.ParseEcdsaPublicKeyFromPemStr(*params.JwtPublicKey) - if err != nil { - log.Debug("Invalid JWT public key: ", err) - return res, err - } - } - - } - - var data map[string]interface{} - byteData, err := json.Marshal(params) - if err != nil { - log.Debug("Failed to marshal update env input: ", err) - return res, fmt.Errorf("error marshalling params: %t", err) - } - - err = json.Unmarshal(byteData, &data) - if err != nil { - log.Debug("Failed to unmarshal update env input: ", err) - return res, fmt.Errorf("error un-marshalling params: %t", err) - } - - // in case of admin secret change update the cookie with new hash - if params.AdminSecret != nil { - if params.OldAdminSecret == nil { - log.Debug("Old admin secret is required for admin secret update") - return res, errors.New("admin secret and old admin secret are required for secret change") - } - oldAdminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - if err != nil { - log.Debug("Failed to get old admin secret: ", err) - return res, err - } - if *params.OldAdminSecret != oldAdminSecret { - log.Debug("Old admin secret is invalid") - return res, errors.New("old admin secret is not correct") - } - - if len(*params.AdminSecret) < 6 { - log.Debug("Admin secret is too short") - err = fmt.Errorf("admin secret must be at least 6 characters") - return res, err - } - - } - - for key, value := range data { - if value != nil { - fieldType := reflect.TypeOf(value).String() - - if fieldType == "string" { - updatedData[key] = value.(string) - } - - if fieldType == "bool" { - updatedData[key] = value.(bool) - } - if fieldType == "[]interface {}" { - stringArr := utils.ConvertInterfaceToStringSlice(value) - updatedData[key] = strings.Join(stringArr, ",") - } - } - } - - // handle derivative cases like disabling email verification & magic login - // in case SMTP is off but env is set to true - if updatedData[constants.EnvKeySmtpHost] == "" || updatedData[constants.EnvKeySmtpUsername] == "" || updatedData[constants.EnvKeySmtpPassword] == "" || updatedData[constants.EnvKeySenderEmail] == "" && updatedData[constants.EnvKeySmtpPort] == "" { - updatedData[constants.EnvKeyIsEmailServiceEnabled] = false - if !updatedData[constants.EnvKeyDisableEmailVerification].(bool) { - updatedData[constants.EnvKeyDisableEmailVerification] = true - } - if !updatedData[constants.EnvKeyDisableMailOTPLogin].(bool) { - updatedData[constants.EnvKeyDisableMailOTPLogin] = true - } - if !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool) { - updatedData[constants.EnvKeyDisableMailOTPLogin] = true - } - } - - if updatedData[constants.EnvKeySmtpHost] != "" || updatedData[constants.EnvKeySmtpUsername] != "" || updatedData[constants.EnvKeySmtpPassword] != "" || updatedData[constants.EnvKeySenderEmail] != "" && updatedData[constants.EnvKeySmtpPort] != "" { - updatedData[constants.EnvKeyIsEmailServiceEnabled] = true - } - - if updatedData[constants.EnvKeyTwilioAPIKey] == "" || updatedData[constants.EnvKeyTwilioAPISecret] == "" || updatedData[constants.EnvKeyTwilioAccountSID] == "" || updatedData[constants.EnvKeyTwilioSender] == "" { - updatedData[constants.EnvKeyIsSMSServiceEnabled] = false - if !updatedData[constants.EnvKeyIsSMSServiceEnabled].(bool) { - updatedData[constants.EnvKeyDisablePhoneVerification] = true - } - } - - if updatedData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) && updatedData[constants.EnvKeyIsEmailServiceEnabled].(bool) { - updatedData[constants.EnvKeyDisableMailOTPLogin] = true - } - - if !currentData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && updatedData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && !updatedData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) { - go db.Provider.UpdateUsers(ctx, map[string]interface{}{ - "is_multi_factor_auth_enabled": true, - }, nil) - } - - previousRoles := strings.Split(currentData[constants.EnvKeyRoles].(string), ",") - previousProtectedRoles := strings.Split(currentData[constants.EnvKeyProtectedRoles].(string), ",") - updatedRoles := strings.Split(updatedData[constants.EnvKeyRoles].(string), ",") - updatedDefaultRoles := strings.Split(updatedData[constants.EnvKeyDefaultRoles].(string), ",") - updatedProtectedRoles := strings.Split(updatedData[constants.EnvKeyProtectedRoles].(string), ",") - // check the roles change - if len(updatedRoles) > 0 && len(updatedDefaultRoles) > 0 { - // should be subset of roles - for _, role := range updatedDefaultRoles { - if !utils.StringSliceContains(updatedRoles, role) { - log.Debug("Default roles should be subset of roles") - return res, fmt.Errorf("default role %s is not in roles", role) - } - } - } - - if len(updatedProtectedRoles) > 0 { - for _, role := range updatedProtectedRoles { - if utils.StringSliceContains(updatedRoles, role) || utils.StringSliceContains(updatedDefaultRoles, role) { - log.Debug("Protected roles should not be in roles or default roles") - return res, fmt.Errorf("protected role %s found roles or default roles", role) - } - } - } - - deletedRoles := utils.FindDeletedValues(previousRoles, updatedRoles) - if len(deletedRoles) > 0 { - go updateRoles(ctx, deletedRoles) - } - - deletedProtectedRoles := utils.FindDeletedValues(previousProtectedRoles, updatedProtectedRoles) - if len(deletedProtectedRoles) > 0 { - go updateRoles(ctx, deletedProtectedRoles) - } - - // Update local store - memorystore.Provider.UpdateEnvStore(updatedData) - jwk, err := crypto.GenerateJWKBasedOnEnv() - if err != nil { - log.Debug("Failed to generate JWK: ", err) - return res, err - } - // updating jwk - err = memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJWK, jwk) - if err != nil { - log.Debug("Failed to update JWK: ", err) - return res, err - } - - err = oauth.InitOAuth() - if err != nil { - return res, err - } - - // Fetch the current db store and update it - env, err := db.Provider.GetEnv(ctx) - if err != nil { - log.Debug("Failed to get env: ", err) - return res, err - } - - if params.AdminSecret != nil { - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - if err != nil { - log.Debug("Failed to get admin secret: ", err) - return res, err - } - hashedKey, err := crypto.EncryptPassword(adminSecret) - if err != nil { - log.Debug("Failed to encrypt admin secret: ", err) - return res, err - } - cookie.SetAdminCookie(gc, hashedKey) - } - - encryptedConfig, err := crypto.EncryptEnvData(updatedData) - if err != nil { - log.Debug("Failed to encrypt env data: ", err) - return res, err - } - - env.EnvData = encryptedConfig - _, err = db.Provider.UpdateEnv(ctx, env) - if err != nil { - log.Debug("Failed to update env: ", err) - return res, err - } - - go clearSessionIfRequired(currentData, updatedData) - - res = &model.Response{ - Message: "configurations updated successfully", - } - return res, nil -} diff --git a/server/resolvers/update_user.go b/server/resolvers/update_user.go deleted file mode 100644 index 006c9e994..000000000 --- a/server/resolvers/update_user.go +++ /dev/null @@ -1,297 +0,0 @@ -package resolvers - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "strings" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/email" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/authorizerdev/authorizer/server/validators" -) - -// UpdateUserResolver is a resolver for update user mutation -// This is admin only mutation -func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*model.User, error) { - var res *model.User - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return res, fmt.Errorf("unauthorized") - } - - if params.ID == "" { - log.Debug("UserID is empty") - return res, fmt.Errorf("User ID is required") - } - - log := log.WithFields(log.Fields{ - "user_id": params.ID, - }) - - if params.GivenName == nil && - params.FamilyName == nil && - params.Picture == nil && - params.MiddleName == nil && - params.Nickname == nil && - params.Email == nil && - params.Birthdate == nil && - params.Gender == nil && - params.PhoneNumber == nil && - params.Roles == nil && - params.IsMultiFactorAuthEnabled == nil && - params.AppData == nil { - log.Debug("No params to update") - return res, fmt.Errorf("please enter atleast one param to update") - } - - user, err := db.Provider.GetUserByID(ctx, params.ID) - if err != nil { - log.Debug("Failed to get user by id: ", err) - return res, fmt.Errorf(`User not found`) - } - - if params.GivenName != nil && refs.StringValue(user.GivenName) != refs.StringValue(params.GivenName) { - user.GivenName = params.GivenName - } - - if params.FamilyName != nil && refs.StringValue(user.FamilyName) != refs.StringValue(params.FamilyName) { - user.FamilyName = params.FamilyName - } - - if params.MiddleName != nil && refs.StringValue(user.MiddleName) != refs.StringValue(params.MiddleName) { - user.MiddleName = params.MiddleName - } - - if params.Nickname != nil && refs.StringValue(user.Nickname) != refs.StringValue(params.Nickname) { - user.Nickname = params.Nickname - } - - if params.Birthdate != nil && refs.StringValue(user.Birthdate) != refs.StringValue(params.Birthdate) { - user.Birthdate = params.Birthdate - } - - if params.Gender != nil && refs.StringValue(user.Gender) != refs.StringValue(params.Gender) { - user.Gender = params.Gender - } - - if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) { - // verify if phone number is unique - if _, err := db.Provider.GetUserByPhoneNumber(ctx, strings.TrimSpace(refs.StringValue(params.PhoneNumber))); err == nil { - log.Debug("user with given phone number already exists") - return nil, errors.New("user with given phone number already exists") - } - user.PhoneNumber = params.PhoneNumber - } - - if params.Picture != nil && refs.StringValue(user.Picture) != refs.StringValue(params.Picture) { - user.Picture = params.Picture - } - - if params.AppData != nil { - appDataString := "" - appDataBytes, err := json.Marshal(params.AppData) - if err != nil { - log.Debug("failed to marshall source app_data: ", err) - return nil, errors.New("malformed app_data") - } - appDataString = string(appDataBytes) - user.AppData = &appDataString - } - - if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) { - user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled - if refs.BoolValue(params.IsMultiFactorAuthEnabled) { - // Check if totp, email or sms is enabled - isMailOTPEnvServiceDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMailOTPLogin) - if err != nil { - log.Debug("Error getting mail otp disabled: ", err) - isMailOTPEnvServiceDisabled = false - } - isTOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin) - if err != nil { - log.Debug("Error getting totp disabled: ", err) - isTOTPEnvServiceDisabled = false - } - isSMSOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) - if err != nil { - log.Debug("Error getting sms otp disabled: ", err) - isSMSOTPEnvServiceDisabled = false - } - // Initialize a flag to check if enabling Mail OTP is required - if isMailOTPEnvServiceDisabled && isTOTPEnvServiceDisabled && isSMSOTPEnvServiceDisabled { - log.Debug("Cannot enable mfa service as all mfa services are disabled") - return nil, errors.New("cannot enable multi factor authentication as all mfa services are disabled") - } - } - } - - if params.EmailVerified != nil { - if *params.EmailVerified { - now := time.Now().Unix() - user.EmailVerifiedAt = &now - } else { - user.EmailVerifiedAt = nil - } - } - if params.PhoneNumberVerified != nil { - if *params.PhoneNumberVerified { - now := time.Now().Unix() - user.PhoneNumberVerifiedAt = &now - } else { - user.PhoneNumberVerifiedAt = nil - } - - } - - if params.Email != nil && refs.StringValue(user.Email) != refs.StringValue(params.Email) { - // check if valid email - if !validators.IsValidEmail(*params.Email) { - log.Debug("Invalid email: ", *params.Email) - return res, fmt.Errorf("invalid email address") - } - newEmail := strings.ToLower(*params.Email) - // check if user with new email exists - _, err = db.Provider.GetUserByEmail(ctx, newEmail) - // err = nil means user exists - if err == nil { - log.Debug("User with email already exists: ", newEmail) - return res, fmt.Errorf("user with this email address already exists") - } - - go memorystore.Provider.DeleteAllUserSessions(user.ID) - - hostname := parsers.GetHost(gc) - user.Email = &newEmail - user.EmailVerifiedAt = nil - // insert verification request - _, nonceHash, err := utils.GenerateNonce() - if err != nil { - log.Debug("Failed to generate nonce: ", err) - return res, err - } - verificationType := constants.VerificationTypeUpdateEmail - redirectURL := parsers.GetAppURL(gc) - verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname, nonceHash, redirectURL) - if err != nil { - log.Debug("Failed to create verification token: ", err) - } - _, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{ - Token: verificationToken, - Identifier: verificationType, - ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), - Email: newEmail, - Nonce: nonceHash, - RedirectURI: redirectURL, - }) - if err != nil { - log.Debug("Failed to add verification request: ", err) - return res, err - } - - // exec it as go routine so that we can reduce the api latency - go email.SendEmail([]string{refs.StringValue(user.Email)}, constants.VerificationTypeBasicAuthSignup, map[string]interface{}{ - "user": user.ToMap(), - "organization": utils.GetOrganization(), - "verification_url": utils.GetEmailVerificationURL(verificationToken, hostname, redirectURL), - }) - - } - - if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) { - phone := strings.TrimSpace(refs.StringValue(params.PhoneNumber)) - if len(phone) < 10 || len(phone) > 15 { - log.Debug("Invalid phone number: ", *params.PhoneNumber) - return res, fmt.Errorf("invalid phone number") - } - // check if user with new phone number exists - _, err = db.Provider.GetUserByPhoneNumber(ctx, phone) - // err = nil means user exists - if err == nil { - log.Debug("User with phone number already exists: ", phone) - return res, fmt.Errorf("user with this phone number already exists") - } - go memorystore.Provider.DeleteAllUserSessions(user.ID) - user.PhoneNumber = &phone - user.PhoneNumberVerifiedAt = nil - } - - rolesToSave := "" - if params.Roles != nil && len(params.Roles) > 0 { - currentRoles := strings.Split(user.Roles, ",") - inputRoles := []string{} - for _, item := range params.Roles { - inputRoles = append(inputRoles, *item) - } - - rolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRoles) - roles := []string{} - if err != nil { - log.Debug("Error getting roles: ", err) - rolesString = "" - } else { - roles = strings.Split(rolesString, ",") - } - protectedRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyProtectedRoles) - protectedRoles := []string{} - if err != nil { - log.Debug("Error getting protected roles: ", err) - protectedRolesString = "" - } else { - protectedRoles = strings.Split(protectedRolesString, ",") - } - - if !validators.IsValidRoles(inputRoles, append([]string{}, append(roles, protectedRoles...)...)) { - log.Debug("Invalid roles: ", params.Roles) - return res, fmt.Errorf("invalid list of roles") - } - - if !validators.IsStringArrayEqual(inputRoles, currentRoles) { - rolesToSave = strings.Join(inputRoles, ",") - } - - go memorystore.Provider.DeleteAllUserSessions(user.ID) - } - - if rolesToSave != "" { - user.Roles = rolesToSave - } - user, err = db.Provider.UpdateUser(ctx, user) - if err != nil { - log.Debug("Failed to update user: ", err) - return res, err - } - - createdAt := user.CreatedAt - updatedAt := user.UpdatedAt - res = &model.User{ - ID: params.ID, - Email: user.Email, - Picture: user.Picture, - GivenName: user.GivenName, - FamilyName: user.FamilyName, - Roles: strings.Split(user.Roles, ","), - CreatedAt: &createdAt, - UpdatedAt: &updatedAt, - } - return res, nil -} diff --git a/server/resolvers/user.go b/server/resolvers/user.go deleted file mode 100644 index 994348cef..000000000 --- a/server/resolvers/user.go +++ /dev/null @@ -1,48 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// UserResolver is a resolver for user query -// This is admin only query -func UserResolver(ctx context.Context, params model.GetUserRequest) (*model.User, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin.") - return nil, fmt.Errorf("unauthorized") - } - // Try getting user by ID - if params.ID != nil && strings.Trim(*params.ID, " ") != "" { - res, err := db.Provider.GetUserByID(ctx, *params.ID) - if err != nil { - log.Debug("Failed to get users by ID: ", err) - return nil, err - } - return res.AsAPIUser(), nil - } - // Try getting user by email - if params.Email != nil && strings.Trim(*params.Email, " ") != "" { - res, err := db.Provider.GetUserByEmail(ctx, *params.Email) - if err != nil { - log.Debug("Failed to get users by email: ", err) - return nil, err - } - return res.AsAPIUser(), nil - } - // Return error if no params are provided - return nil, fmt.Errorf("invalid params, user id or email is required") -} diff --git a/server/resolvers/users.go b/server/resolvers/users.go deleted file mode 100644 index 1ee6aadc8..000000000 --- a/server/resolvers/users.go +++ /dev/null @@ -1,38 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// UsersResolver is a resolver for users query -// This is admin only query -func UsersResolver(ctx context.Context, params *model.PaginatedInput) (*model.Users, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin.") - return nil, fmt.Errorf("unauthorized") - } - - pagination := utils.GetPagination(params) - - res, err := db.Provider.ListUsers(ctx, pagination) - if err != nil { - log.Debug("Failed to get users: ", err) - return nil, err - } - - return res, nil -} diff --git a/server/resolvers/verification_requests.go b/server/resolvers/verification_requests.go deleted file mode 100644 index 9a55be7d1..000000000 --- a/server/resolvers/verification_requests.go +++ /dev/null @@ -1,37 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// VerificationRequestsResolver is a resolver for verification requests query -// This is admin only query -func VerificationRequestsResolver(ctx context.Context, params *model.PaginatedInput) (*model.VerificationRequests, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return nil, fmt.Errorf("unauthorized") - } - - pagination := utils.GetPagination(params) - res, err := db.Provider.ListVerificationRequests(ctx, pagination) - if err != nil { - log.Debug("Failed to get verification requests: ", err) - return nil, err - } - - return res, nil -} diff --git a/server/resolvers/verify_email.go b/server/resolvers/verify_email.go deleted file mode 100644 index 3ad399ebc..000000000 --- a/server/resolvers/verify_email.go +++ /dev/null @@ -1,224 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/authenticators" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// VerifyEmailResolver is a resolver for verify email mutation -func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error) { - var res *model.AuthResponse - - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - verificationRequest, err := db.Provider.GetVerificationRequestByToken(ctx, params.Token) - if err != nil { - log.Debug("Failed to get verification request by token: ", err) - return res, fmt.Errorf(`invalid token: %s`, err.Error()) - } - - // verify if token exists in db - hostname := parsers.GetHost(gc) - claim, err := token.ParseJWTToken(params.Token) - if err != nil { - log.Debug("Failed to parse token: ", err) - return res, fmt.Errorf(`invalid token: %s`, err.Error()) - } - - if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil { - log.Debug("Failed to validate jwt claims: ", err) - return res, fmt.Errorf(`invalid token: %s`, err.Error()) - } - - email := claim["sub"].(string) - log := log.WithFields(log.Fields{ - "email": email, - }) - user, err := db.Provider.GetUserByEmail(ctx, email) - if err != nil { - log.Debug("Failed to get user by email: ", err) - return res, err - } - - isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication) - if err != nil || !isMFADisabled { - log.Debug("MFA service not enabled: ", err) - } - - isTOTPLoginDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin) - if err != nil || !isTOTPLoginDisabled { - log.Debug("totp service not enabled: ", err) - } - - setOTPMFaSession := func(expiresAt int64) error { - mfaSession := uuid.NewString() - err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt) - if err != nil { - log.Debug("Failed to add mfasession: ", err) - return err - } - cookie.SetMfaSession(gc, mfaSession) - return nil - } - - // If mfa enabled and also totp enabled - if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isTOTPLoginDisabled { - expiresAt := time.Now().Add(3 * time.Minute).Unix() - if err := setOTPMFaSession(expiresAt); err != nil { - log.Debug("Failed to set mfa session: ", err) - return nil, err - } - authenticator, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, user.ID, constants.EnvKeyTOTPAuthenticator) - if err != nil || authenticator == nil || authenticator.VerifiedAt == nil { - // generate totp - // Generate a base64 URL and initiate the registration for TOTP - authConfig, err := authenticators.Provider.Generate(ctx, user.ID) - if err != nil { - log.Debug("error while generating base64 url: ", err) - return nil, err - } - recoveryCodes := []*string{} - for _, code := range authConfig.RecoveryCodes { - recoveryCodes = append(recoveryCodes, refs.NewStringRef(code)) - } - // when user is first time registering for totp - res = &model.AuthResponse{ - Message: `Proceed to totp verification screen`, - ShouldShowTotpScreen: refs.NewBoolRef(true), - AuthenticatorScannerImage: refs.NewStringRef(authConfig.ScannerImage), - AuthenticatorSecret: refs.NewStringRef(authConfig.Secret), - AuthenticatorRecoveryCodes: recoveryCodes, - } - return res, nil - } else { - //when user is already register for totp - res = &model.AuthResponse{ - Message: `Proceed to totp screen`, - ShouldShowTotpScreen: refs.NewBoolRef(true), - } - return res, nil - } - } - - isSignUp := false - if user.EmailVerifiedAt == nil { - isSignUp = true - // update email_verified_at in users table - now := time.Now().Unix() - user.EmailVerifiedAt = &now - user, err = db.Provider.UpdateUser(ctx, user) - if err != nil { - log.Debug("Failed to update user: ", err) - return res, err - } - } - // delete from verification table - err = db.Provider.DeleteVerificationRequest(gc, verificationRequest) - if err != nil { - log.Debug("Failed to delete verification request: ", err) - return res, err - } - - loginMethod := constants.AuthRecipeMethodBasicAuth - if loginMethod == constants.VerificationTypeMagicLinkLogin { - loginMethod = constants.AuthRecipeMethodMagicLinkLogin - } - - roles := strings.Split(user.Roles, ",") - scope := []string{"openid", "email", "profile"} - code := "" - // Not required as /oauth/token cannot be resumed from other tab - // codeChallenge := "" - nonce := "" - if params.State != nil { - // Get state from store - authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State)) - if authorizeState != "" { - authorizeStateSplit := strings.Split(authorizeState, "@@") - if len(authorizeStateSplit) > 1 { - code = authorizeStateSplit[0] - // Not required as /oauth/token cannot be resumed from other tab - // codeChallenge = authorizeStateSplit[1] - } else { - nonce = authorizeState - } - go memorystore.Provider.RemoveState(refs.StringValue(params.State)) - } - } - if nonce == "" { - nonce = uuid.New().String() - } - authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod, nonce, code) - if err != nil { - log.Debug("Failed to create auth token: ", err) - return res, err - } - - // Code challenge could be optional if PKCE flow is not used - // Not required as /oauth/token cannot be resumed from other tab - // if code != "" { - // if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { - // log.Debug("SetState failed: ", err) - // return res, err - // } - // } - go func() { - if isSignUp { - utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user) - // User is also logged in with signup - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) - } else { - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) - } - - db.Provider.AddSession(ctx, &models.Session{ - UserID: user.ID, - UserAgent: utils.GetUserAgent(gc.Request), - IP: utils.GetIP(gc.Request), - }) - }() - expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() - if expiresIn <= 0 { - expiresIn = 1 - } - - res = &model.AuthResponse{ - Message: `Email verified successfully.`, - AccessToken: &authToken.AccessToken.Token, - IDToken: &authToken.IDToken.Token, - ExpiresIn: &expiresIn, - User: user.AsAPIUser(), - } - - sessionKey := loginMethod + ":" + user.ID - cookie.SetSession(gc, 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, authToken.AccessToken.ExpiresAt) - - if authToken.RefreshToken != nil { - res.RefreshToken = &authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) - } - return res, nil -} diff --git a/server/resolvers/verify_otp.go b/server/resolvers/verify_otp.go deleted file mode 100644 index 16a10c707..000000000 --- a/server/resolvers/verify_otp.go +++ /dev/null @@ -1,214 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/google/uuid" - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/authenticators" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" -) - -// VerifyOtpResolver resolver for verify otp mutation -func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error) { - var res *model.AuthResponse - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return res, err - } - - mfaSession, err := cookie.GetMfaSession(gc) - if err != nil { - log.Debug("Failed to get otp request by email: ", err) - return res, fmt.Errorf(`invalid session: %s`, err.Error()) - } - - email := strings.TrimSpace(refs.StringValue(params.Email)) - phoneNumber := strings.TrimSpace(refs.StringValue(params.PhoneNumber)) - if email == "" && phoneNumber == "" { - log.Debug("Email or phone number is required") - return res, fmt.Errorf(`email or phone number is required`) - } - isEmailVerification := email != "" - isMobileVerification := phoneNumber != "" - // Get user by email or phone number - var user *models.User - if isEmailVerification { - user, err = db.Provider.GetUserByEmail(ctx, refs.StringValue(params.Email)) - if err != nil { - log.Debug("Failed to get user by email: ", err) - } - } else { - user, err = db.Provider.GetUserByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber)) - if err != nil { - log.Debug("Failed to get user by phone number: ", err) - } - } - if user == nil || err != nil { - return res, fmt.Errorf(`user not found`) - } - // Verify OTP based on TOPT or OTP - if refs.BoolValue(params.IsTotp) { - status, err := authenticators.Provider.Validate(ctx, params.Otp, user.ID) - if err != nil { - log.Debug("Failed to validate totp: ", err) - return nil, fmt.Errorf("error while validating passcode") - } - if !status { - log.Debug("Failed to verify otp request: Incorrect value") - log.Info("Checking if otp is recovery code") - // Check if otp is recovery code - isValidRecoveryCode, err := authenticators.Provider.ValidateRecoveryCode(ctx, params.Otp, user.ID) - if err != nil { - log.Debug("Failed to validate recovery code: ", err) - return nil, fmt.Errorf("error while validating recovery code") - } - if !isValidRecoveryCode { - log.Debug("Failed to verify otp request: Incorrect value") - return res, fmt.Errorf(`invalid otp`) - } - } - } else { - var otp *models.OTP - if isEmailVerification { - otp, err = db.Provider.GetOTPByEmail(ctx, refs.StringValue(params.Email)) - if err != nil { - log.Debug(`Failed to get otp request for email: `, err.Error()) - } - } else { - otp, err = db.Provider.GetOTPByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber)) - if err != nil { - log.Debug(`Failed to get otp request for phone number: `, err.Error()) - } - } - if otp == nil && err != nil { - return res, fmt.Errorf(`OTP not found`) - } - if params.Otp != otp.Otp { - log.Debug("Failed to verify otp request: Incorrect value") - return res, fmt.Errorf(`invalid otp`) - } - expiresIn := otp.ExpiresAt - time.Now().Unix() - if expiresIn < 0 { - log.Debug("Failed to verify otp request: Timeout") - return res, fmt.Errorf("otp expired") - } - db.Provider.DeleteOTP(gc, otp) - } - - if _, err := memorystore.Provider.GetMfaSession(user.ID, mfaSession); err != nil { - log.Debug("Failed to get mfa session: ", err) - return res, fmt.Errorf(`invalid session: %s`, err.Error()) - } - - isSignUp := false - if user.EmailVerifiedAt == nil && isEmailVerification { - isSignUp = true - now := time.Now().Unix() - user.EmailVerifiedAt = &now - } - if user.PhoneNumberVerifiedAt == nil && isMobileVerification { - isSignUp = true - now := time.Now().Unix() - user.PhoneNumberVerifiedAt = &now - } - if isSignUp { - user, err = db.Provider.UpdateUser(ctx, user) - if err != nil { - log.Debug("Failed to update user: ", err) - return res, err - } - } - loginMethod := constants.AuthRecipeMethodBasicAuth - if isMobileVerification { - loginMethod = constants.AuthRecipeMethodMobileOTP - } - roles := strings.Split(user.Roles, ",") - scope := []string{"openid", "email", "profile"} - code := "" - codeChallenge := "" - nonce := "" - if params.State != nil { - // Get state from store - authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State)) - if authorizeState != "" { - authorizeStateSplit := strings.Split(authorizeState, "@@") - if len(authorizeStateSplit) > 1 { - code = authorizeStateSplit[0] - codeChallenge = authorizeStateSplit[1] - } else { - nonce = authorizeState - } - go memorystore.Provider.RemoveState(refs.StringValue(params.State)) - } - } - if nonce == "" { - nonce = uuid.New().String() - } - authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod, nonce, code) - if err != nil { - log.Debug("Failed to create auth token: ", err) - return res, err - } - - // Code challenge could be optional if PKCE flow is not used - if code != "" { - if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil { - log.Debug("Failed to set code state: ", err) - return res, err - } - } - - go func() { - if isSignUp { - utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user) - // User is also logged in with signup - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) - } else { - utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user) - } - - db.Provider.AddSession(ctx, &models.Session{ - UserID: user.ID, - UserAgent: utils.GetUserAgent(gc.Request), - IP: utils.GetIP(gc.Request), - }) - }() - - authTokenExpiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() - if authTokenExpiresIn <= 0 { - authTokenExpiresIn = 1 - } - - res = &model.AuthResponse{ - Message: `OTP verified successfully.`, - AccessToken: &authToken.AccessToken.Token, - IDToken: &authToken.IDToken.Token, - ExpiresIn: &authTokenExpiresIn, - User: user.AsAPIUser(), - } - - sessionKey := loginMethod + ":" + user.ID - cookie.SetSession(gc, 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, authToken.AccessToken.ExpiresAt) - - if authToken.RefreshToken != nil { - res.RefreshToken = &authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) - } - return res, nil -} diff --git a/server/resolvers/webhook.go b/server/resolvers/webhook.go deleted file mode 100644 index d547e7983..000000000 --- a/server/resolvers/webhook.go +++ /dev/null @@ -1,33 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - log "github.com/sirupsen/logrus" -) - -// WebhookResolver resolver for getting webhook by identifier -func WebhookResolver(ctx context.Context, params model.WebhookRequest) (*model.Webhook, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return nil, fmt.Errorf("unauthorized") - } - - webhook, err := db.Provider.GetWebhookByID(ctx, params.ID) - if err != nil { - log.Debug("error getting webhook: ", err) - return nil, err - } - return webhook, nil -} diff --git a/server/resolvers/webhook_logs.go b/server/resolvers/webhook_logs.go deleted file mode 100644 index cd7b62d6b..000000000 --- a/server/resolvers/webhook_logs.go +++ /dev/null @@ -1,47 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - log "github.com/sirupsen/logrus" -) - -// WebhookLogsResolver resolver for getting the list of webhook_logs based on pagination & webhook identifier -func WebhookLogsResolver(ctx context.Context, params *model.ListWebhookLogRequest) (*model.WebhookLogs, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return nil, fmt.Errorf("unauthorized") - } - - var pagination *model.Pagination - var webhookID string - - if params != nil { - pagination = utils.GetPagination(&model.PaginatedInput{ - Pagination: params.Pagination, - }) - webhookID = refs.StringValue(params.WebhookID) - } else { - pagination = utils.GetPagination(nil) - webhookID = "" - } - // TODO fix - webhookLogs, err := db.Provider.ListWebhookLogs(ctx, pagination, webhookID) - if err != nil { - log.Debug("failed to get webhook logs: ", err) - return nil, err - } - return webhookLogs, nil -} diff --git a/server/resolvers/webhooks.go b/server/resolvers/webhooks.go deleted file mode 100644 index 733df821b..000000000 --- a/server/resolvers/webhooks.go +++ /dev/null @@ -1,34 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - log "github.com/sirupsen/logrus" -) - -// WebhooksResolver resolver for getting the list of webhooks based on pagination -func WebhooksResolver(ctx context.Context, params *model.PaginatedInput) (*model.Webhooks, error) { - gc, err := utils.GinContextFromContext(ctx) - if err != nil { - log.Debug("Failed to get GinContext: ", err) - return nil, err - } - - if !token.IsSuperAdmin(gc) { - log.Debug("Not logged in as super admin") - return nil, fmt.Errorf("unauthorized") - } - - pagination := utils.GetPagination(params) - webhooks, err := db.Provider.ListWebhook(ctx, pagination) - if err != nil { - log.Debug("failed to get webhooks: ", err) - return nil, err - } - return webhooks, nil -} diff --git a/server/routes/routes.go b/server/routes/routes.go deleted file mode 100644 index 0f25a0288..000000000 --- a/server/routes/routes.go +++ /dev/null @@ -1,58 +0,0 @@ -package routes - -import ( - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/handlers" - "github.com/authorizerdev/authorizer/server/middlewares" -) - -// InitRouter initializes gin router -func InitRouter(log *logrus.Logger) *gin.Engine { - gin.SetMode(gin.ReleaseMode) - router := gin.New() - - router.Use(middlewares.Logger(log), gin.Recovery()) - router.Use(middlewares.GinContextToContextMiddleware()) - router.Use(middlewares.CORSMiddleware()) - router.Use(middlewares.ClientCheckMiddleware()) - - router.GET("/", handlers.RootHandler()) - router.GET("/health", handlers.HealthHandler()) - router.POST("/graphql", handlers.GraphqlHandler()) - router.GET("/playground", handlers.PlaygroundHandler()) - router.GET("/oauth_login/:oauth_provider", handlers.OAuthLoginHandler()) - router.GET("/oauth_callback/:oauth_provider", handlers.OAuthCallbackHandler()) - router.POST("/oauth_callback/:oauth_provider", handlers.OAuthCallbackHandler()) - router.GET("/verify_email", handlers.VerifyEmailHandler()) - // OPEN ID routes - router.GET("/.well-known/openid-configuration", handlers.OpenIDConfigurationHandler()) - router.GET("/.well-known/jwks.json", handlers.JWKsHandler()) - router.GET("/authorize", handlers.AuthorizeHandler()) - router.GET("/userinfo", handlers.UserInfoHandler()) - router.GET("/logout", handlers.LogoutHandler()) - router.POST("/oauth/token", handlers.TokenHandler()) - router.POST("/oauth/revoke", handlers.RevokeRefreshTokenHandler()) - - router.LoadHTMLGlob("templates/*") - // login page app related routes. - app := router.Group("/app") - { - app.Static("/favicon_io", "app/favicon_io") - app.Static("/build", "app/build") - app.GET("/", handlers.AppHandler()) - app.GET("/:page", handlers.AppHandler()) - } - - // dashboard related routes - dashboard := router.Group("/dashboard") - { - dashboard.Static("/favicon_io", "dashboard/favicon_io") - dashboard.Static("/build", "dashboard/build") - dashboard.Static("/public", "dashboard/public") - dashboard.GET("/", handlers.DashboardHandler()) - dashboard.GET("/:page", handlers.DashboardHandler()) - } - return router -} diff --git a/server/smsproviders/twilio.go b/server/smsproviders/twilio.go deleted file mode 100644 index f4f1acb90..000000000 --- a/server/smsproviders/twilio.go +++ /dev/null @@ -1,49 +0,0 @@ -package smsproviders - -import ( - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - log "github.com/sirupsen/logrus" - twilio "github.com/twilio/twilio-go" - api "github.com/twilio/twilio-go/rest/api/v2010" -) - -// SendSMS util to send sms -// TODO: Should be restructured to interface when another provider is added -func SendSMS(sendTo, messageBody string) error { - twilioAPISecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwilioAPISecret) - if err != nil || twilioAPISecret == "" { - log.Debug("Failed to get api secret: ", err) - return err - } - twilioAPIKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwilioAPIKey) - if err != nil || twilioAPIKey == "" { - log.Debug("Failed to get api key: ", err) - return err - } - twilioSenderFrom, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwilioSender) - if err != nil || twilioSenderFrom == "" { - log.Debug("Failed to get sender: ", err) - return err - } - // accountSID is not a must to send sms on twilio - twilioAccountSID, _ := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwilioAccountSID) - client := twilio.NewRestClientWithParams(twilio.ClientParams{ - Username: twilioAPIKey, - Password: twilioAPISecret, - AccountSid: twilioAccountSID, - }) - message := &api.CreateMessageParams{} - message.SetBody(messageBody) - message.SetFrom(twilioSenderFrom) - message.SetTo(sendTo) - - _, err = client.Api.CreateMessage(message) - - if err != nil { - log.Debug("Failed to send sms: ", err) - return err - } - - return nil -} diff --git a/server/test/add_email_template_test.go b/server/test/add_email_template_test.go deleted file mode 100644 index 4af66090b..000000000 --- a/server/test/add_email_template_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func addEmailTemplateTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run("should add email templates", func(t *testing.T) { - req, ctx := createContext(s) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.NoError(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.NoError(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - t.Run("should not add email template for invalid event type", func(t *testing.T) { - emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{ - EventName: "test", - }) - assert.Error(t, err) - assert.Nil(t, emailTemplate) - }) - - t.Run("should not add email template for empty subject", func(t *testing.T) { - emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{ - EventName: s.TestInfo.TestEmailTemplateEventTypes[0], - Template: " test ", - Subject: " ", - }) - assert.Error(t, err) - assert.Nil(t, emailTemplate) - }) - - t.Run("should not add email template for empty template", func(t *testing.T) { - emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{ - EventName: s.TestInfo.TestEmailTemplateEventTypes[0], - Template: " ", - Subject: "test", - }) - assert.Error(t, err) - assert.Nil(t, emailTemplate) - }) - - design := "" - - for _, eventType := range s.TestInfo.TestEmailTemplateEventTypes { - t.Run("should add email template with empty design for "+eventType, func(t *testing.T) { - emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{ - EventName: eventType, - Template: "Test email", - Subject: "Test email", - Design: &design, - }) - assert.NoError(t, err) - assert.NotNil(t, emailTemplate) - assert.NotEmpty(t, emailTemplate.Message) - - et, err := db.Provider.GetEmailTemplateByEventName(ctx, eventType) - assert.NoError(t, err) - assert.Equal(t, et.EventName, eventType) - assert.Equal(t, "Test email", et.Subject) - assert.Equal(t, "", et.Design) - }) - } - }) -} diff --git a/server/test/add_webhook_test.go b/server/test/add_webhook_test.go deleted file mode 100644 index 500049f55..000000000 --- a/server/test/add_webhook_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package test - -import ( - "fmt" - "testing" - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func addWebhookTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run("should add webhook", func(t *testing.T) { - req, ctx := createContext(s) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.NoError(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.NoError(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - for _, eventType := range s.TestInfo.TestWebhookEventTypes { - webhook, err := resolvers.AddWebhookResolver(ctx, model.AddWebhookRequest{ - EventName: eventType, - Endpoint: s.TestInfo.WebhookEndpoint, - Enabled: true, - Headers: map[string]interface{}{ - "x-test": "foo", - }, - }) - assert.NoError(t, err) - assert.NotNil(t, webhook) - assert.NotEmpty(t, webhook.Message) - } - time.Sleep(2 * time.Second) - // Allow setting multiple webhooks for same event - for _, eventType := range s.TestInfo.TestWebhookEventTypes { - webhook, err := resolvers.AddWebhookResolver(ctx, model.AddWebhookRequest{ - EventName: eventType, - Endpoint: s.TestInfo.WebhookEndpoint, - Enabled: true, - EventDescription: refs.NewStringRef(eventType + "-2"), - Headers: map[string]interface{}{ - "x-test": "foo", - }, - }) - assert.NoError(t, err) - assert.NotNil(t, webhook) - assert.NotEmpty(t, webhook.Message) - } - }) -} diff --git a/server/test/admin_login_test.go b/server/test/admin_login_test.go deleted file mode 100644 index 4b8cc8516..000000000 --- a/server/test/admin_login_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package test - -import ( - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func adminLoginTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should complete admin login`, func(t *testing.T) { - _, ctx := createContext(s) - _, err := resolvers.AdminLoginResolver(ctx, model.AdminLoginInput{ - AdminSecret: "admin_test", - }) - - assert.NotNil(t, err) - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - _, err = resolvers.AdminLoginResolver(ctx, model.AdminLoginInput{ - AdminSecret: adminSecret, - }) - - assert.Nil(t, err) - }) -} diff --git a/server/test/admin_logout_test.go b/server/test/admin_logout_test.go deleted file mode 100644 index d37b1405e..000000000 --- a/server/test/admin_logout_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func adminLogoutTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should get admin session`, func(t *testing.T) { - req, ctx := createContext(s) - _, err := resolvers.AdminLogoutResolver(ctx) - assert.NotNil(t, err) - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - _, err = resolvers.AdminLogoutResolver(ctx) - - assert.Nil(t, err) - }) -} diff --git a/server/test/admin_session_test.go b/server/test/admin_session_test.go deleted file mode 100644 index fb28c96e5..000000000 --- a/server/test/admin_session_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func adminSessionTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should get admin session`, func(t *testing.T) { - req, ctx := createContext(s) - _, err := resolvers.AdminSessionResolver(ctx) - assert.NotNil(t, err) - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - _, err = resolvers.AdminSessionResolver(ctx) - - assert.Nil(t, err) - }) -} diff --git a/server/test/admin_signup_test.go b/server/test/admin_signup_test.go deleted file mode 100644 index 9e425532b..000000000 --- a/server/test/admin_signup_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package test - -import ( - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func adminSignupTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should complete admin signup`, func(t *testing.T) { - _, ctx := createContext(s) - _, err := resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{ - AdminSecret: "admin", - }) - assert.NotNil(t, err) - // reset env for test to pass - err = memorystore.Provider.UpdateEnvVariable(constants.EnvKeyAdminSecret, "") - assert.Nil(t, err) - _, err = resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{ - AdminSecret: "admin123", - }) - assert.NoError(t, err) - }) -} diff --git a/server/test/cors_test.go b/server/test/cors_test.go deleted file mode 100644 index 0dc5c777c..000000000 --- a/server/test/cors_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package test - -import ( - "net/http" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestCors(t *testing.T) { - allowedOrigin := "http://localhost:8080" // The allowed origin that you want to check - notAllowedOrigin := "http://myapp.com" - - s := testSetup() - defer s.Server.Close() - client := &http.Client{} - - req, _ := createContext(s) - req.Header.Add("Origin", allowedOrigin) - res, _ := client.Do(req) - - // You should get your origin (or a * depending on your config) if the - // passed origin is allowed. - o := res.Header.Get("Access-Control-Allow-Origin") - assert.NotEqual(t, o, notAllowedOrigin, "Origins should not match") - assert.Equal(t, o, allowedOrigin, "Origins do match") -} diff --git a/server/test/deactivate_account_test.go b/server/test/deactivate_account_test.go deleted file mode 100644 index 665c5ccc4..000000000 --- a/server/test/deactivate_account_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package test - -import ( - "context" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func deactivateAccountTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should deactiavte the user account with access token only`, func(t *testing.T) { - req, ctx := createContext(s) - email := "deactiavte_account." + s.TestInfo.Email - - resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - _, err := resolvers.DeactivateAccountResolver(ctx) - assert.NotNil(t, err, "unauthorized") - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.NoError(t, err) - assert.NotNil(t, verificationRequest) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.NoError(t, err) - assert.NotNil(t, verifyRes) - s.GinContext.Request.Header.Set("Authorization", "Bearer "+*verifyRes.AccessToken) - ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext) - _, err = resolvers.DeactivateAccountResolver(ctx) - assert.NoError(t, err) - s.GinContext.Request.Header.Set("Authorization", "") - assert.Nil(t, err) - _, err = resolvers.ProfileResolver(ctx) - assert.NotNil(t, err, "unauthorized") - cleanData(email) - }) -} diff --git a/server/test/delete_email_template_test.go b/server/test/delete_email_template_test.go deleted file mode 100644 index c32b6d5b6..000000000 --- a/server/test/delete_email_template_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func deleteEmailTemplateTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run("should delete email templates", func(t *testing.T) { - req, ctx := createContext(s) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.NoError(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.NoError(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - // get all email templates - emailTemplates, err := db.Provider.ListEmailTemplate(ctx, &model.Pagination{ - Limit: 10, - Page: 1, - Offset: 0, - }) - assert.NoError(t, err) - - for _, e := range emailTemplates.EmailTemplates { - res, err := resolvers.DeleteEmailTemplateResolver(ctx, model.DeleteEmailTemplateRequest{ - ID: e.ID, - }) - - assert.NoError(t, err) - assert.NotNil(t, res) - assert.NotEmpty(t, res.Message) - } - - emailTemplates, err = db.Provider.ListEmailTemplate(ctx, &model.Pagination{ - Limit: 10, - Page: 1, - Offset: 0, - }) - assert.NoError(t, err) - assert.Len(t, emailTemplates.EmailTemplates, 0) - }) -} diff --git a/server/test/delete_user_test.go b/server/test/delete_user_test.go deleted file mode 100644 index 94957f0e8..000000000 --- a/server/test/delete_user_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func deleteUserTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should delete users with admin secret only`, func(t *testing.T) { - req, ctx := createContext(s) - email := "delete_user." + s.TestInfo.Email - resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - - _, err := resolvers.DeleteUserResolver(ctx, model.DeleteUserInput{ - Email: email, - }) - assert.NotNil(t, err, "unauthorized") - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - _, err = resolvers.DeleteUserResolver(ctx, model.DeleteUserInput{ - Email: email, - }) - assert.Nil(t, err) - cleanData(email) - }) -} diff --git a/server/test/delete_webhook_test.go b/server/test/delete_webhook_test.go deleted file mode 100644 index 3404a4258..000000000 --- a/server/test/delete_webhook_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func deleteWebhookTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run("should delete webhook", func(t *testing.T) { - req, ctx := createContext(s) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.NoError(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.NoError(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - // get all webhooks - webhooks, err := db.Provider.ListWebhook(ctx, &model.Pagination{ - Limit: 20, - Page: 1, - Offset: 0, - }) - assert.NoError(t, err) - - for _, w := range webhooks.Webhooks { - res, err := resolvers.DeleteWebhookResolver(ctx, model.WebhookRequest{ - ID: w.ID, - }) - - assert.NoError(t, err) - assert.NotNil(t, res) - assert.NotEmpty(t, res.Message) - } - - webhooks, err = db.Provider.ListWebhook(ctx, &model.Pagination{ - Limit: 20, - Page: 1, - Offset: 0, - }) - assert.NoError(t, err) - assert.Len(t, webhooks.Webhooks, 0) - webhookLogs, err := db.Provider.ListWebhookLogs(ctx, &model.Pagination{ - Limit: 100, - Page: 1, - Offset: 0, - }, "") - assert.NoError(t, err) - assert.Len(t, webhookLogs.WebhookLogs, 0) - }) -} diff --git a/server/test/email_templates_test.go b/server/test/email_templates_test.go deleted file mode 100644 index b5c908386..000000000 --- a/server/test/email_templates_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func emailTemplatesTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run("should get email templates", func(t *testing.T) { - req, ctx := createContext(s) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.NoError(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.NoError(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - emailTemplates, err := resolvers.EmailTemplatesResolver(ctx, nil) - assert.NoError(t, err) - assert.NotEmpty(t, emailTemplates) - assert.Len(t, emailTemplates.EmailTemplates, len(s.TestInfo.TestEmailTemplateEventTypes)) - }) -} diff --git a/server/test/enable_access_test.go b/server/test/enable_access_test.go deleted file mode 100644 index 9549968b3..000000000 --- a/server/test/enable_access_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func enableAccessTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should enable access`, func(t *testing.T) { - req, ctx := createContext(s) - email := "enable_access." + s.TestInfo.Email - _, err := resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{ - Email: email, - }) - assert.NoError(t, err) - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin) - assert.NoError(t, err) - assert.NotNil(t, verificationRequest) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.NoError(t, err) - assert.NotNil(t, verifyRes.AccessToken) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - res, err := resolvers.RevokeAccessResolver(ctx, model.UpdateAccessInput{ - UserID: verifyRes.User.ID, - }) - assert.NoError(t, err) - assert.NotEmpty(t, res.Message) - - res, err = resolvers.EnableAccessResolver(ctx, model.UpdateAccessInput{ - UserID: verifyRes.User.ID, - }) - assert.NoError(t, err) - assert.NotEmpty(t, res.Message) - - // it should allow login with enabled access - res, err = resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{ - Email: email, - }) - assert.Nil(t, err) - assert.NotEmpty(t, res.Message) - - cleanData(email) - }) -} diff --git a/server/test/env_file_test.go b/server/test/env_file_test.go deleted file mode 100644 index 31d5c7024..000000000 --- a/server/test/env_file_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package test - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/env" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -func TestEnvs(t *testing.T) { - err := os.Setenv(constants.EnvKeyEnvPath, "../../.env.test") - assert.Nil(t, err) - err = memorystore.InitRequiredEnv() - assert.Nil(t, err) - err = env.InitAllEnv() - assert.Nil(t, err) - store, err := memorystore.Provider.GetEnvStore() - assert.Nil(t, err) - - assert.Equal(t, "test", store[constants.EnvKeyEnv].(string)) - assert.False(t, store[constants.EnvKeyDisableEmailVerification].(bool)) - assert.False(t, store[constants.EnvKeyDisableMagicLinkLogin].(bool)) - assert.False(t, store[constants.EnvKeyDisableBasicAuthentication].(bool)) - assert.Equal(t, "RS256", store[constants.EnvKeyJwtType].(string)) - assert.Equal(t, store[constants.EnvKeyJwtRoleClaim].(string), "role") - assert.EqualValues(t, store[constants.EnvKeyRoles].(string), "user") - assert.EqualValues(t, store[constants.EnvKeyDefaultRoles].(string), "user") - assert.EqualValues(t, store[constants.EnvKeyAllowedOrigins].(string), "*") -} diff --git a/server/test/env_test.go b/server/test/env_test.go deleted file mode 100644 index 725a8341d..000000000 --- a/server/test/env_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func envTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should get envs`, func(t *testing.T) { - req, ctx := createContext(s) - _, err := resolvers.EnvResolver(ctx) - assert.NotNil(t, err) - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - res, err := resolvers.EnvResolver(ctx) - assert.Nil(t, err) - assert.Equal(t, *res.AdminSecret, adminSecret) - }) -} diff --git a/server/test/forgot_password_mobile_test.go b/server/test/forgot_password_mobile_test.go deleted file mode 100644 index 276027975..000000000 --- a/server/test/forgot_password_mobile_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package test - -import ( - "fmt" - "strings" - "testing" - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" -) - -func forgotPasswordMobileTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should run forgot password for mobile`, func(t *testing.T) { - req, ctx := createContext(s) - phoneNumber := "6240345678" - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - PhoneNumber: refs.NewStringRef(phoneNumber), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, res) - forgotPasswordRes, err := resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{ - PhoneNumber: refs.NewStringRef(phoneNumber), - }) - assert.Nil(t, err, "no errors for forgot password") - assert.NotNil(t, forgotPasswordRes) - assert.True(t, *forgotPasswordRes.ShouldShowMobileOtpScreen) - otpReq, err := db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber) - assert.Nil(t, err) - mfaSession := uuid.NewString() - memorystore.Provider.SetMfaSession(res.User.ID, mfaSession, time.Now().Add(1*time.Minute).Unix()) - cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession) - cookie = strings.TrimSuffix(cookie, ";") - req.Header.Set("Cookie", cookie) - // Reset password - resetPasswordRes, err := resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{ - PhoneNumber: refs.NewStringRef(phoneNumber), - Otp: refs.NewStringRef(otpReq.Otp), - Password: s.TestInfo.Password + "test", - ConfirmPassword: s.TestInfo.Password + "test", - }) - assert.Nil(t, err) - assert.NotNil(t, resetPasswordRes) - // Test login - loginRes, err := resolvers.LoginResolver(ctx, model.LoginInput{ - PhoneNumber: refs.NewStringRef(phoneNumber), - Password: s.TestInfo.Password + "test", - }) - assert.Nil(t, err) - assert.NotNil(t, loginRes) - }) -} diff --git a/server/test/forgot_password_test.go b/server/test/forgot_password_test.go deleted file mode 100644 index dd9165af0..000000000 --- a/server/test/forgot_password_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package test - -import ( - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func forgotPasswordTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should run forgot password`, func(t *testing.T) { - _, ctx := createContext(s) - email := "forgot_password." + s.TestInfo.Email - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, res) - forgotPasswordRes, err := resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{ - Email: refs.NewStringRef(email), - }) - assert.Nil(t, err, "no errors for forgot password") - assert.NotNil(t, forgotPasswordRes) - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeForgotPassword) - assert.Nil(t, err) - - assert.Equal(t, verificationRequest.Identifier, constants.VerificationTypeForgotPassword) - - cleanData(email) - }) -} diff --git a/server/test/generate_jwt_keys_test.go b/server/test/generate_jwt_keys_test.go deleted file mode 100644 index e9ef63970..000000000 --- a/server/test/generate_jwt_keys_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func generateJWTkeyTest(t *testing.T, s TestSetup) { - t.Helper() - req, ctx := createContext(s) - t.Run(`generate_jwt_keys`, func(t *testing.T) { - t.Run(`should throw unauthorized`, func(t *testing.T) { - res, err := resolvers.GenerateJWTKeysResolver(ctx, model.GenerateJWTKeysInput{ - Type: "HS256", - }) - assert.Error(t, err) - assert.Nil(t, res) - }) - t.Run(`should throw invalid`, func(t *testing.T) { - res, err := resolvers.GenerateJWTKeysResolver(ctx, model.GenerateJWTKeysInput{ - Type: "test", - }) - assert.Error(t, err) - assert.Nil(t, res) - }) - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - t.Run(`should generate HS256 secret`, func(t *testing.T) { - res, err := resolvers.GenerateJWTKeysResolver(ctx, model.GenerateJWTKeysInput{ - Type: "HS256", - }) - assert.NoError(t, err) - assert.NotEmpty(t, res.Secret) - }) - - t.Run(`should generate RS256 secret`, func(t *testing.T) { - res, err := resolvers.GenerateJWTKeysResolver(ctx, model.GenerateJWTKeysInput{ - Type: "RS256", - }) - assert.NoError(t, err) - assert.NotEmpty(t, res.PrivateKey) - assert.NotEmpty(t, res.PublicKey) - }) - - t.Run(`should generate ES256 secret`, func(t *testing.T) { - res, err := resolvers.GenerateJWTKeysResolver(ctx, model.GenerateJWTKeysInput{ - Type: "ES256", - }) - assert.NoError(t, err) - assert.NotEmpty(t, res.PrivateKey) - assert.NotEmpty(t, res.PublicKey) - }) - }) -} diff --git a/server/test/integration_test.go b/server/test/integration_test.go deleted file mode 100644 index 5329e993d..000000000 --- a/server/test/integration_test.go +++ /dev/null @@ -1,157 +0,0 @@ -package test - -import ( - "context" - "os" - "strings" - "testing" - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/env" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/utils" -) - -func TestResolvers(t *testing.T) { - databases := map[string]string{ - constants.DbTypeSqlite: "../../test.db", - constants.DbTypeArangodb: "http://localhost:8529", - constants.DbTypeMongodb: "mongodb://localhost:27017", - constants.DbTypeScyllaDB: "127.0.0.1:9042", - constants.DbTypeDynamoDB: "http://0.0.0.0:8000", - constants.DbTypeCouchbaseDB: "couchbase://127.0.0.1", - } - - testDBs := strings.Split(os.Getenv("TEST_DBS"), ",") - t.Log("Running tests for following dbs: ", testDBs) - for dbType := range databases { - if !utils.StringSliceContains(testDBs, dbType) { - delete(databases, dbType) - } - } - - if utils.StringSliceContains(testDBs, constants.DbTypeSqlite) && len(testDBs) == 1 { - // do nothing - } else { - t.Log("waiting for docker containers to start...") - // wait for docker containers to spun up - time.Sleep(30 * time.Second) - } - - testDb := "authorizer_test" - s := testSetup() - defer s.Server.Close() - - for dbType, dbURL := range databases { - ctx := context.Background() - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseURL, dbURL) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseType, dbType) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseName, testDb) - os.Setenv(constants.EnvKeyDatabaseURL, dbURL) - os.Setenv(constants.EnvKeyDatabaseType, dbType) - os.Setenv(constants.EnvKeyDatabaseName, testDb) - - if dbType == constants.DbTypeDynamoDB { - memorystore.Provider.UpdateEnvVariable(constants.EnvAwsRegion, "ap-south-1") - os.Setenv(constants.EnvAwsRegion, "ap-south-1") - os.Unsetenv(constants.EnvAwsAccessKeyID) - os.Unsetenv(constants.EnvAwsSecretAccessKey) - // Remove aws credentials from env, so that local dynamodb can be used - memorystore.Provider.UpdateEnvVariable(constants.EnvAwsAccessKeyID, "") - memorystore.Provider.UpdateEnvVariable(constants.EnvAwsSecretAccessKey, "") - } - if dbType == constants.DbTypeCouchbaseDB { - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseUsername, "Administrator") - os.Setenv(constants.EnvKeyDatabaseUsername, "Administrator") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabasePassword, "password") - os.Setenv(constants.EnvKeyDatabasePassword, "password") - } - - memorystore.InitRequiredEnv() - - err := db.InitDB() - if err != nil { - t.Logf("Error initializing database: %s", err.Error()) - } - - // clean the persisted config for test to use fresh config - envData, err := db.Provider.GetEnv(ctx) - if err == nil && envData == nil { - envData = &models.Env{ - EnvData: "", - } - _, err = db.Provider.UpdateEnv(ctx, envData) - if err != nil { - t.Logf("Error updating env: %s", err.Error()) - } - } else if err != nil { - t.Logf("Error getting env: %s", err.Error()) - } - err = env.PersistEnv() - if err != nil { - t.Logf("Error persisting env: %s", err.Error()) - } - - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEnv, "test") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyIsProd, false) - t.Run("should pass tests for "+dbType, func(t *testing.T) { - // admin resolvers tests - adminSignupTests(t, s) - addWebhookTest(t, s) // add webhooks for all the system events - testEndpointTest(t, s) - verificationRequestsTest(t, s) - updateWebhookTest(t, s) - webhookTest(t, s) - webhooksTest(t, s) - //usersTest(t, s) - userTest(t, s) - deleteUserTest(t, s) - //updateUserTest(t, s) - adminLoginTests(t, s) - adminLogoutTests(t, s) - adminSessionTests(t, s) - updateEnvTests(t, s) - envTests(t, s) - revokeAccessTest(t, s) - enableAccessTest(t, s) - generateJWTkeyTest(t, s) - addEmailTemplateTest(t, s) - updateEmailTemplateTest(t, s) - emailTemplatesTest(t, s) - deleteEmailTemplateTest(t, s) - RoleDeletionTest(t, s) - - // user resolvers tests - loginTests(t, s) - signupTests(t, s) - mobileSingupTest(t, s) - mobileLoginTests(t, s) - totpLoginTest(t, s) - totpSignupTest(t, s) - forgotPasswordTest(t, s) - forgotPasswordMobileTest(t, s) - resendVerifyEmailTests(t, s) - resetPasswordTest(t, s) - verifyEmailTest(t, s) - sessionTests(t, s) - profileTests(t, s) - updateProfileTests(t, s) - magicLinkLoginTests(t, s) - logoutTests(t, s) - metaTests(t, s) - inviteUserTest(t, s) - validateJwtTokenTest(t, s) - verifyOTPTest(t, s) - resendOTPTest(t, s) - validateSessionTests(t, s) - deactivateAccountTests(t, s) - - updateAllUsersTest(t, s) - webhookLogsTest(t, s) // get logs after above resolver tests are done - deleteWebhookTest(t, s) // delete webhooks (admin resolver) - }) - } -} diff --git a/server/test/invite_member_test.go b/server/test/invite_member_test.go deleted file mode 100644 index a9aa80677..000000000 --- a/server/test/invite_member_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func inviteUserTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should invite user successfully`, func(t *testing.T) { - req, ctx := createContext(s) - emails := []string{"invite_member1." + s.TestInfo.Email} - - // unauthorized error - res, err := resolvers.InviteMembersResolver(ctx, model.InviteMemberInput{ - Emails: emails, - }) - - assert.Error(t, err) - assert.Nil(t, res) - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - // invalid emails test - invalidEmailsTest := []string{ - "test", - "test.com", - } - res, err = resolvers.InviteMembersResolver(ctx, model.InviteMemberInput{ - Emails: invalidEmailsTest, - }) - assert.Error(t, err) - assert.Nil(t, res) - // valid test - res, err = resolvers.InviteMembersResolver(ctx, model.InviteMemberInput{ - Emails: emails, - }) - assert.Nil(t, err) - assert.NotNil(t, res) - assert.NotNil(t, res.Message) - assert.NotNil(t, res.Users) - // duplicate error test - res, err = resolvers.InviteMembersResolver(ctx, model.InviteMemberInput{ - Emails: emails, - }) - assert.Error(t, err) - assert.Nil(t, res) - cleanData(emails[0]) - }) -} diff --git a/server/test/jwt_test.go b/server/test/jwt_test.go deleted file mode 100644 index 5082689b1..000000000 --- a/server/test/jwt_test.go +++ /dev/null @@ -1,203 +0,0 @@ -package test - -import ( - "testing" - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/token" - "github.com/golang-jwt/jwt" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" -) - -func TestJwt(t *testing.T) { - // persist older data till test is done and then reset it - jwtType, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType) - assert.Nil(t, err) - publicKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey) - assert.Nil(t, err) - privateKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPrivateKey) - assert.Nil(t, err) - clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) - assert.Nil(t, err) - nonce := uuid.New().String() - hostname := "localhost" - subject := "test" - claims := jwt.MapClaims{ - "exp": time.Now().Add(time.Minute * 30).Unix(), - "iat": time.Now().Unix(), - "email": "test@yopmail.com", - "sub": subject, - "aud": clientID, - "nonce": nonce, - "iss": hostname, - } - - t.Run("invalid jwt type", func(t *testing.T) { - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "invalid") - token, err := token.SignJWTToken(claims) - assert.Error(t, err, "unsupported signing method") - assert.Empty(t, token) - }) - t.Run("expired jwt token", func(t *testing.T) { - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "HS256") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtSecret, "test") - expiredClaims := jwt.MapClaims{ - "exp": time.Now().Add(-time.Minute * 30).Unix(), - "iat": time.Now().Unix(), - "email": "test@yopmail.com", - } - jwtToken, err := token.SignJWTToken(expiredClaims) - assert.NoError(t, err) - _, err = token.ParseJWTToken(jwtToken) - assert.Error(t, err, err.Error(), "Token is expired") - }) - t.Run("HMAC algorithms", func(t *testing.T) { - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtSecret, "test") - t.Run("HS256", func(t *testing.T) { - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "HS256") - jwtToken, err := token.SignJWTToken(claims) - assert.NoError(t, err) - assert.NotEmpty(t, jwtToken) - c, err := token.ParseJWTToken(jwtToken) - assert.NoError(t, err) - assert.Equal(t, c["email"].(string), claims["email"]) - valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject) - assert.NoError(t, err) - assert.True(t, valid) - }) - t.Run("HS384", func(t *testing.T) { - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "HS384") - jwtToken, err := token.SignJWTToken(claims) - assert.NoError(t, err) - assert.NotEmpty(t, jwtToken) - c, err := token.ParseJWTToken(jwtToken) - assert.NoError(t, err) - assert.Equal(t, c["email"].(string), claims["email"]) - valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject) - assert.NoError(t, err) - assert.True(t, valid) - }) - t.Run("HS512", func(t *testing.T) { - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "HS512") - jwtToken, err := token.SignJWTToken(claims) - assert.NoError(t, err) - assert.NotEmpty(t, jwtToken) - c, err := token.ParseJWTToken(jwtToken) - assert.NoError(t, err) - assert.Equal(t, c["email"].(string), claims["email"]) - valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject) - assert.NoError(t, err) - assert.True(t, valid) - }) - }) - - t.Run("RSA algorithms", func(t *testing.T) { - t.Run("RS256", func(t *testing.T) { - _, privateKey, publickKey, _, err := crypto.NewRSAKey("RS256", clientID) - assert.NoError(t, err) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "RS256") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPrivateKey, privateKey) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPublicKey, publickKey) - jwtToken, err := token.SignJWTToken(claims) - assert.NoError(t, err) - assert.NotEmpty(t, jwtToken) - c, err := token.ParseJWTToken(jwtToken) - assert.NoError(t, err) - assert.Equal(t, c["email"].(string), claims["email"]) - valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject) - assert.NoError(t, err) - assert.True(t, valid) - }) - t.Run("RS384", func(t *testing.T) { - _, privateKey, publickKey, _, err := crypto.NewRSAKey("RS384", clientID) - assert.NoError(t, err) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "RS384") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPrivateKey, privateKey) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPublicKey, publickKey) - jwtToken, err := token.SignJWTToken(claims) - assert.NoError(t, err) - assert.NotEmpty(t, jwtToken) - c, err := token.ParseJWTToken(jwtToken) - assert.NoError(t, err) - assert.Equal(t, c["email"].(string), claims["email"]) - valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject) - assert.NoError(t, err) - assert.True(t, valid) - }) - t.Run("RS512", func(t *testing.T) { - _, privateKey, publickKey, _, err := crypto.NewRSAKey("RS512", clientID) - assert.NoError(t, err) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "RS512") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPrivateKey, privateKey) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPublicKey, publickKey) - jwtToken, err := token.SignJWTToken(claims) - assert.NoError(t, err) - assert.NotEmpty(t, jwtToken) - c, err := token.ParseJWTToken(jwtToken) - assert.NoError(t, err) - assert.Equal(t, c["email"].(string), claims["email"]) - valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject) - assert.NoError(t, err) - assert.True(t, valid) - }) - }) - - t.Run("ECDSA algorithms", func(t *testing.T) { - t.Run("ES256", func(t *testing.T) { - _, privateKey, publickKey, _, err := crypto.NewECDSAKey("ES256", clientID) - assert.NoError(t, err) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "ES256") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPrivateKey, privateKey) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPublicKey, publickKey) - jwtToken, err := token.SignJWTToken(claims) - assert.NoError(t, err) - assert.NotEmpty(t, jwtToken) - c, err := token.ParseJWTToken(jwtToken) - assert.NoError(t, err) - assert.Equal(t, c["email"].(string), claims["email"]) - valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject) - assert.NoError(t, err) - assert.True(t, valid) - }) - t.Run("ES384", func(t *testing.T) { - _, privateKey, publickKey, _, err := crypto.NewECDSAKey("ES384", clientID) - assert.NoError(t, err) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "ES384") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPrivateKey, privateKey) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPublicKey, publickKey) - jwtToken, err := token.SignJWTToken(claims) - assert.NoError(t, err) - assert.NotEmpty(t, jwtToken) - c, err := token.ParseJWTToken(jwtToken) - assert.NoError(t, err) - assert.Equal(t, c["email"].(string), claims["email"]) - valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject) - assert.NoError(t, err) - assert.True(t, valid) - }) - t.Run("ES512", func(t *testing.T) { - _, privateKey, publickKey, _, err := crypto.NewECDSAKey("ES512", clientID) - assert.NoError(t, err) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "ES512") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPrivateKey, privateKey) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPublicKey, publickKey) - jwtToken, err := token.SignJWTToken(claims) - assert.NoError(t, err) - assert.NotEmpty(t, jwtToken) - c, err := token.ParseJWTToken(jwtToken) - assert.NoError(t, err) - assert.Equal(t, c["email"].(string), claims["email"]) - valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject) - assert.NoError(t, err) - assert.True(t, valid) - }) - }) - - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, jwtType) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPublicKey, publicKey) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtPrivateKey, privateKey) -} diff --git a/server/test/login_test.go b/server/test/login_test.go deleted file mode 100644 index 83b68b791..000000000 --- a/server/test/login_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package test - -import ( - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/stretchr/testify/assert" -) - -func loginTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should login`, func(t *testing.T) { - _, ctx := createContext(s) - email := "login." + s.TestInfo.Email - signUpRes, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, signUpRes) - res, err := resolvers.LoginResolver(ctx, model.LoginInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - }) - // access token should be empty as email is not verified - assert.NoError(t, err) - assert.NotNil(t, res) - assert.Nil(t, res.AccessToken) - assert.NotEmpty(t, res.Message) - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.NoError(t, err) - assert.NotNil(t, verificationRequest) - n, err := utils.EncryptNonce(verificationRequest.Nonce) - assert.NoError(t, err) - assert.NotEmpty(t, n) - assert.NotNil(t, verificationRequest) - res, err = resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.NoError(t, err) - assert.NotNil(t, res) - _, err = resolvers.LoginResolver(ctx, model.LoginInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - Roles: []string{"test"}, - }) - assert.NotNil(t, err, "invalid roles") - - _, err = resolvers.LoginResolver(ctx, model.LoginInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password + "s", - }) - assert.NotNil(t, err, "invalid password") - - loginRes, err := resolvers.LoginResolver(ctx, model.LoginInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - }) - - assert.Nil(t, err, "login successful") - assert.NotNil(t, loginRes.AccessToken, "access token should not be empty") - - cleanData(email) - }) -} diff --git a/server/test/logout_test.go b/server/test/logout_test.go deleted file mode 100644 index 0a79c0bc5..000000000 --- a/server/test/logout_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package test - -import ( - "fmt" - "strings" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/authorizerdev/authorizer/server/token" - "github.com/stretchr/testify/assert" -) - -func logoutTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should logout user`, func(t *testing.T) { - req, ctx := createContext(s) - email := "logout." + s.TestInfo.Email - - magicLoginRes, err := resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{ - Email: email, - }) - assert.NoError(t, err) - assert.NotNil(t, magicLoginRes) - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin) - assert.NoError(t, err) - assert.NotNil(t, verificationRequest) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.NoError(t, err) - assert.NotNil(t, verifyRes) - accessToken := *verifyRes.AccessToken - assert.NotEmpty(t, accessToken) - // Test logout with access token - req.Header.Set("Authorization", "Bearer "+accessToken) - logoutRes, err := resolvers.LogoutResolver(ctx) - assert.Nil(t, err) - assert.NotNil(t, logoutRes) - assert.NotEmpty(t, logoutRes.Message) - req.Header.Set("Authorization", "") - - // Test logout with session cookie - magicLoginRes, err = resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{ - Email: email, - }) - assert.NoError(t, err) - assert.NotNil(t, magicLoginRes) - verificationRequest, err = db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin) - assert.NoError(t, err) - assert.NotNil(t, verificationRequest) - verifyRes, err = resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.NoError(t, err) - assert.NotNil(t, verifyRes) - accessToken = *verifyRes.AccessToken - assert.NotEmpty(t, accessToken) - claims, err := token.ParseJWTToken(accessToken) - assert.NoError(t, err) - assert.NotEmpty(t, claims) - loginMethod := claims["login_method"] - sessionKey := verifyRes.User.ID - if loginMethod != nil && loginMethod != "" { - sessionKey = loginMethod.(string) + ":" + verifyRes.User.ID - } - - sessionToken, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+claims["nonce"].(string)) - assert.NoError(t, err) - assert.NotEmpty(t, sessionToken) - - cookie := fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", sessionToken) - cookie = strings.TrimSuffix(cookie, ";") - - req.Header.Set("Cookie", cookie) - _, err = resolvers.LogoutResolver(ctx) - assert.Nil(t, err) - cleanData(email) - }) -} diff --git a/server/test/magic_link_login_test.go b/server/test/magic_link_login_test.go deleted file mode 100644 index 03b9c86fa..000000000 --- a/server/test/magic_link_login_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package test - -import ( - "context" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func magicLinkLoginTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should login with magic link`, func(t *testing.T) { - req, ctx := createContext(s) - email := "magic_link_login." + s.TestInfo.Email - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, true) - _, err := resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{ - Email: email, - }) - assert.NotNil(t, err, "signup disabled") - - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, false) - _, err = resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{ - Email: email, - }) - assert.Nil(t, err, "signup should be successful") - - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin) - assert.NoError(t, err) - assert.NotNil(t, verificationRequest) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.NoError(t, err) - assert.NotNil(t, verifyRes.AccessToken) - s.GinContext.Request.Header.Set("Authorization", "Bearer "+*verifyRes.AccessToken) - ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext) - _, err = resolvers.ProfileResolver(ctx) - assert.Nil(t, err) - s.GinContext.Request.Header.Set("Authorization", "") - cleanData(email) - }) -} diff --git a/server/test/meta_test.go b/server/test/meta_test.go deleted file mode 100644 index 130ccc7dd..000000000 --- a/server/test/meta_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package test - -import ( - "context" - "testing" - - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func metaTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should get meta information`, func(t *testing.T) { - ctx := context.Background() - meta, err := resolvers.MetaResolver(ctx) - assert.Nil(t, err) - assert.False(t, meta.IsFacebookLoginEnabled) - assert.False(t, meta.IsGoogleLoginEnabled) - assert.False(t, meta.IsGithubLoginEnabled) - assert.True(t, meta.IsEmailVerificationEnabled) - assert.True(t, meta.IsBasicAuthenticationEnabled) - assert.True(t, meta.IsMagicLinkLoginEnabled) - }) -} diff --git a/server/test/mobile_login_test.go b/server/test/mobile_login_test.go deleted file mode 100644 index fa0d5de3b..000000000 --- a/server/test/mobile_login_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package test - -import ( - "fmt" - "strings" - "testing" - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" -) - -func mobileLoginTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should login via mobile`, func(t *testing.T) { - _, ctx := createContext(s) - phoneNumber := "2234567890" - signUpRes, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - PhoneNumber: refs.NewStringRef(phoneNumber), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, signUpRes) - // should fail because phone is not verified - res, err := resolvers.LoginResolver(ctx, model.LoginInput{ - PhoneNumber: refs.NewStringRef(phoneNumber), - Password: s.TestInfo.Password, - }) - // access token should be empty as email is not verified - assert.NoError(t, err) - assert.NotNil(t, res) - assert.Nil(t, res.AccessToken) - assert.NotEmpty(t, res.Message) - assert.True(t, *res.ShouldShowMobileOtpScreen) - smsRequest, err := db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber) - assert.NoError(t, err) - assert.NotEmpty(t, smsRequest.Otp) - // Get user by phone number - user, err := db.Provider.GetUserByPhoneNumber(ctx, phoneNumber) - assert.NoError(t, err) - assert.NotNil(t, user) - // Set mfa cookie session - mfaSession := uuid.NewString() - memorystore.Provider.SetMfaSession(user.ID, mfaSession, time.Now().Add(1*time.Minute).Unix()) - cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession) - cookie = strings.TrimSuffix(cookie, ";") - req, ctx := createContext(s) - req.Header.Set("Cookie", cookie) - verifySMSRequest, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - PhoneNumber: &phoneNumber, - Otp: smsRequest.Otp, - }) - assert.Nil(t, err) - assert.NotEqual(t, verifySMSRequest.Message, "", "message should not be empty") - assert.NotEmpty(t, verifySMSRequest.AccessToken) - assert.NotEmpty(t, verifySMSRequest.IDToken) - }) -} diff --git a/server/test/mobile_signup_test.go b/server/test/mobile_signup_test.go deleted file mode 100644 index 7bfba1c18..000000000 --- a/server/test/mobile_signup_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package test - -import ( - "fmt" - "strings" - "testing" - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" -) - -func mobileSingupTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should complete the signup with mobile and check duplicates`, func(t *testing.T) { - _, ctx := createContext(s) - phoneNumber := "1234567890" - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - PhoneNumber: refs.NewStringRef(phoneNumber), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password + "s", - }) - assert.NotNil(t, err, "invalid password") - assert.Nil(t, res) - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - Password: "test", - ConfirmPassword: "test", - }) - assert.Error(t, err, "phone number or email should be provided") - assert.Nil(t, res) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, true) - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - PhoneNumber: refs.NewStringRef(phoneNumber), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.Error(t, err) - assert.Nil(t, res) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, false) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication, true) - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - PhoneNumber: refs.NewStringRef(phoneNumber), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.Error(t, err) - assert.Nil(t, res) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication, false) - - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - PhoneNumber: refs.NewStringRef(" "), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.Error(t, err) - assert.Nil(t, res) - - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - PhoneNumber: refs.NewStringRef("test"), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.Error(t, err) - assert.Nil(t, res) - - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - PhoneNumber: refs.NewStringRef(phoneNumber), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, res) - assert.True(t, *res.ShouldShowMobileOtpScreen) - // Verify with otp - otp, err := db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber) - assert.Nil(t, err) - assert.NotEmpty(t, otp.Otp) - // Get user by phone number - user, err := db.Provider.GetUserByPhoneNumber(ctx, phoneNumber) - assert.NoError(t, err) - assert.NotNil(t, user) - // Set mfa cookie session - mfaSession := uuid.NewString() - memorystore.Provider.SetMfaSession(user.ID, mfaSession, time.Now().Add(1*time.Minute).Unix()) - cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession) - cookie = strings.TrimSuffix(cookie, ";") - req, ctx := createContext(s) - req.Header.Set("Cookie", cookie) - otpRes, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - PhoneNumber: refs.NewStringRef(phoneNumber), - Otp: otp.Otp, - }) - assert.Nil(t, err) - assert.NotEmpty(t, otpRes.Message) - // Check if phone number is verified - user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber) - assert.NoError(t, err) - assert.NotNil(t, user) - assert.NotNil(t, user.PhoneNumberVerifiedAt) - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - PhoneNumber: refs.NewStringRef(phoneNumber), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.Error(t, err, "should throw duplicate error") - assert.Nil(t, res) - cleanData("1234567890@authorizer.dev") - }) -} diff --git a/server/test/profile_test.go b/server/test/profile_test.go deleted file mode 100644 index a49ba9d0b..000000000 --- a/server/test/profile_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package test - -import ( - "context" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func profileTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should get profile only access_token token`, func(t *testing.T) { - req, ctx := createContext(s) - email := "profile." + s.TestInfo.Email - - resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - - _, err := resolvers.ProfileResolver(ctx) - assert.NotNil(t, err, "unauthorized") - - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.NoError(t, err) - assert.NotNil(t, verificationRequest) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.NoError(t, err) - assert.NotNil(t, verifyRes.AccessToken) - - s.GinContext.Request.Header.Set("Authorization", "Bearer "+*verifyRes.AccessToken) - ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext) - profileRes, err := resolvers.ProfileResolver(ctx) - assert.Nil(t, err) - assert.NotNil(t, profileRes) - s.GinContext.Request.Header.Set("Authorization", "") - newEmail := profileRes.Email - assert.Equal(t, email, refs.StringValue(newEmail), "emails should be equal") - cleanData(email) - }) -} diff --git a/server/test/resend_otp_test.go b/server/test/resend_otp_test.go deleted file mode 100644 index 20b169587..000000000 --- a/server/test/resend_otp_test.go +++ /dev/null @@ -1,114 +0,0 @@ -package test - -import ( - "context" - "fmt" - "strings" - "testing" - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" -) - -func resendOTPTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should resend otp`, func(t *testing.T) { - req, ctx := createContext(s) - email := "resend_otp." + s.TestInfo.Email - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, res) - - // Login should fail as email is not verified - loginRes, err := resolvers.LoginResolver(ctx, model.LoginInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - }) - // access token should be empty as email is not verified - assert.NoError(t, err) - assert.NotNil(t, loginRes) - assert.Nil(t, loginRes.AccessToken) - assert.NotEmpty(t, loginRes.Message) - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.Nil(t, err) - assert.Equal(t, email, verificationRequest.Email) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.Nil(t, err) - assert.NotEqual(t, verifyRes.AccessToken, "", "access token should not be empty") - - // Using access token update profile - s.GinContext.Request.Header.Set("Authorization", "Bearer "+refs.StringValue(verifyRes.AccessToken)) - ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext) - updateRes, err := resolvers.UpdateProfileResolver(ctx, model.UpdateProfileInput{ - IsMultiFactorAuthEnabled: refs.NewBoolRef(true), - }) - assert.NoError(t, err) - assert.NotNil(t, updateRes) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMailOTPLogin, false) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableTOTPLogin, true) - - // Login should not return error but access token should be empty as otp should have been sent - loginRes, err = resolvers.LoginResolver(ctx, model.LoginInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, loginRes) - assert.Nil(t, loginRes.AccessToken) - - // Get otp from db - otp, err := db.Provider.GetOTPByEmail(ctx, email) - assert.NoError(t, err) - assert.NotEmpty(t, otp.Otp) - - // resend otp - resendOtpRes, err := resolvers.ResendOTPResolver(ctx, model.ResendOTPRequest{ - Email: refs.NewStringRef(email), - }) - assert.NoError(t, err) - assert.NotEmpty(t, resendOtpRes.Message) - - newOtp, err := db.Provider.GetOTPByEmail(ctx, email) - assert.NoError(t, err) - assert.NotEmpty(t, newOtp.Otp) - assert.NotEqual(t, otp.Otp, newOtp) - - // Should return error for older otp - verifyOtpRes, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - Email: &email, - Otp: otp.Otp, - }) - assert.Error(t, err) - assert.Nil(t, verifyOtpRes) - // Get user by email - user, err := db.Provider.GetUserByEmail(ctx, email) - assert.NoError(t, err) - assert.NotNil(t, user) - // Set mfa cookie session - mfaSession := uuid.NewString() - memorystore.Provider.SetMfaSession(user.ID, mfaSession, time.Now().Add(1*time.Minute).Unix()) - cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession) - cookie = strings.TrimSuffix(cookie, ";") - req.Header.Set("Cookie", cookie) - verifyOtpRes, err = resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - Email: &email, - Otp: newOtp.Otp, - }) - assert.NoError(t, err) - assert.NotEqual(t, verifyOtpRes.AccessToken, "", "access token should not be empty") - cleanData(email) - }) -} diff --git a/server/test/resend_verify_email_test.go b/server/test/resend_verify_email_test.go deleted file mode 100644 index 028d89a31..000000000 --- a/server/test/resend_verify_email_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package test - -import ( - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func resendVerifyEmailTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should resend verification email`, func(t *testing.T) { - _, ctx := createContext(s) - email := "resend_verify_email." + s.TestInfo.Email - _, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - _, err = resolvers.ResendVerifyEmailResolver(ctx, model.ResendVerifyEmailInput{ - Email: email, - Identifier: constants.VerificationTypeBasicAuthSignup, - }) - assert.NoError(t, err) - - cleanData(email) - }) -} diff --git a/server/test/reset_password_test.go b/server/test/reset_password_test.go deleted file mode 100644 index f784b48e7..000000000 --- a/server/test/reset_password_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package test - -import ( - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func resetPasswordTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should reset password`, func(t *testing.T) { - email := "reset_password." + s.TestInfo.Email - _, ctx := createContext(s) - _, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - _, err = resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{ - Email: refs.NewStringRef(email), - }) - assert.Nil(t, err, "no errors for forgot password") - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeForgotPassword) - assert.Nil(t, err, "should get forgot password request") - assert.NotNil(t, verificationRequest) - _, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{ - Token: refs.NewStringRef(verificationRequest.Token), - Password: "test1", - ConfirmPassword: "test", - }) - assert.NotNil(t, err, "passwords don't match") - _, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{ - Token: refs.NewStringRef(verificationRequest.Token), - Password: "test1", - ConfirmPassword: "test1", - }) - assert.NotNil(t, err, "invalid password") - _, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{ - Token: refs.NewStringRef(verificationRequest.Token), - Password: "Test@1234", - ConfirmPassword: "Test@1234", - }) - assert.Nil(t, err, "password changed successfully") - cleanData(email) - }) -} diff --git a/server/test/revoke_access_test.go b/server/test/revoke_access_test.go deleted file mode 100644 index 4be042d0d..000000000 --- a/server/test/revoke_access_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func revokeAccessTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should revoke access`, func(t *testing.T) { - req, ctx := createContext(s) - email := "revoke_access." + s.TestInfo.Email - _, err := resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{ - Email: email, - }) - assert.NoError(t, err) - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin) - assert.NoError(t, err) - assert.NotNil(t, verificationRequest) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.NoError(t, err) - assert.NotNil(t, verifyRes.AccessToken) - - res, err := resolvers.RevokeAccessResolver(ctx, model.UpdateAccessInput{ - UserID: verifyRes.User.ID, - }) - assert.Error(t, err) - assert.Nil(t, res) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - res, err = resolvers.RevokeAccessResolver(ctx, model.UpdateAccessInput{ - UserID: verifyRes.User.ID, - }) - assert.NoError(t, err) - assert.NotEmpty(t, res.Message) - - // it should not allow login with revoked access - _, err = resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{ - Email: email, - }) - assert.Error(t, err) - cleanData(email) - }) -} diff --git a/server/test/role_deletion_test.go b/server/test/role_deletion_test.go deleted file mode 100644 index ed0ed9000..000000000 --- a/server/test/role_deletion_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package test - -import ( - "fmt" - "github.com/authorizerdev/authorizer/server/crypto" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" -) - -func RoleDeletionTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should complete role deletion`, func(t *testing.T) { - // login as admin - req, ctx := createContext(s) - - _, err := resolvers.AdminLoginResolver(ctx, model.AdminLoginInput{ - AdminSecret: "admin_test", - }) - assert.NotNil(t, err) - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - _, err = resolvers.AdminLoginResolver(ctx, model.AdminLoginInput{ - AdminSecret: adminSecret, - }) - assert.Nil(t, err) - - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - // add new default role to get role, if not present in roles - originalDefaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles) - assert.Nil(t, err) - originalDefaultRolesSlice := strings.Split(originalDefaultRoles, ",") - - data := model.UpdateEnvInput{ - DefaultRoles: append(originalDefaultRolesSlice, "abc"), - } - _, err = resolvers.UpdateEnvResolver(ctx, data) - assert.Error(t, err) - - // add new role - originalRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRoles) - assert.Nil(t, err) - originalRolesSlice := strings.Split(originalRoles, ",") - roleToBeAdded := "abc" - newRoles := append(originalRolesSlice, roleToBeAdded) - data = model.UpdateEnvInput{ - Roles: newRoles, - } - _, err = resolvers.UpdateEnvResolver(ctx, data) - assert.Nil(t, err) - - // register a user with all roles - email := "update_user." + s.TestInfo.Email - _, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - Roles: newRoles, - }) - assert.Nil(t, err) - - regUserDetails, _ := resolvers.UserResolver(ctx, model.GetUserRequest{ - Email: refs.NewStringRef(email), - }) - - // update env by removing role "abc" - var newRolesAfterDeletion []string - for _, value := range newRoles { - if value != roleToBeAdded { - newRolesAfterDeletion = append(newRolesAfterDeletion, value) - } - } - data = model.UpdateEnvInput{ - Roles: newRolesAfterDeletion, - } - _, err = resolvers.UpdateEnvResolver(ctx, data) - assert.Nil(t, err) - - // check user if role still exist - userDetails, err := resolvers.UserResolver(ctx, model.GetUserRequest{ - Email: refs.NewStringRef(email), - }) - assert.Nil(t, err) - assert.Equal(t, newRolesAfterDeletion, userDetails.Roles) - assert.NotEqual(t, newRolesAfterDeletion, regUserDetails.Roles) - }) -} diff --git a/server/test/session_test.go b/server/test/session_test.go deleted file mode 100644 index e80633c6b..000000000 --- a/server/test/session_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package test - -import ( - "fmt" - "strings" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/authorizerdev/authorizer/server/token" - "github.com/stretchr/testify/assert" -) - -func sessionTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should allow access to profile with session only`, func(t *testing.T) { - req, ctx := createContext(s) - email := "session." + s.TestInfo.Email - - resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - - _, err := resolvers.SessionResolver(ctx, &model.SessionQueryInput{}) - assert.NotNil(t, err, "unauthorized") - - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.NoError(t, err) - assert.NotNil(t, verificationRequest) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.NoError(t, err) - assert.NotNil(t, verifyRes) - accessToken := *verifyRes.AccessToken - assert.NotEmpty(t, accessToken) - - claims, err := token.ParseJWTToken(accessToken) - assert.NoError(t, err) - assert.NotEmpty(t, claims) - - sessionKey := constants.AuthRecipeMethodBasicAuth + ":" + verifyRes.User.ID - sessionToken, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+claims["nonce"].(string)) - assert.NoError(t, err) - assert.NotEmpty(t, sessionToken) - - cookie := fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", sessionToken) - cookie = strings.TrimSuffix(cookie, ";") - - req.Header.Set("Cookie", cookie) - _, err = resolvers.SessionResolver(ctx, &model.SessionQueryInput{}) - assert.Nil(t, err) - - cleanData(email) - }) -} diff --git a/server/test/signup_test.go b/server/test/signup_test.go deleted file mode 100644 index ec8cdb36b..000000000 --- a/server/test/signup_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package test - -import ( - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func signupTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should complete the signup and check duplicates`, func(t *testing.T) { - _, ctx := createContext(s) - email := "signup." + s.TestInfo.Email - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password + "s", - }) - assert.NotNil(t, err, "invalid password") - assert.Nil(t, res) - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: "test", - ConfirmPassword: "test", - }) - assert.NotNil(t, err, "invalid password") - assert.Nil(t, res) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, true) - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NotNil(t, err, "signup disabled") - assert.Nil(t, res) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, false) - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - AppData: map[string]interface{}{ - "test": "test", - }, - }) - assert.Nil(t, err, "signup should be successful") - user := *res.User - assert.Equal(t, email, refs.StringValue(user.Email)) - assert.Equal(t, "test", user.AppData["test"]) - assert.Nil(t, res.AccessToken, "access token should be nil") - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NotNil(t, err, "should throw duplicate email error") - assert.Nil(t, res) - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.Nil(t, err) - assert.Equal(t, email, verificationRequest.Email) - cleanData(email) - }) -} diff --git a/server/test/test.go b/server/test/test.go deleted file mode 100644 index 524aeb4b1..000000000 --- a/server/test/test.go +++ /dev/null @@ -1,159 +0,0 @@ -package test - -import ( - "context" - "fmt" - "net/http" - "net/http/httptest" - "os" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/env" - "github.com/authorizerdev/authorizer/server/handlers" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/middlewares" - "github.com/gin-gonic/gin" -) - -// common user data to share across tests -type TestData struct { - Email string - Password string - WebhookEndpoint string - TestWebhookEventTypes []string - TestEmailTemplateEventTypes []string -} - -type TestSetup struct { - GinEngine *gin.Engine - GinContext *gin.Context - Server *httptest.Server - TestInfo TestData -} - -func cleanData(email string) { - ctx := context.Background() - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - if err == nil { - err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest) - if err != nil { - log.Debug("DeleteVerificationRequest err", err) - } - } - - verificationRequest, err = db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeForgotPassword) - if err == nil { - err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest) - if err != nil { - log.Debug("DeleteVerificationRequest err", err) - } - } - - verificationRequest, err = db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeUpdateEmail) - if err == nil { - err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest) - if err != nil { - log.Debug("DeleteVerificationRequest err", err) - } - } - - verificationRequest, err = db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin) - if err == nil { - err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest) - if err != nil { - log.Debug("DeleteVerificationRequest err", err) - } - } - - otp, err := db.Provider.GetOTPByEmail(ctx, email) - if err == nil { - err = db.Provider.DeleteOTP(ctx, otp) - if err != nil { - log.Debug("DeleteOTP err", err) - } - } - - dbUser, err := db.Provider.GetUserByEmail(ctx, email) - if err == nil { - err = db.Provider.DeleteUser(ctx, dbUser) - if err != nil { - log.Debug("DeleteUser err", err) - } - } -} - -func createContext(s TestSetup) (*http.Request, context.Context) { - req, _ := http.NewRequest( - "POST", - "http://"+s.Server.Listener.Addr().String()+"/graphql", - nil, - ) - - ctx := context.WithValue(req.Context(), "GinContextKey", s.GinContext) - s.GinContext.Request = req - return req, ctx -} - -func testSetup() TestSetup { - testData := TestData{ - Email: fmt.Sprintf("%d_authorizer_tester@yopmail.com", time.Now().Unix()), - Password: "Test@123", - WebhookEndpoint: "https://62f93101e05644803533cf36.mockapi.io/authorizer/webhook", - TestWebhookEventTypes: []string{constants.UserAccessEnabledWebhookEvent, constants.UserAccessRevokedWebhookEvent, constants.UserCreatedWebhookEvent, constants.UserDeletedWebhookEvent, constants.UserLoginWebhookEvent, constants.UserSignUpWebhookEvent, constants.UserDeactivatedWebhookEvent}, - TestEmailTemplateEventTypes: []string{constants.VerificationTypeBasicAuthSignup, constants.VerificationTypeForgotPassword, constants.VerificationTypeMagicLinkLogin, constants.VerificationTypeUpdateEmail}, - } - - err := os.Setenv(constants.EnvKeyEnvPath, "../../.env.test") - if err != nil { - log.Fatal("Error loading .env.sample file") - } - err = memorystore.InitRequiredEnv() - if err != nil { - log.Fatal("Error loading required env: ", err) - } - - err = memorystore.InitMemStore() - if err != nil { - log.Fatal("Error loading memory store: ", err) - } - memorystore.Provider.UpdateEnvVariable(constants.EnvKeySmtpHost, "smtp.yopmail.com") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeySmtpPort, "2525") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeySmtpUsername, "lakhan@yopmail.com") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeySmtpPassword, "test") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeySenderEmail, "info@yopmail.com") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyProtectedRoles, "admin") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyTwilioAPIKey, "test") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyTwilioAPISecret, "test") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyTwilioAccountSID, "test") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyTwilioSender, "1234567890") - - err = db.InitDB() - if err != nil { - log.Fatal("Error loading db: ", err) - } - - err = env.InitAllEnv() - if err != nil { - log.Fatal("Error loading env: ", err) - } - - w := httptest.NewRecorder() - c, r := gin.CreateTestContext(w) - r.Use(middlewares.GinContextToContextMiddleware()) - r.Use(middlewares.CORSMiddleware()) - - r.POST("/graphql", handlers.GraphqlHandler()) - - server := httptest.NewServer(r) - - return TestSetup{ - GinEngine: r, - GinContext: c, - Server: server, - TestInfo: testData, - } -} diff --git a/server/test/test_endpoint_test.go b/server/test/test_endpoint_test.go deleted file mode 100644 index 1b29395ac..000000000 --- a/server/test/test_endpoint_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func testEndpointTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run("should test endpoint", func(t *testing.T) { - req, ctx := createContext(s) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.NoError(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.NoError(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - res, err := resolvers.TestEndpointResolver(ctx, model.TestEndpointRequest{ - Endpoint: s.TestInfo.WebhookEndpoint, - EventName: constants.UserLoginWebhookEvent, - Headers: map[string]interface{}{ - "x-test": "test", - }, - }) - assert.NoError(t, err) - assert.NotNil(t, res) - assert.GreaterOrEqual(t, *res.HTTPStatus, int64(200)) - assert.NotEmpty(t, res.Response) - }) -} diff --git a/server/test/totp_login_test.go b/server/test/totp_login_test.go deleted file mode 100644 index 3b9321ef7..000000000 --- a/server/test/totp_login_test.go +++ /dev/null @@ -1,164 +0,0 @@ -package test - -import ( - "bytes" - "context" - "encoding/base64" - "fmt" - "strings" - "testing" - "time" - - "github.com/authorizerdev/authorizer/server/authenticators" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/authorizerdev/authorizer/server/token" - "github.com/gokyle/twofactor" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" - "github.com/tuotoo/qrcode" -) - -func totpLoginTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should verify totp`, func(t *testing.T) { - req, ctx := createContext(s) - email := "verify_totp." + s.TestInfo.Email - cleanData(email) - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: &email, - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, res) - - // Login should fail as email is not verified - loginRes, err := resolvers.LoginResolver(ctx, model.LoginInput{ - Email: &email, - Password: s.TestInfo.Password, - }) - // access token should be empty as email is not verified - assert.NoError(t, err) - assert.NotNil(t, loginRes) - assert.Nil(t, loginRes.AccessToken) - assert.NotEmpty(t, loginRes.Message) - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.Nil(t, err) - assert.Equal(t, email, verificationRequest.Email) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.Nil(t, err) - assert.NotEqual(t, verifyRes.AccessToken, "", "access token should not be empty") - - // Using access token update profile - s.GinContext.Request.Header.Set("Authorization", "Bearer "+refs.StringValue(verifyRes.AccessToken)) - ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableTOTPLogin, false) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMailOTPLogin, true) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisablePhoneVerification, true) - updateProfileRes, err := resolvers.UpdateProfileResolver(ctx, model.UpdateProfileInput{ - IsMultiFactorAuthEnabled: refs.NewBoolRef(true), - }) - assert.NoError(t, err) - assert.NotEmpty(t, updateProfileRes.Message) - - authenticators.InitTOTPStore() - // Login should not return error but access token should be empty - loginRes, err = resolvers.LoginResolver(ctx, model.LoginInput{ - Email: &email, - Password: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, loginRes) - assert.True(t, *loginRes.ShouldShowTotpScreen) - assert.NotNil(t, *loginRes.AuthenticatorScannerImage) - assert.NotNil(t, *loginRes.AuthenticatorSecret) - assert.NotNil(t, loginRes.AuthenticatorRecoveryCodes) - assert.Nil(t, loginRes.AccessToken) - assert.NotEmpty(t, loginRes.Message) - - // get totp url for validation - pngBytes, err := base64.StdEncoding.DecodeString(*loginRes.AuthenticatorScannerImage) - assert.NoError(t, err) - qrmatrix, err := qrcode.Decode(bytes.NewReader(pngBytes)) - assert.NoError(t, err) - tf, label, err := twofactor.FromURL(qrmatrix.Content) - data := strings.Split(label, ":") - assert.NoError(t, err) - assert.Equal(t, email, data[1]) - assert.NotNil(t, tf) - code := tf.OTP() - assert.NotEmpty(t, code) - - // Set mfa cookie session - mfaSession := uuid.NewString() - memorystore.Provider.SetMfaSession(verifyRes.User.ID, mfaSession, time.Now().Add(1*time.Minute).Unix()) - cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession) - cookie = strings.TrimSuffix(cookie, ";") - req.Header.Set("Cookie", cookie) - valid, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - Email: &email, - IsTotp: refs.NewBoolRef(true), - Otp: code, - }) - accessToken := valid.AccessToken - assert.NoError(t, err) - assert.NotNil(t, accessToken) - assert.NotEmpty(t, valid.Message) - assert.NotEmpty(t, accessToken) - claims, err := token.ParseJWTToken(*accessToken) - assert.NoError(t, err) - assert.NotEmpty(t, claims) - loginMethod := claims["login_method"] - sessionKey := verifyRes.User.ID - if loginMethod != nil && loginMethod != "" { - sessionKey = loginMethod.(string) + ":" + verifyRes.User.ID - } - sessionToken, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+claims["nonce"].(string)) - assert.NoError(t, err) - assert.NotEmpty(t, sessionToken) - cookie = fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", sessionToken) - cookie = strings.TrimSuffix(cookie, ";") - req.Header.Set("Cookie", cookie) - - //logged out - logout, err := resolvers.LogoutResolver(ctx) - assert.NoError(t, err) - assert.NotEmpty(t, logout.Message) - loginRes, err = resolvers.LoginResolver(ctx, model.LoginInput{ - Email: &email, - Password: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, loginRes) - assert.Nil(t, loginRes.AuthenticatorRecoveryCodes) - assert.Nil(t, loginRes.AccessToken) - assert.Nil(t, loginRes.AuthenticatorScannerImage) - assert.Nil(t, loginRes.AuthenticatorSecret) - assert.True(t, *loginRes.ShouldShowTotpScreen) - assert.NotEmpty(t, loginRes.Message) - code = tf.OTP() - assert.NotEmpty(t, code) - // Set mfa cookie session - mfaSession = uuid.NewString() - memorystore.Provider.SetMfaSession(verifyRes.User.ID, mfaSession, time.Now().Add(1*time.Minute).Unix()) - cookie = fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession) - cookie = strings.TrimSuffix(cookie, ";") - req.Header.Set("Cookie", cookie) - valid, err = resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - Otp: code, - Email: &email, - IsTotp: refs.NewBoolRef(true), - }) - assert.NoError(t, err) - assert.NotNil(t, *valid.AccessToken) - assert.NotEmpty(t, valid.Message) - cleanData(email) - }) -} diff --git a/server/test/totp_signup_test.go b/server/test/totp_signup_test.go deleted file mode 100644 index 6dc5a0d3c..000000000 --- a/server/test/totp_signup_test.go +++ /dev/null @@ -1,187 +0,0 @@ -package test - -import ( - "bytes" - "encoding/base64" - "fmt" - "strings" - "testing" - "time" - - "github.com/authorizerdev/authorizer/server/authenticators" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/authorizerdev/authorizer/server/token" - "github.com/gokyle/twofactor" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" - "github.com/tuotoo/qrcode" -) - -func totpSignupTest(t *testing.T, s TestSetup) { - t.Helper() - // Test case to verify TOTP for signup - t.Run(`should verify totp for signup`, func(t *testing.T) { - // Create request and context using test setup - req, ctx := createContext(s) - email := "verify_totp." + s.TestInfo.Email - - // Test case: Invalid password (confirm password mismatch) - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password + "s", - }) - assert.NotNil(t, err, "invalid password") - assert.Nil(t, res) - - { - // Test case: Invalid password ("test" as the password) - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: "test", - ConfirmPassword: "test", - }) - assert.NotNil(t, err, "invalid password") - assert.Nil(t, res) - } - - { - // Test case: Signup disabled - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, true) - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NotNil(t, err, "signup disabled") - assert.Nil(t, res) - } - - { - // Test case: Successful signup - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, false) - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - AppData: map[string]interface{}{ - "test": "test", - }, - }) - assert.Nil(t, err, "signup should be successful") - user := *res.User - assert.Equal(t, email, refs.StringValue(user.Email)) - assert.Equal(t, "test", user.AppData["test"]) - assert.Nil(t, res.AccessToken, "access token should be nil") - } - - { - // Test case: Duplicate email (should throw an error) - res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NotNil(t, err, "should throw duplicate email error") - assert.Nil(t, res) - } - - // Clean up data for the email - cleanData(email) - - { - // Test case: Email verification and TOTP setup - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableEmailVerification, false) - - // Sign up a user - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.Nil(t, err, "Expected no error but got: %v", err) - assert.Equal(t, "Verification email has been sent. Please check your inbox", res.Message) - - // Retrieve user and update for TOTP setup - user, err := db.Provider.GetUserByID(ctx, res.User.ID) - assert.Nil(t, err, "Expected no error but got: %v", err) - assert.NotNil(t, user) - - // Enable multi-factor authentication and update the user - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableTOTPLogin, false) - user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) - updatedUser, err := db.Provider.UpdateUser(ctx, user) - assert.Nil(t, err, "Expected no error but got: %v", err) - assert.Equal(t, true, *updatedUser.IsMultiFactorAuthEnabled) - - // Initialise totp authenticator store - authenticators.InitTOTPStore() - - // Verify an email and get TOTP response - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.Nil(t, err) - assert.Equal(t, email, verificationRequest.Email) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.Nil(t, err, "Expected no error but got: %v", err) - assert.NotNil(t, &verifyRes) - assert.Nil(t, verifyRes.AccessToken) - assert.Equal(t, "Proceed to totp verification screen", verifyRes.Message) - assert.NotEqual(t, *verifyRes.AuthenticatorScannerImage, "", "totp url should not be empty") - assert.NotEqual(t, *verifyRes.AuthenticatorSecret, "", "totp secret should not be empty") - assert.NotNil(t, verifyRes.AuthenticatorRecoveryCodes) - - // Get TOTP URL for for validation - pngBytes, err := base64.StdEncoding.DecodeString(*verifyRes.AuthenticatorScannerImage) - assert.NoError(t, err) - qrmatrix, err := qrcode.Decode(bytes.NewReader(pngBytes)) - assert.NoError(t, err) - tf, label, err := twofactor.FromURL(qrmatrix.Content) - data := strings.Split(label, ":") - assert.NoError(t, err) - assert.Equal(t, email, data[1]) - assert.NotNil(t, tf) - code := tf.OTP() - assert.NotEmpty(t, code) - - // Set MFA cookie session - mfaSession := uuid.NewString() - memorystore.Provider.SetMfaSession(res.User.ID, mfaSession, time.Now().Add(1*time.Minute).Unix()) - cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession) - cookie = strings.TrimSuffix(cookie, ";") - req.Header.Set("Cookie", cookie) - valid, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - Email: &email, - IsTotp: refs.NewBoolRef(true), - Otp: code, - }) - accessToken := *valid.AccessToken - assert.NoError(t, err) - assert.NotNil(t, accessToken) - assert.NotEmpty(t, valid.Message) - assert.NotEmpty(t, accessToken) - claims, err := token.ParseJWTToken(accessToken) - assert.NoError(t, err) - assert.NotEmpty(t, claims) - signUpMethod := claims["login_method"] - sessionKey := res.User.ID - if signUpMethod != nil && signUpMethod != "" { - sessionKey = signUpMethod.(string) + ":" + res.User.ID - } - sessionToken, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+claims["nonce"].(string)) - assert.NoError(t, err) - assert.NotEmpty(t, sessionToken) - cookie = fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", sessionToken) - cookie = strings.TrimSuffix(cookie, ";") - req.Header.Set("Cookie", cookie) - } - // Clean up data for the email - cleanData(email) - }) -} diff --git a/server/test/update_all_users_tests.go b/server/test/update_all_users_tests.go deleted file mode 100644 index f3cc82fc7..000000000 --- a/server/test/update_all_users_tests.go +++ /dev/null @@ -1,67 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/stretchr/testify/assert" -) - -func updateAllUsersTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run("Should update all users", func(t *testing.T) { - _, ctx := createContext(s) - for i := 0; i < 10; i++ { - user := &models.User{ - Email: refs.NewStringRef(fmt.Sprintf("update_all_user_%d_%s", i, s.TestInfo.Email)), - SignupMethods: constants.AuthRecipeMethodBasicAuth, - Roles: "user", - } - u, err := db.Provider.AddUser(ctx, user) - assert.NoError(t, err) - assert.NotNil(t, u) - } - - err := db.Provider.UpdateUsers(ctx, map[string]interface{}{ - "is_multi_factor_auth_enabled": true, - }, nil) - assert.NoError(t, err) - - listUsers, err := db.Provider.ListUsers(ctx, &model.Pagination{ - Limit: 20, - Offset: 0, - }) - assert.NoError(t, err) - assert.Greater(t, len(listUsers.Users), 0) - for _, u := range listUsers.Users { - assert.True(t, refs.BoolValue(u.IsMultiFactorAuthEnabled)) - } - // // update few users - updateIds := []string{listUsers.Users[0].ID, listUsers.Users[1].ID} - err = db.Provider.UpdateUsers(ctx, map[string]interface{}{ - "is_multi_factor_auth_enabled": false, - }, updateIds) - assert.NoError(t, err) - listUsers, err = db.Provider.ListUsers(ctx, &model.Pagination{ - Limit: 20, - Offset: 0, - }) - assert.NoError(t, err) - assert.NotNil(t, listUsers) - assert.Greater(t, len(listUsers.Users), 0) - for _, u := range listUsers.Users { - if utils.StringSliceContains(updateIds, u.ID) { - assert.False(t, refs.BoolValue(u.IsMultiFactorAuthEnabled)) - } else { - assert.True(t, refs.BoolValue(u.IsMultiFactorAuthEnabled)) - } - cleanData(refs.StringValue(u.Email)) - } - }) -} diff --git a/server/test/update_email_template_test.go b/server/test/update_email_template_test.go deleted file mode 100644 index 94b9de53c..000000000 --- a/server/test/update_email_template_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func updateEmailTemplateTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run("should update email template", func(t *testing.T) { - req, ctx := createContext(s) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.NoError(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.NoError(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - // get email template - emailTemplate, err := db.Provider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeBasicAuthSignup) - assert.NoError(t, err) - assert.NotNil(t, emailTemplate) - - res, err := resolvers.UpdateEmailTemplateResolver(ctx, model.UpdateEmailTemplateRequest{ - ID: emailTemplate.ID, - Template: refs.NewStringRef("Updated test template"), - Subject: refs.NewStringRef("Updated subject"), - Design: refs.NewStringRef("Updated design"), - }) - - assert.NoError(t, err) - assert.NotEmpty(t, res) - assert.NotEmpty(t, res.Message) - - updatedEmailTemplate, err := db.Provider.GetEmailTemplateByEventName(ctx, constants.VerificationTypeBasicAuthSignup) - assert.NoError(t, err) - assert.NotNil(t, updatedEmailTemplate) - assert.Equal(t, emailTemplate.ID, updatedEmailTemplate.ID) - assert.Equal(t, updatedEmailTemplate.Template, "Updated test template") - assert.Equal(t, updatedEmailTemplate.Subject, "Updated subject") - assert.Equal(t, updatedEmailTemplate.Design, "Updated design") - }) -} diff --git a/server/test/update_env_test.go b/server/test/update_env_test.go deleted file mode 100644 index c602b4a8a..000000000 --- a/server/test/update_env_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package test - -import ( - "fmt" - "strings" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func updateEnvTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should update envs`, func(t *testing.T) { - req, ctx := createContext(s) - originalAppURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppURL) - assert.Nil(t, err) - - data := model.UpdateEnvInput{} - _, err = resolvers.UpdateEnvResolver(ctx, data) - - assert.NotNil(t, err) - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - newURL := "https://test.com" - disableLoginPage := true - allowedOrigins := []string{"http://localhost:8080"} - data = model.UpdateEnvInput{ - AppURL: &newURL, - DisableLoginPage: &disableLoginPage, - AllowedOrigins: allowedOrigins, - } - _, err = resolvers.UpdateEnvResolver(ctx, data) - assert.Nil(t, err) - - appURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppURL) - assert.Nil(t, err) - assert.Equal(t, appURL, newURL) - - isLoginPageDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableLoginPage) - assert.Nil(t, err) - assert.True(t, isLoginPageDisabled) - - storedOriginsStrings, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAllowedOrigins) - assert.Nil(t, err) - storedOrigins := strings.Split(storedOriginsStrings, ",") - assert.Equal(t, storedOrigins, allowedOrigins) - - disableLoginPage = false - data = model.UpdateEnvInput{ - AppURL: &originalAppURL, - DisableLoginPage: &disableLoginPage, - AllowedOrigins: []string{"*"}, - } - _, err = resolvers.UpdateEnvResolver(ctx, data) - assert.Nil(t, err) - }) -} diff --git a/server/test/update_profile_test.go b/server/test/update_profile_test.go deleted file mode 100644 index 12a0ab550..000000000 --- a/server/test/update_profile_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package test - -import ( - "context" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func updateProfileTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should update the profile with access token only`, func(t *testing.T) { - req, ctx := createContext(s) - email := "update_profile." + s.TestInfo.Email - - resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - - fName := "samani" - _, err := resolvers.UpdateProfileResolver(ctx, model.UpdateProfileInput{ - FamilyName: &fName, - }) - assert.NotNil(t, err, "unauthorized") - - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.NoError(t, err) - assert.NotNil(t, verificationRequest) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.NoError(t, err) - assert.NotNil(t, verifyRes) - s.GinContext.Request.Header.Set("Authorization", "Bearer "+*verifyRes.AccessToken) - ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext) - - newEmail := "new_" + email - _, err = resolvers.UpdateProfileResolver(ctx, model.UpdateProfileInput{ - Email: &newEmail, - }) - s.GinContext.Request.Header.Set("Authorization", "") - assert.Nil(t, err) - _, err = resolvers.ProfileResolver(ctx) - assert.NotNil(t, err, "unauthorized") - - cleanData(newEmail) - cleanData(email) - }) -} diff --git a/server/test/update_user_test.go b/server/test/update_user_test.go deleted file mode 100644 index eab173112..000000000 --- a/server/test/update_user_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func updateUserTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should update the user with admin secret only`, func(t *testing.T) { - req, ctx := createContext(s) - email := "update_user." + s.TestInfo.Email - signupRes, _ := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - - user := *signupRes.User - - adminRole := "supplier" - userRole := "user" - newRoles := []*string{&adminRole, &userRole} - _, err := resolvers.UpdateUserResolver(ctx, model.UpdateUserInput{ - ID: user.ID, - Roles: newRoles, - }) - assert.NotNil(t, err, "unauthorized") - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - _, err = resolvers.UpdateUserResolver(ctx, model.UpdateUserInput{ - ID: user.ID, - Roles: newRoles, - }) - // supplier is not part of envs - assert.Error(t, err) - adminRole = "admin" - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyProtectedRoles, adminRole) - newRoles = []*string{&adminRole, &userRole} - _, err = resolvers.UpdateUserResolver(ctx, model.UpdateUserInput{ - ID: user.ID, - Roles: newRoles, - AppData: map[string]interface{}{ - "test": "test", - }, - }) - assert.Nil(t, err) - // Get user and check if roles are updated - users, err := resolvers.UsersResolver(ctx, nil) - assert.Nil(t, err) - for _, u := range users.Users { - if u.ID == user.ID { - assert.Equal(t, u.AppData["test"], "test") - } - } - cleanData(email) - }) -} diff --git a/server/test/update_webhook_test.go b/server/test/update_webhook_test.go deleted file mode 100644 index 6e2d023b4..000000000 --- a/server/test/update_webhook_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func updateWebhookTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run("should update webhook", func(t *testing.T) { - req, ctx := createContext(s) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.NoError(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.NoError(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - // get webhook - webhooks, err := db.Provider.GetWebhookByEventName(ctx, constants.UserDeletedWebhookEvent) - assert.NoError(t, err) - assert.NotNil(t, webhooks) - assert.GreaterOrEqual(t, len(webhooks), 2) - for _, webhook := range webhooks { - // it should completely replace headers - webhook.Headers = map[string]interface{}{ - "x-new-test": "test", - } - res, err := resolvers.UpdateWebhookResolver(ctx, model.UpdateWebhookRequest{ - ID: webhook.ID, - Headers: webhook.Headers, - Enabled: refs.NewBoolRef(false), - Endpoint: refs.NewStringRef("https://sometest.com"), - }) - assert.NoError(t, err) - assert.NotEmpty(t, res) - assert.NotEmpty(t, res.Message) - } - if len(webhooks) == 0 { - // avoid index out of range error - return - } - // Test updating webhook name - w := webhooks[0] - res, err := resolvers.UpdateWebhookResolver(ctx, model.UpdateWebhookRequest{ - ID: w.ID, - EventName: refs.NewStringRef(constants.UserAccessEnabledWebhookEvent), - }) - assert.NoError(t, err) - assert.NotNil(t, res) - // Check if webhooks with new name is as per expected len - accessWebhooks, err := db.Provider.GetWebhookByEventName(ctx, constants.UserAccessEnabledWebhookEvent) - assert.NoError(t, err) - assert.GreaterOrEqual(t, len(accessWebhooks), 3) - // Revert name change - res, err = resolvers.UpdateWebhookResolver(ctx, model.UpdateWebhookRequest{ - ID: w.ID, - EventName: refs.NewStringRef(constants.UserDeletedWebhookEvent), - }) - assert.NoError(t, err) - assert.NotNil(t, res) - updatedWebhooks, err := db.Provider.GetWebhookByEventName(ctx, constants.UserDeletedWebhookEvent) - assert.NoError(t, err) - assert.NotNil(t, updatedWebhooks) - assert.GreaterOrEqual(t, len(updatedWebhooks), 2) - for _, updatedWebhook := range updatedWebhooks { - assert.Contains(t, refs.StringValue(updatedWebhook.EventName), constants.UserDeletedWebhookEvent) - assert.Len(t, updatedWebhook.Headers, 1) - assert.False(t, refs.BoolValue(updatedWebhook.Enabled)) - foundUpdatedHeader := false - for key, val := range updatedWebhook.Headers { - if key == "x-new-test" && val == "test" { - foundUpdatedHeader = true - } - } - assert.True(t, foundUpdatedHeader) - assert.Equal(t, "https://sometest.com", refs.StringValue(updatedWebhook.Endpoint)) - res, err := resolvers.UpdateWebhookResolver(ctx, model.UpdateWebhookRequest{ - ID: updatedWebhook.ID, - Headers: updatedWebhook.Headers, - Enabled: refs.NewBoolRef(true), - Endpoint: refs.NewStringRef(s.TestInfo.WebhookEndpoint), - }) - assert.NoError(t, err) - assert.NotEmpty(t, res) - assert.NotEmpty(t, res.Message) - } - }) -} diff --git a/server/test/urls_test.go b/server/test/urls_test.go deleted file mode 100644 index 3ec2a534d..000000000 --- a/server/test/urls_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package test - -import ( - "testing" - - "github.com/authorizerdev/authorizer/server/parsers" - "github.com/stretchr/testify/assert" -) - -func TestGetHostName(t *testing.T) { - url := "http://test.herokuapp.com:80" - - host, port := parsers.GetHostParts(url) - expectedHost := "test.herokuapp.com" - - assert.Equal(t, host, expectedHost, "hostname should be equal") - assert.Equal(t, port, "80", "port should be 80") -} - -func TestGetDomainName(t *testing.T) { - url := "http://test.herokuapp.com" - - got := parsers.GetDomainName(url) - want := "herokuapp.com" - - assert.Equal(t, got, want, "domain name should be equal") -} diff --git a/server/test/user_test.go b/server/test/user_test.go deleted file mode 100644 index 97a870fc9..000000000 --- a/server/test/user_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func userTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should get users list with admin secret only`, func(t *testing.T) { - req, ctx := createContext(s) - email := "user." + s.TestInfo.Email - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotEmpty(t, res.User) - - userRes, err := resolvers.UserResolver(ctx, model.GetUserRequest{ - ID: &res.User.ID, - }) - assert.Nil(t, userRes) - assert.NotNil(t, err, "unauthorized") - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - // Should throw error for invalid params - userRes, err = resolvers.UserResolver(ctx, model.GetUserRequest{}) - assert.Nil(t, userRes) - assert.NotNil(t, err, "invalid params, user id or email is required") - // Should throw error for invalid params with empty id - userRes, err = resolvers.UserResolver(ctx, model.GetUserRequest{ - ID: refs.NewStringRef(" "), - }) - assert.Nil(t, userRes) - assert.NotNil(t, err, "invalid params, user id or email is required") - // Should throw error for invalid params with empty email - userRes, err = resolvers.UserResolver(ctx, model.GetUserRequest{ - Email: refs.NewStringRef(" "), - }) - assert.Nil(t, userRes) - assert.NotNil(t, err, "invalid params, user id or email is required") - // Should get user by id - userRes, err = resolvers.UserResolver(ctx, model.GetUserRequest{ - ID: &res.User.ID, - }) - assert.Nil(t, err) - assert.Equal(t, res.User.ID, userRes.ID) - assert.Equal(t, email, refs.StringValue(userRes.Email)) - // Should get user by email - userRes, err = resolvers.UserResolver(ctx, model.GetUserRequest{ - Email: &email, - }) - assert.Nil(t, err) - assert.Equal(t, res.User.ID, userRes.ID) - assert.Equal(t, email, refs.StringValue(userRes.Email)) - cleanData(email) - }) -} diff --git a/server/test/users_test.go b/server/test/users_test.go deleted file mode 100644 index 22551ecb4..000000000 --- a/server/test/users_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func usersTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should get users list with admin secret only`, func(t *testing.T) { - req, ctx := createContext(s) - email := "users." + s.TestInfo.Email - resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - - limit := int64(10) - page := int64(1) - pagination := &model.PaginatedInput{ - Pagination: &model.PaginationInput{ - Limit: &limit, - Page: &page, - }, - } - - usersRes, err := resolvers.UsersResolver(ctx, pagination) - assert.NotNil(t, err, "unauthorized") - assert.Nil(t, usersRes) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - usersRes, err = resolvers.UsersResolver(ctx, pagination) - assert.Nil(t, err) - rLen := len(usersRes.Users) - assert.GreaterOrEqual(t, rLen, 1) - - cleanData(email) - }) -} diff --git a/server/test/validate_jwt_token_test.go b/server/test/validate_jwt_token_test.go deleted file mode 100644 index 879cc20e4..000000000 --- a/server/test/validate_jwt_token_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package test - -import ( - "testing" - "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/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/authorizerdev/authorizer/server/token" - "github.com/authorizerdev/authorizer/server/utils" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" -) - -func validateJwtTokenTest(t *testing.T, s TestSetup) { - t.Helper() - _, ctx := createContext(s) - t.Run(`validate params`, func(t *testing.T) { - res, err := resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{ - TokenType: "access_token", - Token: "", - }) - assert.Error(t, err) - assert.Nil(t, res) - res, err = resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{ - TokenType: "access_token", - Token: "invalid", - }) - assert.Error(t, err) - assert.Nil(t, res) - _, err = resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{ - TokenType: "access_token_invalid", - Token: "invalid@invalid", - }) - assert.Error(t, err, "invalid token") - }) - - scope := []string{"openid", "email", "profile", "offline_access"} - user := &models.User{ - ID: uuid.New().String(), - Email: refs.NewStringRef("jwt_test_" + s.TestInfo.Email), - Roles: "user", - UpdatedAt: time.Now().Unix(), - CreatedAt: time.Now().Unix(), - } - - roles := []string{"user"} - gc, err := utils.GinContextFromContext(ctx) - assert.NoError(t, err) - sessionKey := constants.AuthRecipeMethodBasicAuth + ":" + user.ID - nonce := uuid.New().String() - authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth, nonce, "") - assert.NoError(t, err) - assert.NotNil(t, authToken) - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) - - if authToken.RefreshToken != nil { - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) - } - - t.Run(`should validate the access token`, func(t *testing.T) { - res, err := resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{ - TokenType: "access_token", - Token: authToken.AccessToken.Token, - Roles: []string{"user"}, - }) - assert.NoError(t, err) - assert.True(t, res.IsValid) - - res, err = resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{ - TokenType: "access_token", - Token: authToken.AccessToken.Token, - Roles: []string{"invalid_role"}, - }) - assert.Error(t, err) - assert.Nil(t, res) - }) - - t.Run(`should validate the refresh token`, func(t *testing.T) { - res, err := resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{ - TokenType: "refresh_token", - Token: authToken.RefreshToken.Token, - }) - assert.NoError(t, err) - assert.True(t, res.IsValid) - }) - - t.Run(`should validate the id token`, func(t *testing.T) { - res, err := resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{ - TokenType: "id_token", - Token: authToken.IDToken.Token, - }) - assert.NoError(t, err) - assert.True(t, res.IsValid) - assert.Equal(t, refs.StringValue(user.Email), res.Claims["email"]) - }) -} diff --git a/server/test/validate_session_test.go b/server/test/validate_session_test.go deleted file mode 100644 index 9e2cbd5c7..000000000 --- a/server/test/validate_session_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package test - -import ( - "fmt" - "strings" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/authorizerdev/authorizer/server/token" - "github.com/stretchr/testify/assert" -) - -// ValidateSessionTests tests all the validate session resolvers -func validateSessionTests(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should validate session`, func(t *testing.T) { - req, ctx := createContext(s) - email := "validate_session." + s.TestInfo.Email - - resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - _, err := resolvers.ValidateSessionResolver(ctx, &model.ValidateSessionInput{}) - assert.NotNil(t, err, "unauthorized") - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.NoError(t, err) - assert.NotNil(t, verificationRequest) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.NoError(t, err) - assert.NotNil(t, verifyRes) - accessToken := *verifyRes.AccessToken - assert.NotEmpty(t, accessToken) - claims, err := token.ParseJWTToken(accessToken) - assert.NoError(t, err) - assert.NotEmpty(t, claims) - sessionKey := constants.AuthRecipeMethodBasicAuth + ":" + verifyRes.User.ID - sessionToken, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+claims["nonce"].(string)) - assert.NoError(t, err) - assert.NotEmpty(t, sessionToken) - cookie := fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", sessionToken) - cookie = strings.TrimSuffix(cookie, ";") - res, err := resolvers.ValidateSessionResolver(ctx, &model.ValidateSessionInput{ - Cookie: sessionToken, - }) - assert.Nil(t, err) - assert.True(t, res.IsValid) - req.Header.Set("Cookie", cookie) - res, err = resolvers.ValidateSessionResolver(ctx, &model.ValidateSessionInput{}) - assert.Nil(t, err) - assert.True(t, res.IsValid) - assert.Equal(t, res.User.ID, verifyRes.User.ID) - cleanData(email) - }) -} diff --git a/server/test/validator_test.go b/server/test/validator_test.go deleted file mode 100644 index 70611a231..000000000 --- a/server/test/validator_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package test - -import ( - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/validators" - "github.com/stretchr/testify/assert" -) - -func TestIsValidEmail(t *testing.T) { - validEmail := "lakhan@gmail.com" - invalidEmail1 := "lakhan" - invalidEmail2 := "lakhan.me" - - assert.True(t, validators.IsValidEmail(validEmail), "it should be valid email") - assert.False(t, validators.IsValidEmail(invalidEmail1), "it should be invalid email") - assert.False(t, validators.IsValidEmail(invalidEmail2), "it should be invalid email") -} - -func TestIsValidOrigin(t *testing.T) { - // don't use portocal(http/https) for ALLOWED_ORIGINS while testing, - // as we trim them off while running the main function - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyAllowedOrigins, "localhost:8080,*.google.com,*.google.in,*abc.*") - assert.False(t, validators.IsValidOrigin("http://myapp.com"), "it should be invalid origin") - assert.False(t, validators.IsValidOrigin("http://appgoogle.com"), "it should be invalid origin") - assert.True(t, validators.IsValidOrigin("http://app.google.com"), "it should be valid origin") - assert.False(t, validators.IsValidOrigin("http://app.google.ind"), "it should be invalid origin") - assert.True(t, validators.IsValidOrigin("http://app.google.in"), "it should be valid origin") - assert.True(t, validators.IsValidOrigin("http://xyx.abc.com"), "it should be valid origin") - assert.True(t, validators.IsValidOrigin("http://xyx.abc.in"), "it should be valid origin") - assert.True(t, validators.IsValidOrigin("http://xyxabc.in"), "it should be valid origin") - assert.True(t, validators.IsValidOrigin("http://localhost:8080"), "it should be valid origin") - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyAllowedOrigins, "*") -} - -func TestIsValidIdentifier(t *testing.T) { - assert.False(t, validators.IsValidVerificationIdentifier("test"), "it should be invalid identifier") - assert.True(t, validators.IsValidVerificationIdentifier(constants.VerificationTypeBasicAuthSignup), "it should be valid identifier") - assert.True(t, validators.IsValidVerificationIdentifier(constants.VerificationTypeUpdateEmail), "it should be valid identifier") - assert.True(t, validators.IsValidVerificationIdentifier(constants.VerificationTypeForgotPassword), "it should be valid identifier") -} - -func TestIsValidPassword(t *testing.T) { - assert.Error(t, validators.IsValidPassword("test"), "it should be invalid password") - assert.Error(t, validators.IsValidPassword("Te@1"), "it should be invalid password") - assert.Error(t, validators.IsValidPassword("n*rp7GGTd29V{xx%{pDb@7n{](SD.!+.Mp#*$EHDGk&$pAMf7e#432Sg,Gr](j3n]jV/3F8BJJT+9u9{q=8zK:8u!rpQBaXJp%A+7r!jQj)M(vC$UX,h;;WKm$U6i#7dBnC&2ryKzKd+(y&=Ud)hErT/j;v3t..CM).8nS)9qLtV7pmP;@2QuzDyGfL7KB()k:BpjAGL@bxD%r5gcBfh7$&wutk!wzMfPFY#nkjjqyZbEHku,{jc;gvbYq2)3w=KExnYz9Vbv:;*;?f##faxkULdMpmm&yEfePixzx+[{[38zGN;3TzF;6M#Xy_tMtx:yK*n$bc(bPyGz%EYkC&]ttUF@#aZ%$QZ:u!icF@+"), "it should be invalid password") - assert.Error(t, validators.IsValidPassword("test@123"), "it should be invalid password") - assert.NoError(t, validators.IsValidPassword("Test@123"), "it should be valid password") -} diff --git a/server/test/verification_requests_test.go b/server/test/verification_requests_test.go deleted file mode 100644 index 93b464357..000000000 --- a/server/test/verification_requests_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func verificationRequestsTest(t *testing.T, s TestSetup) { - t.Helper() - - t.Run(`should get verification requests with admin secret only`, func(t *testing.T) { - req, ctx := createContext(s) - email := "verification_requests." + s.TestInfo.Email - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, res) - limit := int64(10) - page := int64(1) - pagination := &model.PaginatedInput{ - Pagination: &model.PaginationInput{ - Limit: &limit, - Page: &page, - }, - } - - requests, err := resolvers.VerificationRequestsResolver(ctx, pagination) - assert.NotNil(t, err, "unauthorized") - assert.Nil(t, requests) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.Nil(t, err) - - h, err := crypto.EncryptPassword(adminSecret) - assert.Nil(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - requests, err = resolvers.VerificationRequestsResolver(ctx, pagination) - assert.Nil(t, err) - rLen := len(requests.VerificationRequests) - assert.GreaterOrEqual(t, rLen, 1) - - cleanData(email) - }) -} diff --git a/server/test/verify_email_test.go b/server/test/verify_email_test.go deleted file mode 100644 index 19416c14c..000000000 --- a/server/test/verify_email_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package test - -import ( - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func verifyEmailTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should verify email`, func(t *testing.T) { - _, ctx := createContext(s) - email := "verify_email." + s.TestInfo.Email - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, res) - user := *res.User - assert.Equal(t, email, refs.StringValue(user.Email)) - assert.Nil(t, res.AccessToken, "access token should be nil") - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.Nil(t, err) - assert.Equal(t, email, verificationRequest.Email) - - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.Nil(t, err) - assert.NotEqual(t, verifyRes.AccessToken, "", "access token should not be empty") - // Check if phone number is verified - user1, err := db.Provider.GetUserByEmail(ctx, email) - assert.NoError(t, err) - assert.NotNil(t, user1) - assert.NotNil(t, user1.EmailVerifiedAt) - cleanData(email) - }) -} diff --git a/server/test/verify_otp_test.go b/server/test/verify_otp_test.go deleted file mode 100644 index 917505ef7..000000000 --- a/server/test/verify_otp_test.go +++ /dev/null @@ -1,204 +0,0 @@ -package test - -import ( - "bytes" - "context" - "encoding/base64" - "fmt" - "strings" - "testing" - "time" - - "github.com/gokyle/twofactor" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" - "github.com/tuotoo/qrcode" - - "github.com/authorizerdev/authorizer/server/authenticators" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/authorizerdev/authorizer/server/token" -) - -func verifyOTPTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run(`should verify otp`, func(t *testing.T) { - // Set up request and context using test setup - req, ctx := createContext(s) - email := "verify_otp." + s.TestInfo.Email - - // Test case: Setup email OTP MFA for login - { - // Sign up a user - res, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, res) - - // Attempt to login should fail as email is not verified - loginRes, err := resolvers.LoginResolver(ctx, model.LoginInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, loginRes) - assert.Nil(t, loginRes.AccessToken) - assert.NotEmpty(t, loginRes.Message) - - // Verify the email - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.Nil(t, err) - assert.Equal(t, email, verificationRequest.Email) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.Nil(t, err) - assert.NotEqual(t, verifyRes.AccessToken, "", "access token should not be empty") - - // Use access token to update the profile - s.GinContext.Request.Header.Set("Authorization", "Bearer "+refs.StringValue(verifyRes.AccessToken)) - ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMailOTPLogin, false) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableTOTPLogin, true) - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisablePhoneVerification, true) - updateProfileRes, err := resolvers.UpdateProfileResolver(ctx, model.UpdateProfileInput{ - IsMultiFactorAuthEnabled: refs.NewBoolRef(true), - }) - assert.NoError(t, err) - assert.NotEmpty(t, updateProfileRes.Message) - - // Login should not return an error, but the access token should be empty as OTP should have been sent - loginRes, err = resolvers.LoginResolver(ctx, model.LoginInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - }) - assert.NoError(t, err) - assert.NotNil(t, loginRes) - assert.Nil(t, loginRes.AccessToken) - - // Get OTP from db - otp, err := db.Provider.GetOTPByEmail(ctx, email) - assert.NoError(t, err) - assert.NotEmpty(t, otp.Otp) - - // Get user by email - user, err := db.Provider.GetUserByEmail(ctx, email) - assert.NoError(t, err) - assert.NotNil(t, user) - - // Set MFA cookie session - mfaSession := uuid.NewString() - memorystore.Provider.SetMfaSession(user.ID, mfaSession, time.Now().Add(1*time.Minute).Unix()) - cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession) - cookie = strings.TrimSuffix(cookie, ";") - req.Header.Set("Cookie", cookie) - - // Verify OTP - verifyOtpRes, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - Email: &email, - Otp: otp.Otp, - }) - assert.Nil(t, err) - assert.NotEqual(t, verifyOtpRes.AccessToken, "", "access token should not be empty") - - // Clean up data for the email - cleanData(email) - } - - // Test case: Setup TOTP MFA for signup - { - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableEmailVerification, false) - signUpRes, err := resolvers.SignupResolver(ctx, model.SignUpInput{ - Email: refs.NewStringRef(email), - Password: s.TestInfo.Password, - ConfirmPassword: s.TestInfo.Password, - }) - assert.Nil(t, err, "Expected no error but got: %v", err) - assert.Equal(t, "Verification email has been sent. Please check your inbox", signUpRes.Message) - - // Retrieve user and update for TOTP setup - user, err := db.Provider.GetUserByID(ctx, signUpRes.User.ID) - assert.Nil(t, err, "Expected no error but got: %v", err) - assert.NotNil(t, user) - - // Enable multi-factor authentication and update the user - memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableTOTPLogin, false) - user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true) - updatedUser, err := db.Provider.UpdateUser(ctx, user) - assert.Nil(t, err, "Expected no error but got: %v", err) - assert.Equal(t, true, *updatedUser.IsMultiFactorAuthEnabled) - - // Initialise totp authenticator store - authenticators.InitTOTPStore() - - // Verify an email and get TOTP response - verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup) - assert.Nil(t, err) - assert.Equal(t, email, verificationRequest.Email) - verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ - Token: verificationRequest.Token, - }) - assert.Nil(t, err, "Expected no error but got: %v", err) - assert.NotNil(t, &verifyRes) - assert.Nil(t, verifyRes.AccessToken) - assert.Equal(t, "Proceed to totp verification screen", verifyRes.Message) - assert.NotEqual(t, *verifyRes.AuthenticatorScannerImage, "", "totp url should not be empty") - assert.NotEqual(t, *verifyRes.AuthenticatorSecret, "", "totp secret should not be empty") - assert.NotNil(t, verifyRes.AuthenticatorRecoveryCodes) - - // Get TOTP URL for validation - pngBytes, err := base64.StdEncoding.DecodeString(*verifyRes.AuthenticatorScannerImage) - assert.NoError(t, err) - qrmatrix, err := qrcode.Decode(bytes.NewReader(pngBytes)) - assert.NoError(t, err) - tf, label, err := twofactor.FromURL(qrmatrix.Content) - data := strings.Split(label, ":") - assert.NoError(t, err) - assert.Equal(t, email, data[1]) - assert.NotNil(t, tf) - code := tf.OTP() - assert.NotEmpty(t, code) - - // Set mfa cookie session - mfaSession := uuid.NewString() - memorystore.Provider.SetMfaSession(signUpRes.User.ID, mfaSession, time.Now().Add(1*time.Minute).Unix()) - cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession) - cookie = strings.TrimSuffix(cookie, ";") - req.Header.Set("Cookie", cookie) - valid, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{ - Email: &email, - IsTotp: refs.NewBoolRef(true), - Otp: code, - }) - accessToken := *valid.AccessToken - assert.NoError(t, err) - assert.NotNil(t, accessToken) - assert.NotEmpty(t, valid.Message) - assert.NotEmpty(t, accessToken) - claims, err := token.ParseJWTToken(accessToken) - assert.NoError(t, err) - assert.NotEmpty(t, claims) - signUpMethod := claims["login_method"] - sessionKey := signUpRes.User.ID - if signUpMethod != nil && signUpMethod != "" { - sessionKey = signUpMethod.(string) + ":" + signUpRes.User.ID - } - sessionToken, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+claims["nonce"].(string)) - assert.NoError(t, err) - assert.NotEmpty(t, sessionToken) - cookie = fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", sessionToken) - cookie = strings.TrimSuffix(cookie, ";") - req.Header.Set("Cookie", cookie) - - // Clean up data for the email - cleanData(email) - } - }) -} diff --git a/server/test/webhook_logs_test.go b/server/test/webhook_logs_test.go deleted file mode 100644 index 25210a3af..000000000 --- a/server/test/webhook_logs_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package test - -import ( - "fmt" - "testing" - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func webhookLogsTest(t *testing.T, s TestSetup) { - time.Sleep(30 * time.Second) // add sleep for webhooklogs to get generated as they are async - t.Helper() - t.Run("should get webhook logs", func(t *testing.T) { - req, ctx := createContext(s) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.NoError(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.NoError(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - webhookLogs, err := resolvers.WebhookLogsResolver(ctx, nil) - assert.NoError(t, err) - assert.Greater(t, len(webhookLogs.WebhookLogs), 1) - - webhooks, err := resolvers.WebhooksResolver(ctx, &model.PaginatedInput{ - Pagination: &model.PaginationInput{ - Limit: refs.NewInt64Ref(20), - }, - }) - assert.NoError(t, err) - assert.NotEmpty(t, webhooks) - for _, w := range webhooks.Webhooks { - t.Run(fmt.Sprintf("should get webhook for webhook_id:%s", w.ID), func(t *testing.T) { - webhookLogs, err := resolvers.WebhookLogsResolver(ctx, &model.ListWebhookLogRequest{ - WebhookID: &w.ID, - }) - assert.NoError(t, err) - assert.GreaterOrEqual(t, len(webhookLogs.WebhookLogs), 1, refs.StringValue(w.EventName)) - for _, wl := range webhookLogs.WebhookLogs { - assert.Equal(t, refs.StringValue(wl.WebhookID), w.ID) - } - }) - } - }) -} diff --git a/server/test/webhook_test.go b/server/test/webhook_test.go deleted file mode 100644 index a556f9dd1..000000000 --- a/server/test/webhook_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func webhookTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run("should get webhook", func(t *testing.T) { - req, ctx := createContext(s) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.NoError(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.NoError(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - // get webhook by event name - webhooks, err := db.Provider.GetWebhookByEventName(ctx, constants.UserCreatedWebhookEvent) - assert.NoError(t, err) - assert.NotNil(t, webhooks) - assert.GreaterOrEqual(t, len(webhooks), 2) - for _, webhook := range webhooks { - res, err := resolvers.WebhookResolver(ctx, model.WebhookRequest{ - ID: webhook.ID, - }) - assert.NoError(t, err) - assert.Equal(t, res.ID, webhook.ID) - assert.Equal(t, refs.StringValue(res.Endpoint), refs.StringValue(webhook.Endpoint)) - // assert.Equal(t, refs.StringValue(res.EventName), refs.StringValue(webhook.EventName)) - assert.Equal(t, refs.BoolValue(res.Enabled), refs.BoolValue(webhook.Enabled)) - assert.Len(t, res.Headers, len(webhook.Headers)) - } - }) -} diff --git a/server/test/webhooks_test.go b/server/test/webhooks_test.go deleted file mode 100644 index 74cad7411..000000000 --- a/server/test/webhooks_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package test - -import ( - "fmt" - "testing" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/stretchr/testify/assert" -) - -func webhooksTest(t *testing.T, s TestSetup) { - t.Helper() - t.Run("should get webhooks", func(t *testing.T) { - req, ctx := createContext(s) - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - assert.NoError(t, err) - h, err := crypto.EncryptPassword(adminSecret) - assert.NoError(t, err) - req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h)) - - webhooks, err := resolvers.WebhooksResolver(ctx, &model.PaginatedInput{ - Pagination: &model.PaginationInput{ - Limit: refs.NewInt64Ref(20), - }, - }) - assert.NoError(t, err) - assert.NotEmpty(t, webhooks) - assert.GreaterOrEqual(t, len(webhooks.Webhooks), len(s.TestInfo.TestWebhookEventTypes)*2) - }) -} diff --git a/server/token/admin_token.go b/server/token/admin_token.go deleted file mode 100644 index 9dcbeb317..000000000 --- a/server/token/admin_token.go +++ /dev/null @@ -1,59 +0,0 @@ -package token - -import ( - "fmt" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/cookie" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/gin-gonic/gin" - "golang.org/x/crypto/bcrypt" -) - -// CreateAdminAuthToken creates the admin token based on secret key -func CreateAdminAuthToken(tokenType string, c *gin.Context) (string, error) { - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - if err != nil { - return "", err - } - return crypto.EncryptPassword(adminSecret) -} - -// GetAdminAuthToken helps in getting the admin token from the request cookie -func GetAdminAuthToken(gc *gin.Context) (string, error) { - token, err := cookie.GetAdminCookie(gc) - if err != nil || token == "" { - return "", fmt.Errorf("unauthorized") - } - - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - if err != nil { - return "", err - } - err = bcrypt.CompareHashAndPassword([]byte(token), []byte(adminSecret)) - - if err != nil { - return "", fmt.Errorf(`unauthorized`) - } - - return token, nil -} - -// IsSuperAdmin checks if user is super admin -func IsSuperAdmin(gc *gin.Context) bool { - token, err := GetAdminAuthToken(gc) - if err != nil { - secret := gc.Request.Header.Get("x-authorizer-admin-secret") - if secret == "" { - return false - } - adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) - if err != nil { - return false - } - return secret == adminSecret - } - - return token != "" -} diff --git a/server/token/jwt.go b/server/token/jwt.go deleted file mode 100644 index 4e5f0ed93..000000000 --- a/server/token/jwt.go +++ /dev/null @@ -1,166 +0,0 @@ -package token - -import ( - "errors" - - "github.com/golang-jwt/jwt" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/crypto" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -// SignJWTToken common util to sing jwt token -func SignJWTToken(claims jwt.MapClaims) (string, error) { - jwtType, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType) - if err != nil { - return "", err - } - signingMethod := jwt.GetSigningMethod(jwtType) - if signingMethod == nil { - return "", errors.New("unsupported signing method") - } - t := jwt.New(signingMethod) - if t == nil { - return "", errors.New("unsupported signing method") - } - t.Claims = claims - - switch signingMethod { - case jwt.SigningMethodHS256, jwt.SigningMethodHS384, jwt.SigningMethodHS512: - jwtSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret) - if err != nil { - return "", err - } - return t.SignedString([]byte(jwtSecret)) - case jwt.SigningMethodRS256, jwt.SigningMethodRS384, jwt.SigningMethodRS512: - jwtPrivateKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPrivateKey) - if err != nil { - return "", err - } - key, err := crypto.ParseRsaPrivateKeyFromPemStr(jwtPrivateKey) - if err != nil { - return "", err - } - return t.SignedString(key) - case jwt.SigningMethodES256, jwt.SigningMethodES384, jwt.SigningMethodES512: - jwtPrivateKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPrivateKey) - if err != nil { - return "", err - } - key, err := crypto.ParseEcdsaPrivateKeyFromPemStr(jwtPrivateKey) - if err != nil { - return "", err - } - - return t.SignedString(key) - default: - return "", errors.New("unsupported signing method") - } -} - -// ParseJWTToken common util to parse jwt token -func ParseJWTToken(token string) (jwt.MapClaims, error) { - jwtType, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType) - if err != nil { - return nil, err - } - signingMethod := jwt.GetSigningMethod(jwtType) - - var claims jwt.MapClaims - - switch signingMethod { - case jwt.SigningMethodHS256, jwt.SigningMethodHS384, jwt.SigningMethodHS512: - _, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { - jwtSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret) - if err != nil { - return nil, err - } - return []byte(jwtSecret), nil - }) - case jwt.SigningMethodRS256, jwt.SigningMethodRS384, jwt.SigningMethodRS512: - _, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { - jwtPublicKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey) - if err != nil { - return nil, err - } - key, err := crypto.ParseRsaPublicKeyFromPemStr(jwtPublicKey) - if err != nil { - return nil, err - } - return key, nil - }) - case jwt.SigningMethodES256, jwt.SigningMethodES384, jwt.SigningMethodES512: - _, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { - jwtPublicKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey) - if err != nil { - return nil, err - } - key, err := crypto.ParseEcdsaPublicKeyFromPemStr(jwtPublicKey) - if err != nil { - return nil, err - } - return key, nil - }) - default: - err = errors.New("unsupported signing method") - } - if err != nil { - return claims, err - } - - // claim parses exp & iat into float 64 with e^10, - // but we expect it to be int64 - // hence we need to assert interface and convert to int64 - intExp := int64(claims["exp"].(float64)) - intIat := int64(claims["iat"].(float64)) - claims["exp"] = intExp - claims["iat"] = intIat - - return claims, nil -} - -// ValidateJWTClaims common util to validate claims -func ValidateJWTClaims(claims jwt.MapClaims, hostname, nonce, subject string) (bool, error) { - clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) - if err != nil { - return false, err - } - if claims["aud"] != clientID { - return false, errors.New("invalid audience") - } - - if claims["nonce"] != nonce { - return false, errors.New("invalid nonce") - } - - if claims["iss"] != hostname { - return false, errors.New("invalid issuer") - } - - if claims["sub"] != subject { - return false, errors.New("invalid subject") - } - - return true, nil -} - -// ValidateJWTTokenWithoutNonce common util to validate claims without nonce -func ValidateJWTTokenWithoutNonce(claims jwt.MapClaims, hostname, subject string) (bool, error) { - clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) - if err != nil { - return false, err - } - if claims["aud"] != clientID { - return false, errors.New("invalid audience") - } - - if claims["iss"] != hostname { - return false, errors.New("invalid issuer") - } - - if claims["sub"] != subject { - return false, errors.New("invalid subject") - } - return true, nil -} diff --git a/server/token/verification_token.go b/server/token/verification_token.go deleted file mode 100644 index 75aef3063..000000000 --- a/server/token/verification_token.go +++ /dev/null @@ -1,29 +0,0 @@ -package token - -import ( - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/golang-jwt/jwt" -) - -// CreateVerificationToken creates a verification JWT token -func CreateVerificationToken(email, tokenType, hostname, nonceHash, redirectURL string) (string, error) { - clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) - if err != nil { - return "", err - } - claims := jwt.MapClaims{ - "iss": hostname, - "aud": clientID, - "sub": email, - "exp": time.Now().Add(time.Minute * 30).Unix(), - "iat": time.Now().Unix(), - "token_type": tokenType, - "nonce": nonceHash, - "redirect_uri": redirectURL, - } - - return SignJWTToken(claims) -} diff --git a/server/utils/webhook.go b/server/utils/webhook.go deleted file mode 100644 index a97f286cc..000000000 --- a/server/utils/webhook.go +++ /dev/null @@ -1,117 +0,0 @@ -package utils - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - "time" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" - "github.com/authorizerdev/authorizer/server/db/models" - "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/refs" - log "github.com/sirupsen/logrus" -) - -// RegisterEvent util to register event -// TODO change user to user ref -func RegisterEvent(ctx context.Context, eventName string, authRecipe string, user *models.User) error { - webhooks, err := db.Provider.GetWebhookByEventName(ctx, eventName) - if err != nil { - log.Debug("error getting webhook: %v", err) - return err - } - for _, webhook := range webhooks { - if !refs.BoolValue(webhook.Enabled) { - continue - } - userBytes, err := json.Marshal(user.AsAPIUser()) - if err != nil { - log.Debug("error marshalling user obj: ", err) - continue - } - userMap := map[string]interface{}{} - err = json.Unmarshal(userBytes, &userMap) - if err != nil { - log.Debug("error un-marshalling user obj: ", err) - continue - } - - reqBody := map[string]interface{}{ - "webhook_id": webhook.ID, - "event_name": eventName, - "event_description": webhook.EventDescription, - "user": userMap, - } - - if eventName == constants.UserLoginWebhookEvent || eventName == constants.UserSignUpWebhookEvent { - reqBody["auth_recipe"] = authRecipe - } - - requestBody, err := json.Marshal(reqBody) - if err != nil { - log.Debug("error marshalling requestBody obj: ", err) - continue - } - - // dont trigger webhook call in case of test - envKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEnv) - if err != nil { - continue - } - if envKey == constants.TestEnv { - _, err := db.Provider.AddWebhookLog(ctx, &models.WebhookLog{ - HttpStatus: 200, - Request: string(requestBody), - Response: string(`{"message": "test"}`), - WebhookID: webhook.ID, - }) - if err != nil { - log.Debug("error saving webhook log:", err) - } - continue - } - - requestBytesBuffer := bytes.NewBuffer(requestBody) - req, err := http.NewRequest("POST", refs.StringValue(webhook.Endpoint), requestBytesBuffer) - if err != nil { - log.Debug("error creating webhook post request: ", err) - continue - } - req.Header.Set("Content-Type", "application/json") - - for key, val := range webhook.Headers { - req.Header.Set(key, val.(string)) - } - - client := &http.Client{Timeout: time.Second * 30} - resp, err := client.Do(req) - if err != nil { - log.Debug("error making request: ", err) - continue - } - defer resp.Body.Close() - - responseBytes, err := io.ReadAll(resp.Body) - if err != nil { - log.Debug("error reading response: ", err) - continue - } - - statusCode := int64(resp.StatusCode) - _, err = db.Provider.AddWebhookLog(ctx, &models.WebhookLog{ - HttpStatus: statusCode, - Request: string(requestBody), - Response: string(responseBytes), - WebhookID: webhook.ID, - }) - if err != nil { - log.Debug("failed to add webhook log: ", err) - continue - } - } - return nil -} diff --git a/app/.prettierrc.json b/web/app/.prettierrc.json similarity index 100% rename from app/.prettierrc.json rename to web/app/.prettierrc.json diff --git a/app/README.md b/web/app/README.md similarity index 100% rename from app/README.md rename to web/app/README.md diff --git a/app/favicon_io/android-chrome-192x192.png b/web/app/favicon_io/android-chrome-192x192.png similarity index 100% rename from app/favicon_io/android-chrome-192x192.png rename to web/app/favicon_io/android-chrome-192x192.png diff --git a/app/favicon_io/android-chrome-512x512.png b/web/app/favicon_io/android-chrome-512x512.png similarity index 100% rename from app/favicon_io/android-chrome-512x512.png rename to web/app/favicon_io/android-chrome-512x512.png diff --git a/app/favicon_io/apple-touch-icon.png b/web/app/favicon_io/apple-touch-icon.png similarity index 100% rename from app/favicon_io/apple-touch-icon.png rename to web/app/favicon_io/apple-touch-icon.png diff --git a/app/favicon_io/favicon-16x16.png b/web/app/favicon_io/favicon-16x16.png similarity index 100% rename from app/favicon_io/favicon-16x16.png rename to web/app/favicon_io/favicon-16x16.png diff --git a/app/favicon_io/favicon-32x32.png b/web/app/favicon_io/favicon-32x32.png similarity index 100% rename from app/favicon_io/favicon-32x32.png rename to web/app/favicon_io/favicon-32x32.png diff --git a/app/favicon_io/favicon.ico b/web/app/favicon_io/favicon.ico similarity index 100% rename from app/favicon_io/favicon.ico rename to web/app/favicon_io/favicon.ico diff --git a/web/app/package-lock.json b/web/app/package-lock.json new file mode 100644 index 000000000..66b1784db --- /dev/null +++ b/web/app/package-lock.json @@ -0,0 +1,3099 @@ +{ + "name": "app", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "app", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@authorizerdev/authorizer-react": "^2.0.0-rc.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-is": "^18.3.1", + "react-router-dom": "^6.28.0", + "styled-components": "^6.1.13" + }, + "devDependencies": { + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@types/react-router-dom": "^5.3.3", + "@types/styled-components": "^5.1.34", + "@vitejs/plugin-react": "^4.3.1", + "prettier": "^3.3.3", + "typescript": "^5.6.3", + "vite": "^7.3.0" + } + }, + "node_modules/@authorizerdev/authorizer-js": { + "version": "3.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-3.0.0-rc.1.tgz", + "integrity": "sha512-tTY6NQJ7W00TjoJJSQXRqTi3mhz8z/epRH1lE0S9jM7EMxCQ4FCSbRLJ7nd2mxch3ORHRx9GIq8UkH+VHsCLxA==", + "license": "MIT", + "dependencies": { + "cross-fetch": "^3.1.5" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/authorizerdev" + } + }, + "node_modules/@authorizerdev/authorizer-react": { + "version": "2.0.0-rc.2", + "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-2.0.0-rc.2.tgz", + "integrity": "sha512-Uwb2pzK7DevXebK7nbkezv/3QeMy2l2KoNGlEP7a9Y4Z5Gx+ZhhNGRqdx4w8UiEQdEkAieJkH3JnZxJMuusoNQ==", + "license": "MIT", + "dependencies": { + "@authorizerdev/authorizer-js": "3.0.0-rc.1", + "@storybook/preset-scss": "^1.0.3", + "validator": "^13.11.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.1.tgz", + "integrity": "sha512-vDbaOzF7yT2Qs4vO6XV1MHcJv+3dgR1sT+l3B8xxOVhUC336prMvqrvsLL/9Dnw2xr6Qhz4J0dmS0llNAbnUmQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz", + "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz", + "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz", + "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz", + "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz", + "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz", + "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz", + "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz", + "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz", + "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz", + "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz", + "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz", + "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz", + "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz", + "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz", + "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz", + "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz", + "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz", + "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz", + "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz", + "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz", + "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz", + "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@storybook/preset-scss": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@storybook/preset-scss/-/preset-scss-1.0.3.tgz", + "integrity": "sha512-o9Iz6wxPeNENrQa2mKlsDKynBfqU2uWaRP80HeWp4TkGgf7/x3DVF2O7yi9N0x/PI1qzzTTpxlQ90D62XmpiTw==", + "license": "MIT", + "peerDependencies": { + "css-loader": "*", + "sass-loader": "*", + "style-loader": "*" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dev": true, + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.0.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz", + "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.4", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.3.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz", + "integrity": "sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg==", + "dev": true, + "dependencies": { + "@types/history": "*", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/styled-components": { + "version": "5.1.36", + "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.36.tgz", + "integrity": "sha512-pGMRNY5G2rNDKEv2DOiFYa7Ft1r0jrhmgBwHhOMzPTgCjO76bCot0/4uEfqj7K0Jf1KdQmDtAuaDk9EAs9foSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hoist-non-react-statics": "*", + "@types/react": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/stylis": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", + "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.11", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", + "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001762", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz", + "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-loader": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", + "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.4", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", + "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dev": true, + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loader-runner": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "license": "MIT", + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/prettier": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.30.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.2.tgz", + "integrity": "sha512-H2Bm38Zu1bm8KUE5NVWRMzuIyAV8p/JrOaBJAwVmp37AXG72+CZJlEBw6pdn9i5TBgLMhNDgijS4ZlblpHyWTA==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.2.tgz", + "integrity": "sha512-l2OwHn3UUnEVUqc6/1VMmR1cvZryZ3j3NzapC2eUXO1dB0sYp5mvwdjiXhpUbRb21eFow3qSxpP8Yv6oAU824Q==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.1", + "react-router": "6.30.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz", + "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.54.0", + "@rollup/rollup-android-arm64": "4.54.0", + "@rollup/rollup-darwin-arm64": "4.54.0", + "@rollup/rollup-darwin-x64": "4.54.0", + "@rollup/rollup-freebsd-arm64": "4.54.0", + "@rollup/rollup-freebsd-x64": "4.54.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", + "@rollup/rollup-linux-arm-musleabihf": "4.54.0", + "@rollup/rollup-linux-arm64-gnu": "4.54.0", + "@rollup/rollup-linux-arm64-musl": "4.54.0", + "@rollup/rollup-linux-loong64-gnu": "4.54.0", + "@rollup/rollup-linux-ppc64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-musl": "4.54.0", + "@rollup/rollup-linux-s390x-gnu": "4.54.0", + "@rollup/rollup-linux-x64-gnu": "4.54.0", + "@rollup/rollup-linux-x64-musl": "4.54.0", + "@rollup/rollup-openharmony-arm64": "4.54.0", + "@rollup/rollup-win32-arm64-msvc": "4.54.0", + "@rollup/rollup-win32-ia32-msvc": "4.54.0", + "@rollup/rollup-win32-x64-gnu": "4.54.0", + "@rollup/rollup-win32-x64-msvc": "4.54.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/sass-loader": { + "version": "16.0.6", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.6.tgz", + "integrity": "sha512-sglGzId5gmlfxNs4gK2U3h7HlVRfx278YK6Ono5lwzuvi1jxig80YiuHkaDBVsYIKFhx8wN7XSCI0M2IDS/3qA==", + "license": "MIT", + "peer": true, + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/style-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", + "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.27.0" + } + }, + "node_modules/styled-components": { + "version": "6.1.19", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.19.tgz", + "integrity": "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.2.2", + "@emotion/unitless": "0.8.1", + "@types/stylis": "4.2.5", + "css-to-react-native": "3.2.0", + "csstype": "3.1.3", + "postcss": "8.4.49", + "shallowequal": "1.1.0", + "stylis": "4.3.2", + "tslib": "2.6.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/stylis": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser": { + "version": "5.44.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz", + "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.16", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", + "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/validator": { + "version": "13.15.26", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", + "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vite": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", + "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/watchpack": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.0.tgz", + "integrity": "sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==", + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/webpack": { + "version": "5.104.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz", + "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.4", + "es-module-lexer": "^2.0.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.3.1", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.4.4", + "webpack-sources": "^3.3.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-sources": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/web/app/package.json b/web/app/package.json new file mode 100644 index 000000000..58a5a4270 --- /dev/null +++ b/web/app/package.json @@ -0,0 +1,33 @@ +{ + "name": "app", + "version": "1.0.0", + "description": "", + "type": "module", + "scripts": { + "dev": "vite build --watch", + "build": "vite build", + "preview": "vite preview", + "format": "prettier --write 'src/**/*.(ts|tsx|js|jsx)'" + }, + "keywords": [], + "author": "Lakhan Samani", + "license": "ISC", + "dependencies": { + "@authorizerdev/authorizer-react": "^2.0.0-rc.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-is": "^18.3.1", + "react-router-dom": "^6.28.0", + "styled-components": "^6.1.13" + }, + "devDependencies": { + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@types/react-router-dom": "^5.3.3", + "@types/styled-components": "^5.1.34", + "@vitejs/plugin-react": "^4.3.1", + "prettier": "^3.3.3", + "typescript": "^5.6.3", + "vite": "^7.3.0" + } +} diff --git a/app/src/App.tsx b/web/app/src/App.tsx similarity index 98% rename from app/src/App.tsx rename to web/app/src/App.tsx index 9b4f8b547..281f6f247 100644 --- a/app/src/App.tsx +++ b/web/app/src/App.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { BrowserRouter } from 'react-router-dom'; import { AuthorizerProvider } from '@authorizerdev/authorizer-react'; import Root from './Root'; diff --git a/app/src/Root.tsx b/web/app/src/Root.tsx similarity index 70% rename from app/src/Root.tsx rename to web/app/src/Root.tsx index 11e42546a..56a04c98a 100644 --- a/app/src/Root.tsx +++ b/web/app/src/Root.tsx @@ -1,29 +1,14 @@ -import React, { useEffect, lazy, Suspense } from 'react'; -import { Switch, Route } from 'react-router-dom'; +import { useEffect, lazy, Suspense } from 'react'; +import { Routes, Route } from 'react-router-dom'; import { useAuthorizer } from '@authorizerdev/authorizer-react'; -import styled, { ThemeProvider } from 'styled-components'; import SetupPassword from './pages/setup-password'; import { hasWindow, createRandomString } from './utils/common'; -import { theme } from './theme'; const ResetPassword = lazy(() => import('./pages/rest-password')); const Login = lazy(() => import('./pages/login')); const Dashboard = lazy(() => import('./pages/dashboard')); const SignUp = lazy(() => import('./pages/signup')); -const Wrapper = styled.div` - font-family: ${(props) => props.theme.fonts.fontStack}; - color: ${(props) => props.theme.colors.textColor}; - font-size: ${(props) => props.theme.fonts.mediumText}; - box-sizing: border-box; - - *, - *:before, - *:after { - box-sizing: inherit; - } -`; - export default function Root({ globalState, }: { @@ -97,35 +82,21 @@ export default function Root({ if (token) { return ( }> - - - - - + + } /> + ); } return ( }> - - - - - - - - - - - - - - - - - - + + } /> + } /> + } /> + } /> + ); } diff --git a/app/src/index.css b/web/app/src/index.css similarity index 65% rename from app/src/index.css rename to web/app/src/index.css index c86863c54..b43f92ee1 100644 --- a/app/src/index.css +++ b/web/app/src/index.css @@ -1,8 +1,8 @@ body { margin: 10; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: + -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', + 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #374151; @@ -16,7 +16,7 @@ body { } .container { - box-sizing: content-box; + box-sizing: border-box; border: 1px solid #d1d5db; padding: 25px 20px; border-radius: 5px; diff --git a/web/app/src/index.tsx b/web/app/src/index.tsx new file mode 100644 index 000000000..6561a41be --- /dev/null +++ b/web/app/src/index.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; +import './index.css'; +import '@authorizerdev/authorizer-react/styles.css'; + +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement, +); +root.render( + + + , +); diff --git a/app/src/pages/dashboard.tsx b/web/app/src/pages/dashboard.tsx similarity index 100% rename from app/src/pages/dashboard.tsx rename to web/app/src/pages/dashboard.tsx diff --git a/app/src/pages/login.tsx b/web/app/src/pages/login.tsx similarity index 100% rename from app/src/pages/login.tsx rename to web/app/src/pages/login.tsx diff --git a/app/src/pages/rest-password.tsx b/web/app/src/pages/rest-password.tsx similarity index 100% rename from app/src/pages/rest-password.tsx rename to web/app/src/pages/rest-password.tsx diff --git a/app/src/pages/setup-password.tsx b/web/app/src/pages/setup-password.tsx similarity index 100% rename from app/src/pages/setup-password.tsx rename to web/app/src/pages/setup-password.tsx diff --git a/app/src/pages/signup.tsx b/web/app/src/pages/signup.tsx similarity index 100% rename from app/src/pages/signup.tsx rename to web/app/src/pages/signup.tsx diff --git a/web/app/src/styled.d.ts b/web/app/src/styled.d.ts new file mode 100644 index 000000000..1daffa540 --- /dev/null +++ b/web/app/src/styled.d.ts @@ -0,0 +1,26 @@ +import 'styled-components'; + +declare module 'styled-components' { + export interface DefaultTheme { + colors: { + primary: string; + primaryDisabled: string; + gray: string; + danger: string; + success: string; + textColor: string; + }; + fonts: { + fontStack: string; + largeText: string; + mediumText: string; + smallText: string; + tinyText: string; + }; + radius: { + card: string; + button: string; + input: string; + }; + } +} diff --git a/app/src/theme.ts b/web/app/src/theme.ts similarity index 100% rename from app/src/theme.ts rename to web/app/src/theme.ts diff --git a/app/src/utils/common.ts b/web/app/src/utils/common.ts similarity index 100% rename from app/src/utils/common.ts rename to web/app/src/utils/common.ts diff --git a/dashboard/tsconfig.json b/web/app/tsconfig.json similarity index 77% rename from dashboard/tsconfig.json rename to web/app/tsconfig.json index ad505d2ed..d6d92a54e 100644 --- a/dashboard/tsconfig.json +++ b/web/app/tsconfig.json @@ -1,15 +1,21 @@ { + "include": ["src/**/*"], + "exclude": ["node_modules", "build", "dist"], "compilerOptions": { /* Visit https://aka.ms/tsconfig.json to read more about this file */ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */, - "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, - // "lib": ["es2018", "dom"], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ + "target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */, + "module": "ESNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + "lib": [ + "ES2020", + "DOM", + "DOM.Iterable" + ] /* Specify library files to be included in the compilation. */, + "allowJs": true /* Allow javascript files to be compiled. */, // "checkJs": true, /* Report errors in .js files. */ - "jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */, + "jsx": "react-jsx" /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */, // "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */ @@ -19,10 +25,10 @@ // "composite": true, /* Enable project compilation */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ + "noEmit": true /* Do not emit outputs. */, // "importHelpers": true, /* Import emit helpers from 'tslib'. */ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + "isolatedModules": true /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */, /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */, @@ -44,13 +50,15 @@ // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ /* Module Resolution Options */ - // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + "moduleResolution": "bundler" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, + "baseUrl": "." /* Base directory to resolve non-absolute module names. */, + "paths": { + "@/*": ["./src/*"] + } /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */, // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */, "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ @@ -67,7 +75,6 @@ /* Advanced Options */ "skipLibCheck": true /* Skip type checking of declaration files. */, - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "lib": ["esnext", "dom"] + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ } } diff --git a/web/app/vite.config.ts b/web/app/vite.config.ts new file mode 100644 index 000000000..1aa676c97 --- /dev/null +++ b/web/app/vite.config.ts @@ -0,0 +1,28 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build', + emptyOutDir: true, + rollupOptions: { + input: { + main: 'src/index.tsx', + }, + output: { + entryFileNames: 'index.js', + chunkFileNames: 'chunk-[name]-[hash].js', + assetFileNames: (assetInfo) => { + // Name all CSS files as index.css (since cssCodeSplit is false, there's only one) + if (assetInfo.name && assetInfo.name.includes('.css')) { + return 'index.css'; + } + return 'assets/[name]-[hash][extname]'; + }, + }, + }, + cssCodeSplit: false, // Ensure CSS is in a single file + }, +}); diff --git a/dashboard/.prettierrc.json b/web/dashboard/.prettierrc.json similarity index 100% rename from dashboard/.prettierrc.json rename to web/dashboard/.prettierrc.json diff --git a/dashboard/README.md b/web/dashboard/README.md similarity index 100% rename from dashboard/README.md rename to web/dashboard/README.md diff --git a/dashboard/favicon_io/android-chrome-192x192.png b/web/dashboard/favicon_io/android-chrome-192x192.png similarity index 100% rename from dashboard/favicon_io/android-chrome-192x192.png rename to web/dashboard/favicon_io/android-chrome-192x192.png diff --git a/dashboard/favicon_io/android-chrome-512x512.png b/web/dashboard/favicon_io/android-chrome-512x512.png similarity index 100% rename from dashboard/favicon_io/android-chrome-512x512.png rename to web/dashboard/favicon_io/android-chrome-512x512.png diff --git a/dashboard/favicon_io/apple-touch-icon.png b/web/dashboard/favicon_io/apple-touch-icon.png similarity index 100% rename from dashboard/favicon_io/apple-touch-icon.png rename to web/dashboard/favicon_io/apple-touch-icon.png diff --git a/dashboard/favicon_io/favicon-16x16.png b/web/dashboard/favicon_io/favicon-16x16.png similarity index 100% rename from dashboard/favicon_io/favicon-16x16.png rename to web/dashboard/favicon_io/favicon-16x16.png diff --git a/dashboard/favicon_io/favicon-32x32.png b/web/dashboard/favicon_io/favicon-32x32.png similarity index 100% rename from dashboard/favicon_io/favicon-32x32.png rename to web/dashboard/favicon_io/favicon-32x32.png diff --git a/dashboard/favicon_io/favicon.ico b/web/dashboard/favicon_io/favicon.ico similarity index 100% rename from dashboard/favicon_io/favicon.ico rename to web/dashboard/favicon_io/favicon.ico diff --git a/web/dashboard/package-lock.json b/web/dashboard/package-lock.json new file mode 100644 index 000000000..a4308d66d --- /dev/null +++ b/web/dashboard/package-lock.json @@ -0,0 +1,3055 @@ +{ + "name": "dashboard", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dashboard", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@chakra-ui/icons": "^2.1.2", + "@chakra-ui/react": "^2.9.2", + "@emotion/react": "^11.13.5", + "@emotion/styled": "^11.13.5", + "@urql/core": "^4.2.2", + "dayjs": "^1.11.13", + "focus-visible": "^5.2.1", + "framer-motion": "^11.11.17", + "graphql": "^16.9.0", + "lodash": "^4.17.21", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-draft-wysiwyg": "^1.15.0", + "react-dropzone": "^14.3.8", + "react-email-editor": "^1.7.11", + "react-icons": "^5.5.0", + "react-router-dom": "^7.0.2", + "urql": "^4.2.2" + }, + "devDependencies": { + "@types/lodash": "^4.17.7", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@types/react-email-editor": "^1.7.0", + "@types/react-router-dom": "^5.3.3", + "@vitejs/plugin-react": "^4.3.1", + "prettier": "^3.3.3", + "typescript": "^5.6.3", + "vite": "^7.3.0" + } + }, + "node_modules/@0no-co/graphql.web": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.1.2.tgz", + "integrity": "sha512-N2NGsU5FLBhT8NZ+3l2YrzZSHITjNXNuDhC4iDiikv0IujaJ0Xc6xIxQZ/Ek3Cb+rgPjnLHYyJm11tInuJn+cw==", + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" + }, + "peerDependenciesMeta": { + "graphql": { + "optional": true + } + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@chakra-ui/anatomy": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@chakra-ui/anatomy/-/anatomy-2.3.6.tgz", + "integrity": "sha512-TjmjyQouIZzha/l8JxdBZN1pKZTj7sLpJ0YkFnQFyqHcbfWggW9jKWzY1E0VBnhtFz/xF3KC6UAVuZVSJx+y0g==" + }, + "node_modules/@chakra-ui/hooks": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@chakra-ui/hooks/-/hooks-2.4.4.tgz", + "integrity": "sha512-+gMwLIkabtddIL/GICU7JmnYtvfONP+fNiTfdYLV9/I1eyCz8igKgLmFJOGM6F+BpUev6hh+/+DX5ezGQ9VTbQ==", + "dependencies": { + "@chakra-ui/utils": "2.2.4", + "@zag-js/element-size": "0.31.1", + "copy-to-clipboard": "3.3.3", + "framesync": "6.1.2" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@chakra-ui/icons": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@chakra-ui/icons/-/icons-2.2.4.tgz", + "integrity": "sha512-l5QdBgwrAg3Sc2BRqtNkJpfuLw/pWRDwwT58J6c4PqQT6wzXxyNa8Q0PForu1ltB5qEiFb1kxr/F/HO1EwNa6g==", + "peerDependencies": { + "@chakra-ui/react": ">=2.0.0", + "react": ">=18" + } + }, + "node_modules/@chakra-ui/react": { + "version": "2.10.7", + "resolved": "https://registry.npmjs.org/@chakra-ui/react/-/react-2.10.7.tgz", + "integrity": "sha512-GX1dCmnvrxxyZEofDX9GMAtRakZJKnUqFM9k8qhaycPaeyfkiTNNTjhPNX917hgVx1yhC3kcJOs5IeC7yW56/g==", + "peer": true, + "dependencies": { + "@chakra-ui/hooks": "2.4.4", + "@chakra-ui/styled-system": "2.12.2", + "@chakra-ui/theme": "3.4.8", + "@chakra-ui/utils": "2.2.4", + "@popperjs/core": "^2.11.8", + "@zag-js/focus-visible": "^0.31.1", + "aria-hidden": "^1.2.3", + "react-fast-compare": "3.2.2", + "react-focus-lock": "^2.9.6", + "react-remove-scroll": "^2.5.7" + }, + "peerDependencies": { + "@emotion/react": ">=11", + "@emotion/styled": ">=11", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@chakra-ui/styled-system": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/@chakra-ui/styled-system/-/styled-system-2.12.2.tgz", + "integrity": "sha512-BlQ7i3+GYC0S0c72B+paa0sYo+QeNSMfz6fwQRFsc8A5Aax9i9lSdRL+vwJVC+k6r/0HWfRwk016R2RD2ihEwQ==", + "peer": true, + "dependencies": { + "@chakra-ui/utils": "2.2.4", + "csstype": "^3.1.2" + } + }, + "node_modules/@chakra-ui/theme": { + "version": "3.4.8", + "resolved": "https://registry.npmjs.org/@chakra-ui/theme/-/theme-3.4.8.tgz", + "integrity": "sha512-ZLMP2Gek38ZTIlj+sMZLsd1TW27yVdmUKMfBmjsr1psAeOa5bDBLKDszICjhEqk7gAbiWB7jr1/HzBXid4kduQ==", + "dependencies": { + "@chakra-ui/anatomy": "2.3.6", + "@chakra-ui/theme-tools": "2.2.8", + "@chakra-ui/utils": "2.2.4" + }, + "peerDependencies": { + "@chakra-ui/styled-system": ">=2.8.0" + } + }, + "node_modules/@chakra-ui/theme-tools": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@chakra-ui/theme-tools/-/theme-tools-2.2.8.tgz", + "integrity": "sha512-X2i2qgkG+k3DQfh/adn3zzM4Ty8QrGobVPjMl9rMrEYq3ac+pur6KVdVHy/SwwoPvB6S4i84uq7y35+KbJan9g==", + "dependencies": { + "@chakra-ui/anatomy": "2.3.6", + "@chakra-ui/utils": "2.2.4", + "color2k": "^2.0.2" + }, + "peerDependencies": { + "@chakra-ui/styled-system": ">=2.0.0" + } + }, + "node_modules/@chakra-ui/utils": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@chakra-ui/utils/-/utils-2.2.4.tgz", + "integrity": "sha512-nRpR9SnX7aLcJx7lKu8kgQWxdJso1oR/78HcBI+mzidvWdTykbTGdm5Q2R7S0PVH1IFBzBTgi6TiAjHvu96auA==", + "dependencies": { + "@types/lodash.mergewith": "4.6.9", + "lodash.mergewith": "4.6.2" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + }, + "node_modules/@emotion/styled": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz", + "integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz", + "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz", + "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz", + "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz", + "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz", + "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz", + "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz", + "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz", + "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz", + "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz", + "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz", + "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz", + "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz", + "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz", + "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz", + "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz", + "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz", + "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz", + "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz", + "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz", + "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz", + "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz", + "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.17.16", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", + "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==" + }, + "node_modules/@types/lodash.mergewith": { + "version": "4.6.9", + "resolved": "https://registry.npmjs.org/@types/lodash.mergewith/-/lodash.mergewith-4.6.9.tgz", + "integrity": "sha512-fgkoCAOF47K7sxrQ7Mlud2TH023itugZs2bUg8h/KzT+BnZNrR2jAOmaokbLunHNnobXVWOezAeNn/lZqwxkcw==", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/react-email-editor": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@types/react-email-editor/-/react-email-editor-1.7.0.tgz", + "integrity": "sha512-27b9gZr9h5yYWISkQVqKV8LQoW4njDjGceIYfYlUHkd7IeAG9bmdusRE4MN0IqlRQR6kyq5qIksEAXtPl1gMEw==", + "deprecated": "This is a stub types definition. react-email-editor provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "react-email-editor": "*" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.17", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz", + "integrity": "sha512-RNSXOyb3VyRs/EOGmjBhhGKTbnN6fHWvy5FNLzWfOWOGjgVUKqJZXfpKzLmgoU8h6Hj8mpALj/mbXQASOb92wQ==", + "dev": true, + "dependencies": { + "@types/history": "*", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@urql/core": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@urql/core/-/core-4.3.0.tgz", + "integrity": "sha512-wT+FeL8DG4x5o6RfHEnONNFVDM3616ouzATMYUClB6CB+iIu2mwfBKd7xSUxYOZmwtxna5/hDRQdMl3nbQZlnw==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.0.1", + "wonka": "^6.3.2" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@zag-js/dom-query": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@zag-js/dom-query/-/dom-query-0.31.1.tgz", + "integrity": "sha512-oiuohEXAXhBxpzzNm9k2VHGEOLC1SXlXSbRPcfBZ9so5NRQUA++zCE7cyQJqGLTZR0t3itFLlZqDbYEXRrefwg==" + }, + "node_modules/@zag-js/element-size": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@zag-js/element-size/-/element-size-0.31.1.tgz", + "integrity": "sha512-4T3yvn5NqqAjhlP326Fv+w9RqMIBbNN9H72g5q2ohwzhSgSfZzrKtjL4rs9axY/cw9UfMfXjRjEE98e5CMq7WQ==" + }, + "node_modules/@zag-js/focus-visible": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@zag-js/focus-visible/-/focus-visible-0.31.1.tgz", + "integrity": "sha512-dbLksz7FEwyFoANbpIlNnd3bVm0clQSUsnP8yUVQucStZPsuWjCrhL2jlAbGNrTrahX96ntUMXHb/sM68TibFg==", + "dependencies": { + "@zag-js/dom-query": "0.31.1" + } + }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "node_modules/attr-accept": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz", + "integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.11", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", + "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001762", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz", + "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + }, + "node_modules/color2k": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/color2k/-/color2k-2.0.3.tgz", + "integrity": "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog==" + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "engines": { + "node": ">=18" + } + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/core-js": { + "version": "3.33.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.33.2.tgz", + "integrity": "sha512-XeBzWI6QL3nJQiHmdzbAOiMYqjrb7hwU7A39Qhvd/POSa/t9E1AeZyEZx3fNvp/vtM8zXwhoL0FsiS0hD0pruQ==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" + }, + "node_modules/draft-js": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.11.7.tgz", + "integrity": "sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg==", + "peer": true, + "dependencies": { + "fbjs": "^2.0.0", + "immutable": "~3.7.4", + "object-assign": "^4.1.1" + }, + "peerDependencies": { + "react": ">=0.14.0", + "react-dom": ">=0.14.0" + } + }, + "node_modules/draft-js/node_modules/immutable": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", + "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/draftjs-utils": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz", + "integrity": "sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg==", + "peerDependencies": { + "draft-js": "^0.11.x", + "immutable": "3.x.x || 4.x.x" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, + "license": "ISC" + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fbjs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz", + "integrity": "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ==", + "dependencies": { + "core-js": "^3.6.4", + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "node_modules/fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-selector": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.2.tgz", + "integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==", + "dependencies": { + "tslib": "^2.7.0" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "node_modules/focus-lock": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-1.3.6.tgz", + "integrity": "sha512-Ik/6OCk9RQQ0T5Xw+hKNLWrjSMtv51dD4GRmJjbD5a58TIEpI5a5iXagKVl3Z5UuyslMCA8Xwnu76jQob62Yhg==", + "dependencies": { + "tslib": "^2.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/focus-visible": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/focus-visible/-/focus-visible-5.2.1.tgz", + "integrity": "sha512-8Bx950VD1bWTQJEH/AM6SpEk+SU55aVnp4Ujhuuxy3eMEBCRwBnTBnVXr9YAPvZL3/CNjCa8u4IWfNmEO53whA==" + }, + "node_modules/framer-motion": { + "version": "11.18.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", + "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", + "license": "MIT", + "peer": true, + "dependencies": { + "motion-dom": "^11.18.1", + "motion-utils": "^11.18.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/framesync": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.1.2.tgz", + "integrity": "sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==", + "dependencies": { + "tslib": "2.4.0" + } + }, + "node_modules/framesync/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/graphql": { + "version": "16.11.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", + "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/html-to-draftjs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/html-to-draftjs/-/html-to-draftjs-1.5.0.tgz", + "integrity": "sha512-kggLXBNciKDwKf+KYsuE+V5gw4dZ7nHyGMX9m0wy7urzWjKGWyNFetmArRLvRV0VrxKN70WylFsJvMTJx02OBQ==", + "peerDependencies": { + "draft-js": "^0.10.x || ^0.11.x", + "immutable": "3.x.x || 4.x.x" + } + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "peer": true + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/motion-dom": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", + "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "license": "MIT", + "dependencies": { + "motion-utils": "^11.18.1" + } + }, + "node_modules/motion-utils": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-clientside-effect": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.7.tgz", + "integrity": "sha512-gce9m0Pk/xYYMEojRI9bgvqQAkl6hm7ozQvqWPyQx+kULiatdHgkNM1QG4DQRx5N9BAzWSCJmt9mMV8/KsdgVg==", + "dependencies": { + "@babel/runtime": "^7.12.13" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-draft-wysiwyg": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/react-draft-wysiwyg/-/react-draft-wysiwyg-1.15.0.tgz", + "integrity": "sha512-p1cYZcWc6/ALFBVksbFoCM3b29fGQDlZLIMrXng0TU/UElxIOF2/AWWo4L5auIYVhmqKTZ0NkNjnXOzGGuxyeA==", + "dependencies": { + "classnames": "^2.2.6", + "draftjs-utils": "^0.10.2", + "html-to-draftjs": "^1.5.0", + "linkify-it": "^2.2.0", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "draft-js": "^0.10.x || ^0.11.x", + "immutable": "3.x.x || 4.x.x", + "react": "0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x", + "react-dom": "0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x" + } + }, + "node_modules/react-dropzone": { + "version": "14.3.8", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.3.8.tgz", + "integrity": "sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==", + "dependencies": { + "attr-accept": "^2.2.4", + "file-selector": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, + "node_modules/react-email-editor": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/react-email-editor/-/react-email-editor-1.7.11.tgz", + "integrity": "sha512-AyoKKtMEPhKdqUxFX1hyJMvEO+E5fzk88uNVGHhK1ymhLpcghYLkz1+pXKLcByjR6LHkfEbrCmoYFG8zyripug==", + "dependencies": { + "unlayer-types": "latest" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, + "node_modules/react-focus-lock": { + "version": "2.13.6", + "resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.13.6.tgz", + "integrity": "sha512-ehylFFWyYtBKXjAO9+3v8d0i+cnc1trGS0vlTGhzFW1vbFXVUTmR8s2tt/ZQG8x5hElg6rhENlLG1H3EZK0Llg==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "focus-lock": "^1.3.6", + "prop-types": "^15.6.2", + "react-clientside-effect": "^1.2.7", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-icons": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", + "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", + "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz", + "integrity": "sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.0.tgz", + "integrity": "sha512-DYgm6RDEuKdopSyGOWZGtDfSm7Aofb8CCzgkliTjtu/eDuB0gcsv6qdFhhi8HdtmA+KHkt5MfZ5K2PdzjugYsA==", + "dependencies": { + "react-router": "7.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz", + "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.54.0", + "@rollup/rollup-android-arm64": "4.54.0", + "@rollup/rollup-darwin-arm64": "4.54.0", + "@rollup/rollup-darwin-x64": "4.54.0", + "@rollup/rollup-freebsd-arm64": "4.54.0", + "@rollup/rollup-freebsd-x64": "4.54.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", + "@rollup/rollup-linux-arm-musleabihf": "4.54.0", + "@rollup/rollup-linux-arm64-gnu": "4.54.0", + "@rollup/rollup-linux-arm64-musl": "4.54.0", + "@rollup/rollup-linux-loong64-gnu": "4.54.0", + "@rollup/rollup-linux-ppc64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-musl": "4.54.0", + "@rollup/rollup-linux-s390x-gnu": "4.54.0", + "@rollup/rollup-linux-x64-gnu": "4.54.0", + "@rollup/rollup-linux-x64-musl": "4.54.0", + "@rollup/rollup-openharmony-arm64": "4.54.0", + "@rollup/rollup-win32-arm64-msvc": "4.54.0", + "@rollup/rollup-win32-ia32-msvc": "4.54.0", + "@rollup/rollup-win32-x64-gnu": "4.54.0", + "@rollup/rollup-win32-x64-msvc": "4.54.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==" + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.40", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.40.tgz", + "integrity": "sha512-us1E3K+3jJppDBa3Tl0L3MOJiGhe1C6P0+nIvQAFYbxlMAx0h81eOwLmU57xgqToduDDPx3y5QsdjPfDu+FgOQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, + "node_modules/unlayer-types": { + "version": "1.259.0", + "resolved": "https://registry.npmjs.org/unlayer-types/-/unlayer-types-1.259.0.tgz", + "integrity": "sha512-u5XYqhyOXESMQcgaS3SgzQgpoJOGIHU8wu0KPkMtVRfeuvcJOinomy6reqxN03tlsSt/u33OGY5z3ijFWVTlXA==" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/urql": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/urql/-/urql-4.2.2.tgz", + "integrity": "sha512-3GgqNa6iF7bC4hY/ImJKN4REQILcSU9VKcKL8gfELZM8mM5BnLH1BsCc8kBdnVGD1LIFOs4W3O2idNHhON1r0w==", + "dependencies": { + "@urql/core": "^5.1.1", + "wonka": "^6.3.2" + }, + "peerDependencies": { + "@urql/core": "^5.0.0", + "react": ">= 16.8.0" + } + }, + "node_modules/urql/node_modules/@urql/core": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.2.0.tgz", + "integrity": "sha512-/n0ieD0mvvDnVAXEQgX/7qJiVcvYvNkOHeBvkwtylfjydar123caCXcl58PXFY11oU1oquJocVXHxLAbtv4x1A==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.0.13", + "wonka": "^6.3.2" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/vite": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", + "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wonka": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.5.tgz", + "integrity": "sha512-SSil+ecw6B4/Dm7Pf2sAshKQ5hWFvfyGlfPbEd6A14dOH6VDjrmbY86u6nZvy9omGwwIPFR8V41+of1EezgoUw==" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/web/dashboard/package.json b/web/dashboard/package.json new file mode 100644 index 000000000..3b6e7ca8c --- /dev/null +++ b/web/dashboard/package.json @@ -0,0 +1,46 @@ +{ + "name": "dashboard", + "version": "1.0.0", + "description": "", + "type": "module", + "scripts": { + "dev": "vite build --watch", + "build": "vite build", + "preview": "vite preview", + "format": "prettier --write --use-tabs 'src/**/*.(ts|tsx|js|jsx)'" + }, + "keywords": [], + "author": "Lakhan Samani", + "license": "ISC", + "dependencies": { + "@chakra-ui/icons": "^2.1.2", + "@chakra-ui/react": "^2.9.2", + "@emotion/react": "^11.13.5", + "@emotion/styled": "^11.13.5", + "@urql/core": "^4.2.2", + "dayjs": "^1.11.13", + "focus-visible": "^5.2.1", + "framer-motion": "^11.11.17", + "graphql": "^16.9.0", + "lodash": "^4.17.21", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-draft-wysiwyg": "^1.15.0", + "react-dropzone": "^14.3.8", + "react-email-editor": "^1.7.11", + "react-icons": "^5.5.0", + "react-router-dom": "^7.0.2", + "urql": "^4.2.2" + }, + "devDependencies": { + "@types/lodash": "^4.17.7", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@types/react-email-editor": "^1.7.0", + "@types/react-router-dom": "^5.3.3", + "@vitejs/plugin-react": "^4.3.1", + "prettier": "^3.3.3", + "typescript": "^5.6.3", + "vite": "^7.3.0" + } +} diff --git a/dashboard/public/roblox.png b/web/dashboard/public/roblox.png similarity index 100% rename from dashboard/public/roblox.png rename to web/dashboard/public/roblox.png diff --git a/dashboard/public/sample.csv b/web/dashboard/public/sample.csv similarity index 100% rename from dashboard/public/sample.csv rename to web/dashboard/public/sample.csv diff --git a/dashboard/src/App.tsx b/web/dashboard/src/App.tsx similarity index 91% rename from dashboard/src/App.tsx rename to web/dashboard/src/App.tsx index f7a4afe99..ea1d0c85b 100644 --- a/dashboard/src/App.tsx +++ b/web/dashboard/src/App.tsx @@ -3,6 +3,7 @@ import { Fragment } from 'react'; import { ChakraProvider, extendTheme } from '@chakra-ui/react'; import { BrowserRouter } from 'react-router-dom'; import { createClient, Provider } from 'urql'; +import { cacheExchange, fetchExchange } from '@urql/core'; import { AppRoutes } from './routes'; import { AuthContextProvider } from './contexts/AuthContext'; @@ -17,6 +18,7 @@ const queryClient = createClient({ }; }, requestPolicy: 'network-only', + exchanges: [cacheExchange, fetchExchange], }); const theme = extendTheme({ diff --git a/dashboard/src/components/DeleteEmailTemplateModal.tsx b/web/dashboard/src/components/DeleteEmailTemplateModal.tsx similarity index 100% rename from dashboard/src/components/DeleteEmailTemplateModal.tsx rename to web/dashboard/src/components/DeleteEmailTemplateModal.tsx diff --git a/dashboard/src/components/DeleteUserModal.tsx b/web/dashboard/src/components/DeleteUserModal.tsx similarity index 100% rename from dashboard/src/components/DeleteUserModal.tsx rename to web/dashboard/src/components/DeleteUserModal.tsx diff --git a/dashboard/src/components/DeleteWebhookModal.tsx b/web/dashboard/src/components/DeleteWebhookModal.tsx similarity index 100% rename from dashboard/src/components/DeleteWebhookModal.tsx rename to web/dashboard/src/components/DeleteWebhookModal.tsx diff --git a/dashboard/src/components/EditUserModal.tsx b/web/dashboard/src/components/EditUserModal.tsx similarity index 100% rename from dashboard/src/components/EditUserModal.tsx rename to web/dashboard/src/components/EditUserModal.tsx diff --git a/dashboard/src/components/EnvComponents/AccessToken.tsx b/web/dashboard/src/components/EnvComponents/AccessToken.tsx similarity index 100% rename from dashboard/src/components/EnvComponents/AccessToken.tsx rename to web/dashboard/src/components/EnvComponents/AccessToken.tsx diff --git a/dashboard/src/components/EnvComponents/DatabaseCredentials.tsx b/web/dashboard/src/components/EnvComponents/DatabaseCredentials.tsx similarity index 100% rename from dashboard/src/components/EnvComponents/DatabaseCredentials.tsx rename to web/dashboard/src/components/EnvComponents/DatabaseCredentials.tsx diff --git a/dashboard/src/components/EnvComponents/DomainWhitelisting.tsx b/web/dashboard/src/components/EnvComponents/DomainWhitelisting.tsx similarity index 100% rename from dashboard/src/components/EnvComponents/DomainWhitelisting.tsx rename to web/dashboard/src/components/EnvComponents/DomainWhitelisting.tsx diff --git a/dashboard/src/components/EnvComponents/EmailConfiguration.tsx b/web/dashboard/src/components/EnvComponents/EmailConfiguration.tsx similarity index 100% rename from dashboard/src/components/EnvComponents/EmailConfiguration.tsx rename to web/dashboard/src/components/EnvComponents/EmailConfiguration.tsx diff --git a/dashboard/src/components/EnvComponents/Features.tsx b/web/dashboard/src/components/EnvComponents/Features.tsx similarity index 100% rename from dashboard/src/components/EnvComponents/Features.tsx rename to web/dashboard/src/components/EnvComponents/Features.tsx diff --git a/dashboard/src/components/EnvComponents/JWTConfiguration.tsx b/web/dashboard/src/components/EnvComponents/JWTConfiguration.tsx similarity index 100% rename from dashboard/src/components/EnvComponents/JWTConfiguration.tsx rename to web/dashboard/src/components/EnvComponents/JWTConfiguration.tsx diff --git a/dashboard/src/components/EnvComponents/OAuthConfig.tsx b/web/dashboard/src/components/EnvComponents/OAuthConfig.tsx similarity index 100% rename from dashboard/src/components/EnvComponents/OAuthConfig.tsx rename to web/dashboard/src/components/EnvComponents/OAuthConfig.tsx diff --git a/dashboard/src/components/EnvComponents/OrganizationInfo.tsx b/web/dashboard/src/components/EnvComponents/OrganizationInfo.tsx similarity index 100% rename from dashboard/src/components/EnvComponents/OrganizationInfo.tsx rename to web/dashboard/src/components/EnvComponents/OrganizationInfo.tsx diff --git a/dashboard/src/components/EnvComponents/Roles.tsx b/web/dashboard/src/components/EnvComponents/Roles.tsx similarity index 100% rename from dashboard/src/components/EnvComponents/Roles.tsx rename to web/dashboard/src/components/EnvComponents/Roles.tsx diff --git a/dashboard/src/components/EnvComponents/SecurityAdminSecret.tsx b/web/dashboard/src/components/EnvComponents/SecurityAdminSecret.tsx similarity index 100% rename from dashboard/src/components/EnvComponents/SecurityAdminSecret.tsx rename to web/dashboard/src/components/EnvComponents/SecurityAdminSecret.tsx diff --git a/dashboard/src/components/EnvComponents/SessionStorage.tsx b/web/dashboard/src/components/EnvComponents/SessionStorage.tsx similarity index 100% rename from dashboard/src/components/EnvComponents/SessionStorage.tsx rename to web/dashboard/src/components/EnvComponents/SessionStorage.tsx diff --git a/dashboard/src/components/GenerateKeysModal.tsx b/web/dashboard/src/components/GenerateKeysModal.tsx similarity index 100% rename from dashboard/src/components/GenerateKeysModal.tsx rename to web/dashboard/src/components/GenerateKeysModal.tsx diff --git a/dashboard/src/components/InputField.tsx b/web/dashboard/src/components/InputField.tsx similarity index 100% rename from dashboard/src/components/InputField.tsx rename to web/dashboard/src/components/InputField.tsx diff --git a/dashboard/src/components/InviteMembersModal.tsx b/web/dashboard/src/components/InviteMembersModal.tsx similarity index 100% rename from dashboard/src/components/InviteMembersModal.tsx rename to web/dashboard/src/components/InviteMembersModal.tsx diff --git a/dashboard/src/components/Menu.tsx b/web/dashboard/src/components/Menu.tsx similarity index 72% rename from dashboard/src/components/Menu.tsx rename to web/dashboard/src/components/Menu.tsx index 09775c397..e860b5dab 100644 --- a/dashboard/src/components/Menu.tsx +++ b/web/dashboard/src/components/Menu.tsx @@ -6,7 +6,6 @@ import { Flex, Image, HStack, - VStack, Icon, useColorModeValue, Link, @@ -22,26 +21,18 @@ import { AccordionPanel, AccordionItem, useMediaQuery, + Button, } from '@chakra-ui/react'; import { - FiUser, FiCode, - FiSettings, FiMenu, FiUsers, FiChevronDown, FiLink, FiFileText, + FiPower, } from 'react-icons/fi'; -import { BiCustomize } from 'react-icons/bi'; -import { AiOutlineKey } from 'react-icons/ai'; -import { SiOpenaccess, SiJsonwebtokens } from 'react-icons/si'; -import { MdSecurity } from 'react-icons/md'; -import { RiDatabase2Line } from 'react-icons/ri'; -import { BsCheck2Circle } from 'react-icons/bs'; -import { HiOutlineMail, HiOutlineOfficeBuilding } from 'react-icons/hi'; import { IconType } from 'react-icons'; -import { ReactText } from 'react'; import { useMutation, useQuery } from 'urql'; import { NavLink, useNavigate, useLocation } from 'react-router-dom'; import { useAuthContext } from '../contexts/AuthContext'; @@ -61,58 +52,7 @@ interface LinkItemProps { subRoutes?: SubRoutes[]; } const LinkItems: Array = [ - { - name: 'Environment ', - icon: FiSettings, - route: '/', - subRoutes: [ - { - name: 'OAuth Config', - icon: AiOutlineKey, - route: '/oauth-setting', - }, - - { name: 'Roles', icon: FiUser, route: '/roles' }, - { - name: 'JWT Secrets', - icon: SiJsonwebtokens, - route: '/jwt-config', - }, - { - name: 'Session Storage', - icon: RiDatabase2Line, - route: '/session-storage', - }, - { - name: 'Email Configurations', - icon: HiOutlineMail, - route: '/email-config', - }, - { - name: 'Domain White Listing', - icon: BsCheck2Circle, - route: '/whitelist-variables', - }, - { - name: 'Organization Info', - icon: HiOutlineOfficeBuilding, - route: '/organization-info', - }, - { name: 'Access Token', icon: SiOpenaccess, route: '/access-token' }, - { - name: 'Features', - icon: BiCustomize, - route: '/features', - }, - { name: 'Database', icon: RiDatabase2Line, route: '/db-cred' }, - { - name: ' Security', - icon: MdSecurity, - route: '/admin-secret', - }, - ], - }, - { name: 'Users', icon: FiUsers, route: '/users' }, + { name: 'Users', icon: FiUsers, route: '/' }, { name: 'Webhooks', icon: FiLink, route: '/webhooks' }, { name: 'Email Templates', icon: FiFileText, route: '/email-templates' }, ]; @@ -254,8 +194,9 @@ export const Sidebar = ({ onClose, ...rest }: SidebarProps) => { interface NavItemProps extends FlexProps { icon: IconType; - children: ReactText | JSX.Element | JSX.Element[]; + children: ReactNode; } + export const NavItem = ({ icon, children, ...rest }: NavItemProps) => { return ( { - - - - - - Admin - - - - - - - - Sign out - - + diff --git a/dashboard/src/components/UpdateEmailTemplateModal.tsx b/web/dashboard/src/components/UpdateEmailTemplateModal.tsx similarity index 100% rename from dashboard/src/components/UpdateEmailTemplateModal.tsx rename to web/dashboard/src/components/UpdateEmailTemplateModal.tsx diff --git a/dashboard/src/components/UpdateWebhookModal.tsx b/web/dashboard/src/components/UpdateWebhookModal.tsx similarity index 100% rename from dashboard/src/components/UpdateWebhookModal.tsx rename to web/dashboard/src/components/UpdateWebhookModal.tsx diff --git a/dashboard/src/components/ViewWebhookLogsModal.tsx b/web/dashboard/src/components/ViewWebhookLogsModal.tsx similarity index 100% rename from dashboard/src/components/ViewWebhookLogsModal.tsx rename to web/dashboard/src/components/ViewWebhookLogsModal.tsx diff --git a/dashboard/src/constants.ts b/web/dashboard/src/constants.ts similarity index 100% rename from dashboard/src/constants.ts rename to web/dashboard/src/constants.ts diff --git a/dashboard/src/contexts/AuthContext.tsx b/web/dashboard/src/contexts/AuthContext.tsx similarity index 100% rename from dashboard/src/contexts/AuthContext.tsx rename to web/dashboard/src/contexts/AuthContext.tsx diff --git a/dashboard/src/graphql/mutation/index.ts b/web/dashboard/src/graphql/mutation/index.ts similarity index 94% rename from dashboard/src/graphql/mutation/index.ts rename to web/dashboard/src/graphql/mutation/index.ts index 47e9acf0f..22c95077d 100644 --- a/dashboard/src/graphql/mutation/index.ts +++ b/web/dashboard/src/graphql/mutation/index.ts @@ -22,14 +22,6 @@ export const AdminLogout = ` } `; -export const UpdateEnvVariables = ` - mutation updateEnvVariables($params: UpdateEnvInput!) { - _update_env(params: $params) { - message - } - } -`; - export const UpdateUser = ` mutation updateUser($params: UpdateUserInput!) { _update_user(params: $params) { diff --git a/dashboard/src/graphql/queries/index.ts b/web/dashboard/src/graphql/queries/index.ts similarity index 54% rename from dashboard/src/graphql/queries/index.ts rename to web/dashboard/src/graphql/queries/index.ts index 4953fd1c0..3b1e70d4d 100644 --- a/dashboard/src/graphql/queries/index.ts +++ b/web/dashboard/src/graphql/queries/index.ts @@ -15,78 +15,6 @@ export const AdminSessionQuery = ` } `; -export const EnvVariablesQuery = ` - query { - _env{ - CLIENT_ID - CLIENT_SECRET - GOOGLE_CLIENT_ID - GOOGLE_CLIENT_SECRET - GITHUB_CLIENT_ID - GITHUB_CLIENT_SECRET - FACEBOOK_CLIENT_ID - FACEBOOK_CLIENT_SECRET - LINKEDIN_CLIENT_ID - LINKEDIN_CLIENT_SECRET - APPLE_CLIENT_ID - APPLE_CLIENT_SECRET - DISCORD_CLIENT_ID - DISCORD_CLIENT_SECRET - TWITTER_CLIENT_ID - TWITTER_CLIENT_SECRET - MICROSOFT_CLIENT_ID - MICROSOFT_CLIENT_SECRET - MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID - TWITCH_CLIENT_ID - TWITCH_CLIENT_SECRET - ROBLOX_CLIENT_ID - ROBLOX_CLIENT_SECRET - DEFAULT_ROLES - PROTECTED_ROLES - ROLES - JWT_TYPE - JWT_SECRET - JWT_ROLE_CLAIM - JWT_PRIVATE_KEY - JWT_PUBLIC_KEY - REDIS_URL - SMTP_HOST - SMTP_PORT - SMTP_USERNAME - SMTP_PASSWORD - SMTP_LOCAL_NAME - SENDER_EMAIL - SENDER_NAME - ALLOWED_ORIGINS - ORGANIZATION_NAME - ORGANIZATION_LOGO - ADMIN_SECRET - APP_COOKIE_SECURE - ADMIN_COOKIE_SECURE - DISABLE_LOGIN_PAGE - DISABLE_MAGIC_LINK_LOGIN - DISABLE_EMAIL_VERIFICATION - DISABLE_BASIC_AUTHENTICATION - DISABLE_MOBILE_BASIC_AUTHENTICATION - DISABLE_SIGN_UP - DISABLE_STRONG_PASSWORD - DISABLE_REDIS_FOR_ENV - CUSTOM_ACCESS_TOKEN_SCRIPT - DATABASE_NAME - DATABASE_TYPE - DATABASE_URL - ACCESS_TOKEN_EXPIRY_TIME - DISABLE_MULTI_FACTOR_AUTHENTICATION - ENFORCE_MULTI_FACTOR_AUTHENTICATION - DEFAULT_AUTHORIZE_RESPONSE_TYPE - DEFAULT_AUTHORIZE_RESPONSE_MODE - DISABLE_PLAYGROUND - DISABLE_TOTP_LOGIN - DISABLE_MAIL_OTP_LOGIN - } - } -`; - export const UserDetailsQuery = ` query($params: PaginatedInput) { _users(params: $params) { diff --git a/web/dashboard/src/index.tsx b/web/dashboard/src/index.tsx new file mode 100644 index 000000000..5c1a28dc0 --- /dev/null +++ b/web/dashboard/src/index.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement, +); +root.render(); diff --git a/dashboard/src/layouts/AuthLayout.tsx b/web/dashboard/src/layouts/AuthLayout.tsx similarity index 100% rename from dashboard/src/layouts/AuthLayout.tsx rename to web/dashboard/src/layouts/AuthLayout.tsx diff --git a/dashboard/src/layouts/DashboardLayout.tsx b/web/dashboard/src/layouts/DashboardLayout.tsx similarity index 100% rename from dashboard/src/layouts/DashboardLayout.tsx rename to web/dashboard/src/layouts/DashboardLayout.tsx diff --git a/dashboard/src/pages/Auth.tsx b/web/dashboard/src/pages/Auth.tsx similarity index 84% rename from dashboard/src/pages/Auth.tsx rename to web/dashboard/src/pages/Auth.tsx index f8ace42c5..eae88646c 100644 --- a/dashboard/src/pages/Auth.tsx +++ b/web/dashboard/src/pages/Auth.tsx @@ -109,18 +109,6 @@ export default function Auth() { > {isLogin ? 'Login' : 'Sign up'} - {isLogin ? ( - - Note: In case if you have forgot your admin secret, you can - reset it by updating ADMIN_SECRET environment - variable. For more information, please refer to the{' '} - documentation. - - ) : ( - - Note: Configure the password to start using your dashboard. - - )} diff --git a/dashboard/src/pages/EmailTemplates.tsx b/web/dashboard/src/pages/EmailTemplates.tsx similarity index 100% rename from dashboard/src/pages/EmailTemplates.tsx rename to web/dashboard/src/pages/EmailTemplates.tsx diff --git a/dashboard/src/pages/Home.tsx b/web/dashboard/src/pages/Home.tsx similarity index 100% rename from dashboard/src/pages/Home.tsx rename to web/dashboard/src/pages/Home.tsx diff --git a/dashboard/src/pages/Users.tsx b/web/dashboard/src/pages/Users.tsx similarity index 99% rename from dashboard/src/pages/Users.tsx rename to web/dashboard/src/pages/Users.tsx index 64002dec3..a33ad8412 100644 --- a/dashboard/src/pages/Users.tsx +++ b/web/dashboard/src/pages/Users.tsx @@ -64,6 +64,7 @@ interface userDataTypes { gender: string; birthdate: string; phone_number: string; + phone_number_verified: boolean; picture: string; signup_methods: string; roles: [string]; @@ -145,7 +146,7 @@ export default function Users() { }; const checkEmailVerification = async () => { setLoading(true); - const { data } = await client.query(EmailVerificationQuery).toPromise(); + const { data } = await client.query(EmailVerificationQuery, {}).toPromise(); if (data?._env) { const { DISABLE_EMAIL_VERIFICATION } = data._env; setDisableInviteMembers(DISABLE_EMAIL_VERIFICATION); diff --git a/dashboard/src/pages/Webhooks.tsx b/web/dashboard/src/pages/Webhooks.tsx similarity index 100% rename from dashboard/src/pages/Webhooks.tsx rename to web/dashboard/src/pages/Webhooks.tsx diff --git a/dashboard/src/routes/index.tsx b/web/dashboard/src/routes/index.tsx similarity index 88% rename from dashboard/src/routes/index.tsx rename to web/dashboard/src/routes/index.tsx index 544c17268..c8ac37aef 100644 --- a/dashboard/src/routes/index.tsx +++ b/web/dashboard/src/routes/index.tsx @@ -6,7 +6,6 @@ import { DashboardLayout } from '../layouts/DashboardLayout'; import EmailTemplates from '../pages/EmailTemplates'; const Auth = lazy(() => import('../pages/Auth')); -const Environment = lazy(() => import('../pages/Environment')); const Home = lazy(() => import('../pages/Home')); const Users = lazy(() => import('../pages/Users')); const Webhooks = lazy(() => import('../pages/Webhooks')); @@ -26,11 +25,11 @@ export const AppRoutes = () => { } > - }> + {/* }> } /> } /> - - } /> + */} + } /> } /> } /> } /> diff --git a/dashboard/src/utils/index.ts b/web/dashboard/src/utils/index.ts similarity index 100% rename from dashboard/src/utils/index.ts rename to web/dashboard/src/utils/index.ts diff --git a/dashboard/src/utils/parseCSV.ts b/web/dashboard/src/utils/parseCSV.ts similarity index 100% rename from dashboard/src/utils/parseCSV.ts rename to web/dashboard/src/utils/parseCSV.ts diff --git a/web/dashboard/tsconfig.json b/web/dashboard/tsconfig.json new file mode 100644 index 000000000..73810f7ba --- /dev/null +++ b/web/dashboard/tsconfig.json @@ -0,0 +1,80 @@ +{ + "include": ["src/**/*"], + "exclude": ["node_modules", "build", "dist"], + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */, + "module": "ESNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + "lib": [ + "ES2020", + "DOM", + "DOM.Iterable" + ] /* Specify library files to be included in the compilation. */, + "allowJs": true /* Allow javascript files to be compiled. */, + // "checkJs": true, /* Report errors in .js files. */ + "jsx": "react-jsx" /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */, + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + "rootDir": "src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + "noEmit": true /* Do not emit outputs. */, + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + "isolatedModules": true /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */, + + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ + + /* Module Resolution Options */ + "moduleResolution": "bundler" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, + "baseUrl": "." /* Base directory to resolve non-absolute module names. */, + "paths": { + "@/*": ["./src/*"] + } /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */, + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + "types": [] /* Type declaration files to be included in compilation. */, + "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */, + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} diff --git a/web/dashboard/vite.config.ts b/web/dashboard/vite.config.ts new file mode 100644 index 000000000..9a0d4e2f9 --- /dev/null +++ b/web/dashboard/vite.config.ts @@ -0,0 +1,25 @@ +import { defineConfig, type PluginOption } from 'vite'; +import react from '@vitejs/plugin-react'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()] as PluginOption[], + build: { + outDir: 'build', + emptyOutDir: true, + rollupOptions: { + input: { + main: 'src/index.tsx', + }, + output: { + entryFileNames: 'index.js', + chunkFileNames: 'chunk-[name]-[hash].js', + assetFileNames: (assetInfo) => { + return 'assets/[name]-[hash][extname]'; + }, + }, + }, + }, + base: '/dashboard/', + publicDir: 'public', +}); diff --git a/templates/app.tmpl b/web/templates/app.tmpl similarity index 94% rename from templates/app.tmpl rename to web/templates/app.tmpl index bd15a4ef1..8ddd4bf2b 100644 --- a/templates/app.tmpl +++ b/web/templates/app.tmpl @@ -11,7 +11,7 @@ Document diff --git a/templates/authorize_form_post.tmpl b/web/templates/authorize_form_post.tmpl similarity index 100% rename from templates/authorize_form_post.tmpl rename to web/templates/authorize_form_post.tmpl diff --git a/templates/authorize_web_message.tmpl b/web/templates/authorize_web_message.tmpl similarity index 100% rename from templates/authorize_web_message.tmpl rename to web/templates/authorize_web_message.tmpl diff --git a/templates/dashboard.tmpl b/web/templates/dashboard.tmpl similarity index 99% rename from templates/dashboard.tmpl rename to web/templates/dashboard.tmpl index 8710a3567..a3e4ab4a2 100644 --- a/templates/dashboard.tmpl +++ b/web/templates/dashboard.tmpl @@ -8,9 +8,8 @@ - Document