diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index fac4792..74ce864 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -23,7 +23,8 @@ jobs:
sudo mv github-assets-uploader /usr/sbin/ && \
sudo rm -f github-assets-uploader.tar.gz && \
github-assets-uploader -version && \
- make build-app
+ make build-app && \
+ make build-dashboard
- name: Print Go paths
run: whereis go
- name: Print Go Version
@@ -37,12 +38,12 @@ jobs:
make clean && \
CGO_ENABLED=1 GOOS=windows CC=/usr/bin/x86_64-w64-mingw32-gcc make && \
mv build/server build/server.exe && \
- zip -vr authorizer-${VERSION}-windows-amd64.zip .env app/build build templates
+ zip -vr authorizer-${VERSION}-windows-amd64.zip .env app/build build templates dashboard/build
- name: Package files for linux
run: |
make clean && \
CGO_ENABLED=1 make && \
- tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz .env app/build build templates
+ tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz .env app/build build templates dashboard/build
- name: Upload assets
run: |
github-assets-uploader -f authorizer-${VERSION}-windows-amd64.zip -mediatype application/zip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} && \
diff --git a/.gitignore b/.gitignore
index 30b32c7..bab8c91 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,8 @@ server/.env
data
app/node_modules
app/build
+dashboard/node_modules
+dashboard/build
build
.env
data.db
diff --git a/Dockerfile b/Dockerfile
index a60cab8..d0045c4 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -14,14 +14,17 @@ RUN apk add build-base &&\
FROM node:17-alpine3.12 as node-builder
WORKDIR /authorizer
COPY app app
+COPY dashboard dashboard
COPY Makefile .
RUN apk add build-base &&\
- make build-app
+ make build-app && \
+ make build-dashboard
FROM alpine:latest
WORKDIR /root/
-RUN mkdir app
+RUN mkdir app dashboard
COPY --from=node-builder /authorizer/app/build app/build
+COPY --from=node-builder /authorizer/dashboard/build dashboard/build
COPY --from=go-builder /authorizer/build build
COPY templates templates
EXPOSE 8080
diff --git a/Makefile b/Makefile
index 4da765e..e45a5d5 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,8 @@ cmd:
cd server && go build -ldflags "-w -X main.VERSION=$(VERSION)" -o '../build/server'
build-app:
cd app && npm i && npm run build
+build-dashboard:
+ cd dashboard && npm i && npm run build
clean:
rm -rf build
test:
diff --git a/app/README.md b/app/README.md
index 2a33c8e..15ac1e9 100644
--- a/app/README.md
+++ b/app/README.md
@@ -1,3 +1,14 @@
# Authorizer APP
-App that can be used as login wall for your any application in combination with @authorizerdev/@authorizer.js
\ No newline at end of file
+App that can be used as login wall for your any application in combination with @authorizerdev/@authorizer.js
+
+### Getting started
+
+**Setting up locally**
+
+- `cd app`
+- `npm start`
+
+**Creating production build**
+
+- `make build-app`
diff --git a/dashboard/README.md b/dashboard/README.md
new file mode 100644
index 0000000..863e9dc
--- /dev/null
+++ b/dashboard/README.md
@@ -0,0 +1,12 @@
+# Authorizer dashboard
+
+### Getting started
+
+**Setting up locally**
+
+- `cd dashboard`
+- `npm start`
+
+**Creating production build**
+
+- `make build-dashboard`
diff --git a/dashboard/esbuild.config.js b/dashboard/esbuild.config.js
new file mode 100644
index 0000000..40fe839
--- /dev/null
+++ b/dashboard/esbuild.config.js
@@ -0,0 +1,12 @@
+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
new file mode 100644
index 0000000..10b7230
--- /dev/null
+++ b/dashboard/package-lock.json
@@ -0,0 +1,1682 @@
+{
+ "name": "dashboard",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz",
+ "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==",
+ "requires": {
+ "@babel/highlight": "^7.16.0"
+ }
+ },
+ "@babel/helper-module-imports": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz",
+ "integrity": "sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==",
+ "requires": {
+ "@babel/types": "^7.16.0"
+ }
+ },
+ "@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=="
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.15.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
+ "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w=="
+ },
+ "@babel/highlight": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz",
+ "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==",
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.15.7",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.16.5"
+ }
+ },
+ "@babel/runtime": {
+ "version": "7.16.5",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz",
+ "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==",
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
+ "@babel/types": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz",
+ "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==",
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.15.7",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@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": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/alert/-/alert-1.3.2.tgz",
+ "integrity": "sha512-+OMeVeGtydpj6nry0zH7qFDt36zEaxckRnufx1BGiCfWdUg6ahVwKXl8qX93Q8w82od7eAoBKMgGJz7IVL5NPw==",
+ "requires": {
+ "@chakra-ui/icon": "2.0.0",
+ "@chakra-ui/react-utils": "1.2.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/theme-tools": "^1.3.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/image": "1.1.1",
+ "@chakra-ui/react-utils": "1.2.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/react-utils": "1.2.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@chakra-ui/button": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/button/-/button-1.5.1.tgz",
+ "integrity": "sha512-BvP29quEhP6OTgDiRsugD6adgkeOTEQpoDsZUVEmHnNVrbFfdsICEKKQTtDJ2iPf+hmpFrtnpN50vCLdAANKcw==",
+ "requires": {
+ "@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": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/checkbox/-/checkbox-1.6.1.tgz",
+ "integrity": "sha512-Z5ZMeUYIRjRbi/knhYhSQshZH7OnROA7ezl9a9oVSKRF7iLMNMibQSlQLXmqUWaTKSgrS37cpKAzfgEuemyiUQ==",
+ "requires": {
+ "@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": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/clickable/-/clickable-1.2.1.tgz",
+ "integrity": "sha512-B0CIbKzDMwzG1APeTpW9H2Jl8dkarI1Qstb3hDOy23O+N5TU6lpDdVnXQ7fpFJS6mu5JjFqtkwzGAVZnkkv1rw==",
+ "requires": {
+ "@chakra-ui/react-utils": "1.2.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/icon": "2.0.0",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/hooks": "1.7.1",
+ "@chakra-ui/react-env": "1.1.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/hooks": "1.7.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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=="
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/react-utils": "^1.2.1"
+ }
+ },
+ "@chakra-ui/editable": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/editable/-/editable-1.3.1.tgz",
+ "integrity": "sha512-MwyTtsnHNqmKmHv9SH3KIHWa06D4gBwcuTawTiSnYBUJL6My8ry/Wdca1to9So2tD6hcjz3TPTzOJOlyv0eiZg==",
+ "requires": {
+ "@chakra-ui/hooks": "1.7.1",
+ "@chakra-ui/react-utils": "1.2.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/utils": "1.9.1",
+ "react-focus-lock": "2.5.2"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@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": {
+ "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==",
+ "requires": {
+ "@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": {
+ "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==",
+ "requires": {
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@chakra-ui/image": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/image/-/image-1.1.1.tgz",
+ "integrity": "sha512-bz1pn08XlXcO3r1KnpdjQgN3R2soiTx10sG2d5Pw9BdGdySf7Y73wiLh+Tan1xJHp6p2KH1hz4f7uKXXDn7Qmw==",
+ "requires": {
+ "@chakra-ui/hooks": "1.7.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@chakra-ui/input": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/input/-/input-1.3.2.tgz",
+ "integrity": "sha512-VMxmQgFiQ2UnBlkgLX/336G0IfYfw8YWF2ZoEFj5WL9kDSrrL1FXSBgjFGxrper74G4W20tESBCfU1S891y6cg==",
+ "requires": {
+ "@chakra-ui/form-control": "1.5.2",
+ "@chakra-ui/react-utils": "1.2.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/icon": "2.0.0",
+ "@chakra-ui/react-utils": "1.2.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/react-env": "1.1.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@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": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/modal/-/modal-1.10.2.tgz",
+ "integrity": "sha512-ZlmYetPHwHW4CAM09j4/+Ui54dXR1nzU6mOwhWe4/IzLvEyoEU6fHJeKyGxVUpYTG/7wltG/wKFRJpYa77tiBg==",
+ "requires": {
+ "@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": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/number-input/-/number-input-1.3.2.tgz",
+ "integrity": "sha512-7x7AoqwPXU1odyDcqIwjBwf0MJUwYMM2fa+6YZ52F941GKlvkDiiJOhK6xfhhBzkLUQD6DN8zgAmmGhaZ6UQXw==",
+ "requires": {
+ "@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": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/pin-input/-/pin-input-1.7.1.tgz",
+ "integrity": "sha512-eFFc5sofiyion+NxELWfCzD23XHIBDrJcfKKbNxt8jdXg9Ek4mFpmvnxBVrK0DIz6cVYgKY8c364OmxNUf4IyA==",
+ "requires": {
+ "@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": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/popover/-/popover-1.11.0.tgz",
+ "integrity": "sha512-cCHXAfhIRir+M0ehlYIjDw3mHpiCxDTJ9WV0H1zHQV8nDYVIlZw3nEntaq8oJrv0wpIzq2WCW5ss+bBR7nLZ1A==",
+ "requires": {
+ "@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": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/popper/-/popper-2.4.1.tgz",
+ "integrity": "sha512-cuwnwXx6RUXZGGynVOGG8fEIiMNBXUCy3UqWQD1eEd8200eWQobgNk4Z0YwzKuSzJwp0Auy+j5iKefi5FSkyog==",
+ "requires": {
+ "@chakra-ui/react-utils": "1.2.1",
+ "@popperjs/core": "^2.9.3"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/hooks": "1.7.1",
+ "@chakra-ui/react-utils": "1.2.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/theme-tools": "1.3.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@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": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/radio/-/radio-1.4.3.tgz",
+ "integrity": "sha512-TQdyfdUD3BLklOP67n82JN8ksQv1BYjvaYsK0m6WCa0LDJr9aCC+XtUPgVq/1L2t4HqHdiGOrGBooF4vvy/+BA==",
+ "requires": {
+ "@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": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/react/-/react-1.7.3.tgz",
+ "integrity": "sha512-6mrfDUOa9MoQ44Xvi7xgdDq48jTTTjW9BupCGf2R3DI+z6RbUKIHzbcoDJZt2HGY6j9EarMVNRoQJzvzGUKpoQ==",
+ "requires": {
+ "@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/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==",
+ "requires": {
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/utils": "^1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/form-control": "1.5.2",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@chakra-ui/skeleton": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/skeleton/-/skeleton-1.2.3.tgz",
+ "integrity": "sha512-u5ASkzPiBjfvKxKuBienUfmyYDTHziSWQ8Ny6k83LbwLv9IcmBNGsSkmsp7hesgi9cMHGBQ3hY2GTqG9ljndIg==",
+ "requires": {
+ "@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": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/slider/-/slider-1.5.2.tgz",
+ "integrity": "sha512-zP07TMew61GkJe47Nu7zEg/SUEwPHpN4alW6VUM6Y8UaVpQaDx7InarbWTc/bXdTP03SfE+hQ6WD9Oy7noe4hQ==",
+ "requires": {
+ "@chakra-ui/hooks": "1.7.1",
+ "@chakra-ui/react-utils": "1.2.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/utils": "1.9.1",
+ "@chakra-ui/visually-hidden": "1.1.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/icon": "2.0.0",
+ "@chakra-ui/utils": "1.9.1",
+ "@chakra-ui/visually-hidden": "1.1.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/utils": "1.9.1",
+ "csstype": "^3.0.9"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/checkbox": "1.6.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@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": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/table/-/table-1.3.1.tgz",
+ "integrity": "sha512-+ia/7zs7AGj01lon301EEx+mK4918yGc0K6e68Kxomex8tnxkwbskFWs6hX+6Kzbj56ZBm99eLlKpo2iGYX0HA==",
+ "requires": {
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@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": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/tag/-/tag-1.2.2.tgz",
+ "integrity": "sha512-H25y9nEyUAUdwQDND9P4mMXKf1wf9UH4A3DyP237qVKIyYBpa4aCH8eJU4dunh2yIzASB0DWcr7lsul/HAHxmg==",
+ "requires": {
+ "@chakra-ui/icon": "2.0.0",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/form-control": "1.5.2",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/anatomy": "1.2.1",
+ "@chakra-ui/theme-tools": "1.3.1",
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@chakra-ui/utils": "1.9.1",
+ "@ctrl/tinycolor": "^3.4.0"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@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": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/tooltip/-/tooltip-1.4.2.tgz",
+ "integrity": "sha512-+wyYXG8qenKkFy2YSFfOBf3rlWADnu6S9EUxP+3Rmm78unOWXDuTJWzqy2QlXs2BwoQoifaz1LVwzmMb7WLVgQ==",
+ "requires": {
+ "@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": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/transition/-/transition-1.4.2.tgz",
+ "integrity": "sha512-S+BNmpErHlntl//uaqv0sJegzMsQms0OnJapeZaRsvZL4s1SVYrR8kMrXigkdpeh4lAUqGsLpQHPKkzaKGbBOw==",
+ "requires": {
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@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": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/visually-hidden/-/visually-hidden-1.1.1.tgz",
+ "integrity": "sha512-AGK9YBQS2FW/1e5tfivS8VVXn8y2uTyJ9ACOnGiLm9FNdth9pR0fGil9axlcmhZpEYcSRlnCuma3nkqaCjJnAA==",
+ "requires": {
+ "@chakra-ui/utils": "1.9.1"
+ }
+ },
+ "@ctrl/tinycolor": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz",
+ "integrity": "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ=="
+ },
+ "@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==",
+ "requires": {
+ "@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": {
+ "version": "11.7.1",
+ "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz",
+ "integrity": "sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==",
+ "requires": {
+ "@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/hash": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
+ "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
+ },
+ "@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==",
+ "requires": {
+ "@emotion/memoize": "^0.7.4"
+ }
+ },
+ "@emotion/memoize": {
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz",
+ "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ=="
+ },
+ "@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==",
+ "requires": {
+ "@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": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz",
+ "integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==",
+ "requires": {
+ "@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": {
+ "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": {
+ "version": "11.6.0",
+ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.6.0.tgz",
+ "integrity": "sha512-mxVtVyIOTmCAkFbwIp+nCjTXJNgcz4VWkOYQro87jE2QBTydnkiYusMrRGFtzuruiGK4dDaNORk4gH049iiQuw==",
+ "requires": {
+ "@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": {
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
+ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
+ },
+ "@emotion/utils": {
+ "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": {
+ "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": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz",
+ "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg=="
+ },
+ "@popperjs/core": {
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.0.tgz",
+ "integrity": "sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ=="
+ },
+ "@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==",
+ "requires": {
+ "@reach/utils": "0.13.2",
+ "@reach/visually-hidden": "0.13.2",
+ "prop-types": "^15.7.2",
+ "tslib": "^2.1.0"
+ }
+ },
+ "@reach/utils": {
+ "version": "0.13.2",
+ "resolved": "https://registry.npmjs.org/@reach/utils/-/utils-0.13.2.tgz",
+ "integrity": "sha512-3ir6cN60zvUrwjOJu7C6jec/samqAeyAB12ZADK+qjnmQPdzSYldrFWwDVV5H0WkhbYXR3uh+eImu13hCetNPQ==",
+ "requires": {
+ "@types/warning": "^3.0.0",
+ "tslib": "^2.1.0",
+ "warning": "^4.0.3"
+ }
+ },
+ "@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==",
+ "requires": {
+ "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": {
+ "version": "4.14.178",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz",
+ "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw=="
+ },
+ "@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==",
+ "requires": {
+ "@types/lodash": "*"
+ }
+ },
+ "@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=="
+ },
+ "@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": {
+ "version": "17.0.38",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.38.tgz",
+ "integrity": "sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ==",
+ "requires": {
+ "@types/prop-types": "*",
+ "@types/scheduler": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@types/react": "*"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@types/history": "*",
+ "@types/react": "*"
+ }
+ },
+ "@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==",
+ "requires": {
+ "@types/history": "*",
+ "@types/react": "*",
+ "@types/react-router": "*"
+ }
+ },
+ "@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": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
+ "integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI="
+ },
+ "@urql/core": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/@urql/core/-/core-2.3.6.tgz",
+ "integrity": "sha512-PUxhtBh7/8167HJK6WqBv6Z0piuiaZHQGYbhwpNL9aIQmLROPEdaUYkY4wh45wPQXcTpnd11l0q3Pw+TI11pdw==",
+ "requires": {
+ "@graphql-typed-document-node/core": "^3.1.0",
+ "wonka": "^4.0.14"
+ }
+ },
+ "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==",
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "aria-hidden": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.1.3.tgz",
+ "integrity": "sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA==",
+ "requires": {
+ "tslib": "^1.0.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ }
+ }
+ },
+ "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==",
+ "requires": {
+ "@babel/runtime": "^7.7.2",
+ "cosmiconfig": "^6.0.0",
+ "resolve": "^1.12.0"
+ }
+ },
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ }
+ }
+ },
+ "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==",
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+ },
+ "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=="
+ },
+ "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==",
+ "requires": {
+ "safe-buffer": "~5.1.1"
+ }
+ },
+ "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==",
+ "requires": {
+ "toggle-selection": "^1.0.6"
+ }
+ },
+ "cosmiconfig": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
+ "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
+ "requires": {
+ "@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"
+ }
+ },
+ "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==",
+ "requires": {
+ "tiny-invariant": "^1.0.6"
+ }
+ },
+ "csstype": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
+ "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA=="
+ },
+ "debounce": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
+ "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug=="
+ },
+ "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=="
+ },
+ "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==",
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "esbuild": {
+ "version": "0.14.9",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.9.tgz",
+ "integrity": "sha512-uuT3kFsfUvzNW6I2RKKIHuCvutY/U9KFcAP6emUm98WvBhyhEr5vGkZLeN3r3vXfoykl+7xekAH8Ky09LXBd0Q==",
+ "requires": {
+ "esbuild-android-arm64": "0.14.9",
+ "esbuild-darwin-64": "0.14.9",
+ "esbuild-darwin-arm64": "0.14.9",
+ "esbuild-freebsd-64": "0.14.9",
+ "esbuild-freebsd-arm64": "0.14.9",
+ "esbuild-linux-32": "0.14.9",
+ "esbuild-linux-64": "0.14.9",
+ "esbuild-linux-arm": "0.14.9",
+ "esbuild-linux-arm64": "0.14.9",
+ "esbuild-linux-mips64le": "0.14.9",
+ "esbuild-linux-ppc64le": "0.14.9",
+ "esbuild-linux-s390x": "0.14.9",
+ "esbuild-netbsd-64": "0.14.9",
+ "esbuild-openbsd-64": "0.14.9",
+ "esbuild-sunos-64": "0.14.9",
+ "esbuild-windows-32": "0.14.9",
+ "esbuild-windows-64": "0.14.9",
+ "esbuild-windows-arm64": "0.14.9"
+ }
+ },
+ "esbuild-android-arm64": {
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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==",
+ "optional": true
+ },
+ "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=="
+ },
+ "find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
+ },
+ "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==",
+ "requires": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "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==",
+ "requires": {
+ "@emotion/is-prop-valid": "^0.8.2",
+ "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"
+ },
+ "dependencies": {
+ "@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,
+ "requires": {
+ "@emotion/memoize": "0.7.4"
+ }
+ },
+ "@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
+ },
+ "framesync": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz",
+ "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==",
+ "requires": {
+ "tslib": "^2.1.0"
+ }
+ }
+ }
+ },
+ "framesync": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/framesync/-/framesync-5.3.0.tgz",
+ "integrity": "sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA==",
+ "requires": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "get-nonce": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="
+ },
+ "graphql": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.2.0.tgz",
+ "integrity": "sha512-MuQd7XXrdOcmfwuLwC2jNvx0n3rxIuNYOxUtiee5XOmfrWo613ar2U8pE7aHAKh8VwfpifubpD9IP+EdEAEOsA=="
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+ },
+ "hey-listen": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
+ "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
+ },
+ "history": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz",
+ "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==",
+ "requires": {
+ "@babel/runtime": "^7.7.6"
+ }
+ },
+ "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==",
+ "requires": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ }
+ },
+ "invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
+ },
+ "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==",
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "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=="
+ },
+ "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=="
+ },
+ "lodash.mergewith": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
+ "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="
+ },
+ "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==",
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "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==",
+ "requires": {
+ "callsites": "^3.0.0"
+ }
+ },
+ "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==",
+ "requires": {
+ "@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": {
+ "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": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
+ },
+ "popmotion": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz",
+ "integrity": "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==",
+ "requires": {
+ "framesync": "6.0.1",
+ "hey-listen": "^1.0.8",
+ "style-value-types": "5.0.0",
+ "tslib": "^2.1.0"
+ },
+ "dependencies": {
+ "framesync": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz",
+ "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==",
+ "requires": {
+ "tslib": "^2.1.0"
+ }
+ }
+ }
+ },
+ "prop-types": {
+ "version": "15.8.0",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.0.tgz",
+ "integrity": "sha512-fDGekdaHh65eI3lMi5OnErU6a8Ighg2KjcjQxO7m8VHyWjcPyj5kiOgV1LQDOOOgVy3+5FgjXvdSSX7B8/5/4g==",
+ "requires": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
+ "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==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
+ "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==",
+ "requires": {
+ "@babel/runtime": "^7.12.13"
+ }
+ },
+ "react-dom": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
+ "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "scheduler": "^0.20.2"
+ }
+ },
+ "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=="
+ },
+ "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==",
+ "requires": {
+ "@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": {
+ "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": {
+ "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": {
+ "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": {
+ "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==",
+ "requires": {
+ "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"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ }
+ }
+ },
+ "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==",
+ "requires": {
+ "react-style-singleton": "^2.1.0",
+ "tslib": "^1.0.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ }
+ }
+ },
+ "react-router": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz",
+ "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==",
+ "requires": {
+ "history": "^5.2.0"
+ }
+ },
+ "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==",
+ "requires": {
+ "history": "^5.2.0",
+ "react-router": "6.2.1"
+ }
+ },
+ "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==",
+ "requires": {
+ "get-nonce": "^1.0.0",
+ "invariant": "^2.2.4",
+ "tslib": "^1.0.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ }
+ }
+ },
+ "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==",
+ "requires": {
+ "debounce": "^1.2.1"
+ }
+ },
+ "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=="
+ },
+ "resolve": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
+ "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
+ "requires": {
+ "is-core-module": "^2.2.0",
+ "path-parse": "^1.0.6"
+ }
+ },
+ "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=="
+ },
+ "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=="
+ },
+ "scheduler": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
+ "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "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==",
+ "requires": {
+ "hey-listen": "^1.0.8",
+ "tslib": "^2.1.0"
+ }
+ },
+ "stylis": {
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz",
+ "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag=="
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "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=="
+ },
+ "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="
+ },
+ "toggle-selection": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+ "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI="
+ },
+ "tslib": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
+ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
+ },
+ "typescript": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz",
+ "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg=="
+ },
+ "urql": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/urql/-/urql-2.0.6.tgz",
+ "integrity": "sha512-ovK9mx7YxD/CKUwVZGbEDBzZjbCcNsr1990nIhDCKe3Ij/0gNcIa+0EIyXKceOPuYDYKavIoaNQV2kOZjQxFcw==",
+ "requires": {
+ "@urql/core": "^2.3.6",
+ "wonka": "^4.0.14"
+ }
+ },
+ "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=="
+ },
+ "use-sidecar": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.0.5.tgz",
+ "integrity": "sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA==",
+ "requires": {
+ "detect-node-es": "^1.1.0",
+ "tslib": "^1.9.3"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ }
+ }
+ },
+ "warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "wonka": {
+ "version": "4.0.15",
+ "resolved": "https://registry.npmjs.org/wonka/-/wonka-4.0.15.tgz",
+ "integrity": "sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg=="
+ },
+ "yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
+ }
+ }
+}
diff --git a/dashboard/package.json b/dashboard/package.json
new file mode 100644
index 0000000..ba96a12
--- /dev/null
+++ b/dashboard/package.json
@@ -0,0 +1,30 @@
+{
+ "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"
+ },
+ "keywords": [],
+ "author": "Lakhan Samani",
+ "license": "ISC",
+ "dependencies": {
+ "@chakra-ui/react": "^1.7.3",
+ "@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",
+ "esbuild": "^0.14.9",
+ "framer-motion": "^5.5.5",
+ "graphql": "^16.2.0",
+ "react": "^17.0.2",
+ "react-dom": "^17.0.2",
+ "react-icons": "^4.3.1",
+ "react-router-dom": "^6.2.1",
+ "typescript": "^4.5.4",
+ "urql": "^2.0.6"
+ }
+}
diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx
new file mode 100644
index 0000000..4effe54
--- /dev/null
+++ b/dashboard/src/App.tsx
@@ -0,0 +1,44 @@
+import * as React from "react";
+import { ChakraProvider, extendTheme } from "@chakra-ui/react";
+import { BrowserRouter } from "react-router-dom";
+import { createClient, Provider } from "urql";
+import {AppRoutes} from './routes'
+import { AuthContainer } from "./containers/AuthContainer";
+
+const queryClient = createClient({
+ url: "/graphql",
+ fetchOptions: () => {
+ return {
+ credentials: "include",
+ };
+ },
+});
+
+const theme = extendTheme({
+ styles: {
+ global: {
+ "html, body, #root": {
+ height: "100%",
+ },
+ },
+ },
+ colors: {
+ blue: {
+ 500: "rgb(59,130,246)",
+ },
+ },
+});
+
+export default function App() {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/dashboard/src/components/Sidebar.tsx b/dashboard/src/components/Sidebar.tsx
new file mode 100644
index 0000000..d4fbb13
--- /dev/null
+++ b/dashboard/src/components/Sidebar.tsx
@@ -0,0 +1,54 @@
+import { Box, Image, Link, Text } from "@chakra-ui/react";
+import { NavLink, useLocation } from "react-router-dom";
+import React from "react";
+import { LOGO_URL } from "../constants";
+
+const routes = [
+ {
+ route: "/users",
+ name: "Users",
+ },
+ {
+ route: "/settings",
+ name: "Settings",
+ },
+];
+
+export const Sidebar = () => {
+ const { pathname } = useLocation();
+ return (
+
+
+
+
+
+ Authorizer
+
+
+
+ {routes.map(({ route, name }: any) => (
+
+ {name}
+
+ ))}
+
+ );
+};
diff --git a/dashboard/src/constants.ts b/dashboard/src/constants.ts
new file mode 100644
index 0000000..2a2eacc
--- /dev/null
+++ b/dashboard/src/constants.ts
@@ -0,0 +1 @@
+export const LOGO_URL = "https://user-images.githubusercontent.com/6964334/147834043-fc384cab-e7ca-40f8-9663-38fc25fd5f3a.png"
\ No newline at end of file
diff --git a/dashboard/src/containers/AuthContainer.tsx b/dashboard/src/containers/AuthContainer.tsx
new file mode 100644
index 0000000..e8aad71
--- /dev/null
+++ b/dashboard/src/containers/AuthContainer.tsx
@@ -0,0 +1,37 @@
+import { Center, Spinner } from "@chakra-ui/react";
+import React from "react";
+import { Navigate, Route, Routes } from "react-router-dom";
+import { useLocation } from "react-router-dom";
+import { useQuery } from "urql";
+import { AdminSessionQuery } from "../graphql/queries";
+import { hasAdminSecret } from "../utils";
+
+export const AuthContainer = ({ children }: { children: any }) => {
+ const { pathname } = useLocation();
+ const isOnboardingComplete = hasAdminSecret();
+ const [result] = useQuery({
+ query: AdminSessionQuery,
+ pause: !isOnboardingComplete,
+ });
+
+ if (result.fetching) {
+ return (
+
+
+
+ );
+ }
+
+ if (
+ result?.error?.message.includes("unauthorized") &&
+ pathname !== "/login"
+ ) {
+ return ;
+ }
+
+ if (!isOnboardingComplete && pathname !== "/setup") {
+ return ;
+ }
+
+ return children;
+};
diff --git a/dashboard/src/graphql/mutation/index.ts b/dashboard/src/graphql/mutation/index.ts
new file mode 100644
index 0000000..01fcacc
--- /dev/null
+++ b/dashboard/src/graphql/mutation/index.ts
@@ -0,0 +1,15 @@
+export const AdminSignup = `
+ mutation adminSignup($secret: String!) {
+ _admin_signup (params: {admin_secret: $secret}) {
+ message
+ }
+ }
+`;
+
+export const AdminLogin = `
+mutation adminLogin($secret: String!){
+ _admin_login(params: { admin_secret: $secret }) {
+ message
+ }
+}
+`
\ No newline at end of file
diff --git a/dashboard/src/graphql/queries/index.ts b/dashboard/src/graphql/queries/index.ts
new file mode 100644
index 0000000..837dbbc
--- /dev/null
+++ b/dashboard/src/graphql/queries/index.ts
@@ -0,0 +1,7 @@
+export const AdminSessionQuery = `
+ query {
+ _admin_session{
+ message
+ }
+ }
+`;
diff --git a/dashboard/src/index.tsx b/dashboard/src/index.tsx
new file mode 100644
index 0000000..b597a44
--- /dev/null
+++ b/dashboard/src/index.tsx
@@ -0,0 +1,5 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import App from './App';
+
+ReactDOM.render(, document.getElementById('root'));
diff --git a/dashboard/src/layouts/AuthLayout.tsx b/dashboard/src/layouts/AuthLayout.tsx
new file mode 100644
index 0000000..10c73bd
--- /dev/null
+++ b/dashboard/src/layouts/AuthLayout.tsx
@@ -0,0 +1,29 @@
+import { Box, Center, Flex, Image, Text } from "@chakra-ui/react";
+import React from "react";
+import { LOGO_URL } from "../constants";
+
+export function AuthLayout({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+
+ Authorizer
+
+
+
+ {children}
+
+
+ );
+}
diff --git a/dashboard/src/layouts/DashboardLayout.tsx b/dashboard/src/layouts/DashboardLayout.tsx
new file mode 100644
index 0000000..d3b663f
--- /dev/null
+++ b/dashboard/src/layouts/DashboardLayout.tsx
@@ -0,0 +1,14 @@
+import { Box, Flex } from "@chakra-ui/react";
+import React from "react";
+import { Sidebar } from "../components/Sidebar";
+
+export function DashboardLayout({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+ {children}
+
+ );
+}
diff --git a/dashboard/src/pages/Auth.tsx b/dashboard/src/pages/Auth.tsx
new file mode 100644
index 0000000..0db905f
--- /dev/null
+++ b/dashboard/src/pages/Auth.tsx
@@ -0,0 +1,90 @@
+import {
+ Button,
+ FormControl,
+ FormLabel,
+ Input,
+ useToast,
+ VStack,
+} from "@chakra-ui/react";
+import React, { useEffect } from "react";
+import { useMutation } from "urql";
+import { AuthLayout } from "../layouts/AuthLayout";
+import { AdminLogin, AdminSignup } from "../graphql/mutation";
+import { useLocation, useNavigate } from "react-router-dom";
+
+export const Auth = () => {
+ const [loginResult, login] = useMutation(AdminLogin);
+ const [signUpResult, signup] = useMutation(AdminSignup);
+
+ const toast = useToast();
+ const navigate = useNavigate()
+ const { pathname } = useLocation();
+ const isLogin = pathname === "/login";
+
+ const handleAdminSecret = (e: any) => {
+ e.preventDefault();
+ const formValues = [...e.target.elements].reduce((agg: any, elem: any) => {
+ if (elem.id) {
+ return {
+ ...agg,
+ [elem.id]: elem.value,
+ };
+ }
+
+ return agg;
+ }, {});
+
+ (isLogin ? login : signup)({
+ secret: formValues["admin-secret"],
+ }).then((res) => {
+ if (!res.error?.name) {
+ navigate("/");
+ }
+ });
+ };
+
+ const errors = isLogin ? loginResult.error : signUpResult.error;
+
+ useEffect(() => {
+ if (errors?.graphQLErrors) {
+ (errors?.graphQLErrors || []).map((error: any) => {
+ toast({
+ title: error.message,
+ isClosable: true,
+ status: "error",
+ position:"bottom-right"
+ });
+ })
+ }
+ }, [errors])
+
+ return (
+
+
+
+ );
+};
diff --git a/dashboard/src/pages/Home.tsx b/dashboard/src/pages/Home.tsx
new file mode 100644
index 0000000..2fd4335
--- /dev/null
+++ b/dashboard/src/pages/Home.tsx
@@ -0,0 +1,6 @@
+import { Box } from "@chakra-ui/react";
+import React from "react";
+
+export function Home() {
+ return Welcome to Authorizer dashboard!;
+}
diff --git a/dashboard/src/pages/Users.tsx b/dashboard/src/pages/Users.tsx
new file mode 100644
index 0000000..3f97712
--- /dev/null
+++ b/dashboard/src/pages/Users.tsx
@@ -0,0 +1,6 @@
+import { Box } from "@chakra-ui/react";
+import React from "react";
+
+export function Users() {
+ return users;
+}
diff --git a/dashboard/src/routes/index.tsx b/dashboard/src/routes/index.tsx
new file mode 100644
index 0000000..3c1e2f9
--- /dev/null
+++ b/dashboard/src/routes/index.tsx
@@ -0,0 +1,26 @@
+import React from "react";
+import { Outlet, Route, Routes } from "react-router-dom";
+import { DashboardLayout } from "../layouts/DashboardLayout";
+import { Auth } from "../pages/Auth";
+
+import { Home } from "../pages/Home";
+import { Users } from "../pages/Users";
+
+export const AppRoutes = () => {
+ return (
+
+ } />
+ } />
+
+
+
+ }
+ >
+ } />
+ } />
+
+
+ );
+};
diff --git a/dashboard/src/utils/index.ts b/dashboard/src/utils/index.ts
new file mode 100644
index 0000000..cab1ebf
--- /dev/null
+++ b/dashboard/src/utils/index.ts
@@ -0,0 +1,3 @@
+export const hasAdminSecret = () => {
+ return (window)["__authorizer__"].isOnboardingCompleted === true
+}
\ No newline at end of file
diff --git a/dashboard/tsconfig.json b/dashboard/tsconfig.json
new file mode 100644
index 0000000..a752b14
--- /dev/null
+++ b/dashboard/tsconfig.json
@@ -0,0 +1,72 @@
+{
+ "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/scripts/build-mac.sh b/scripts/build-mac.sh
index 1e3f4a2..e41d529 100644
--- a/scripts/build-mac.sh
+++ b/scripts/build-mac.sh
@@ -1,7 +1,7 @@
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
+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
diff --git a/server/__test__/admin_login_test.go b/server/__test__/admin_login_test.go
new file mode 100644
index 0000000..eefd8b9
--- /dev/null
+++ b/server/__test__/admin_login_test.go
@@ -0,0 +1,27 @@
+package test
+
+import (
+ "testing"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/graph/model"
+ "github.com/authorizerdev/authorizer/server/resolvers"
+ "github.com/stretchr/testify/assert"
+)
+
+func adminLoginTests(s TestSetup, t *testing.T) {
+ 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)
+
+ _, err = resolvers.AdminLoginResolver(ctx, model.AdminLoginInput{
+ AdminSecret: constants.EnvData.ADMIN_SECRET,
+ })
+
+ assert.Nil(t, err)
+ })
+}
diff --git a/server/__test__/admin_logout_test.go b/server/__test__/admin_logout_test.go
new file mode 100644
index 0000000..c548368
--- /dev/null
+++ b/server/__test__/admin_logout_test.go
@@ -0,0 +1,26 @@
+package test
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/resolvers"
+ "github.com/authorizerdev/authorizer/server/utils"
+ "github.com/stretchr/testify/assert"
+)
+
+func adminLogoutTests(s TestSetup, t *testing.T) {
+ t.Run(`should get admin session`, func(t *testing.T) {
+ req, ctx := createContext(s)
+ _, err := resolvers.AdminLogout(ctx)
+ assert.NotNil(t, err)
+
+ h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
+ assert.Nil(t, err)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
+ _, err = resolvers.AdminLogout(ctx)
+
+ assert.Nil(t, err)
+ })
+}
diff --git a/server/__test__/admin_session_test.go b/server/__test__/admin_session_test.go
new file mode 100644
index 0000000..afc0179
--- /dev/null
+++ b/server/__test__/admin_session_test.go
@@ -0,0 +1,28 @@
+package test
+
+import (
+ "fmt"
+ "log"
+ "testing"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/resolvers"
+ "github.com/authorizerdev/authorizer/server/utils"
+ "github.com/stretchr/testify/assert"
+)
+
+func adminSessionTests(s TestSetup, t *testing.T) {
+ t.Run(`should get admin session`, func(t *testing.T) {
+ req, ctx := createContext(s)
+ _, err := resolvers.AdminSession(ctx)
+ log.Println("error:", err)
+ assert.NotNil(t, err)
+
+ h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
+ assert.Nil(t, err)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
+ _, err = resolvers.AdminSession(ctx)
+
+ assert.Nil(t, err)
+ })
+}
diff --git a/server/__test__/admin_signup_test.go b/server/__test__/admin_signup_test.go
new file mode 100644
index 0000000..441533e
--- /dev/null
+++ b/server/__test__/admin_signup_test.go
@@ -0,0 +1,31 @@
+package test
+
+import (
+ "log"
+ "testing"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/graph/model"
+ "github.com/authorizerdev/authorizer/server/resolvers"
+ "github.com/google/uuid"
+ "github.com/stretchr/testify/assert"
+)
+
+func adminSignupTests(s TestSetup, t *testing.T) {
+ t.Run(`should complete admin login`, func(t *testing.T) {
+ _, ctx := createContext(s)
+ _, err := resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{
+ AdminSecret: "admin",
+ })
+ log.Println("err", err)
+ assert.NotNil(t, err)
+ // reset env for test to pass
+ constants.EnvData.ADMIN_SECRET = ""
+
+ _, err = resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{
+ AdminSecret: uuid.New().String(),
+ })
+
+ assert.Nil(t, err)
+ })
+}
diff --git a/server/__test__/config_test.go b/server/__test__/config_test.go
new file mode 100644
index 0000000..5cf6d2c
--- /dev/null
+++ b/server/__test__/config_test.go
@@ -0,0 +1,29 @@
+package test
+
+import (
+ "fmt"
+ "log"
+ "testing"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/resolvers"
+ "github.com/authorizerdev/authorizer/server/utils"
+ "github.com/stretchr/testify/assert"
+)
+
+func configTests(s TestSetup, t *testing.T) {
+ t.Run(`should get config`, func(t *testing.T) {
+ req, ctx := createContext(s)
+ _, err := resolvers.ConfigResolver(ctx)
+ log.Println("error:", err)
+ assert.NotNil(t, err)
+
+ h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
+ assert.Nil(t, err)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
+ res, err := resolvers.ConfigResolver(ctx)
+
+ assert.Nil(t, err)
+ assert.Equal(t, *res.AdminSecret, constants.EnvData.ADMIN_SECRET)
+ })
+}
diff --git a/server/__test__/delete_user_test.go b/server/__test__/delete_user_test.go
index 4f306dc..ae891d1 100644
--- a/server/__test__/delete_user_test.go
+++ b/server/__test__/delete_user_test.go
@@ -1,11 +1,13 @@
package test
import (
+ "fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers"
+ "github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
@@ -24,7 +26,10 @@ func deleteUserTest(s TestSetup, t *testing.T) {
})
assert.NotNil(t, err, "unauthorized")
- req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET)
+ h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
+ assert.Nil(t, err)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
+
_, err = resolvers.DeleteUser(ctx, model.DeleteUserInput{
Email: email,
})
diff --git a/server/__test__/env_test.go b/server/__test__/env_test.go
index 690ad51..328d5f6 100644
--- a/server/__test__/env_test.go
+++ b/server/__test__/env_test.go
@@ -8,18 +8,18 @@ import (
)
func TestEnvs(t *testing.T) {
- constants.ENV_PATH = "../../.env.sample"
+ constants.EnvData.ENV_PATH = "../../.env.sample"
- assert.Equal(t, constants.ADMIN_SECRET, "admin")
- assert.Equal(t, constants.ENV, "production")
- assert.False(t, constants.DISABLE_EMAIL_VERIFICATION)
- assert.False(t, constants.DISABLE_MAGIC_LINK_LOGIN)
- assert.False(t, constants.DISABLE_BASIC_AUTHENTICATION)
- assert.Equal(t, constants.JWT_TYPE, "HS256")
- assert.Equal(t, constants.JWT_SECRET, "random_string")
- assert.Equal(t, constants.JWT_ROLE_CLAIM, "role")
- assert.EqualValues(t, constants.ROLES, []string{"user"})
- assert.EqualValues(t, constants.DEFAULT_ROLES, []string{"user"})
- assert.EqualValues(t, constants.PROTECTED_ROLES, []string{"admin"})
- assert.EqualValues(t, constants.ALLOWED_ORIGINS, []string{"*"})
+ assert.Equal(t, constants.EnvData.ADMIN_SECRET, "admin")
+ assert.Equal(t, constants.EnvData.ENV, "production")
+ assert.False(t, constants.EnvData.DISABLE_EMAIL_VERIFICATION)
+ assert.False(t, constants.EnvData.DISABLE_MAGIC_LINK_LOGIN)
+ assert.False(t, constants.EnvData.DISABLE_BASIC_AUTHENTICATION)
+ assert.Equal(t, constants.EnvData.JWT_TYPE, "HS256")
+ assert.Equal(t, constants.EnvData.JWT_SECRET, "random_string")
+ assert.Equal(t, constants.EnvData.JWT_ROLE_CLAIM, "role")
+ assert.EqualValues(t, constants.EnvData.ROLES, []string{"user"})
+ assert.EqualValues(t, constants.EnvData.DEFAULT_ROLES, []string{"user"})
+ assert.EqualValues(t, constants.EnvData.PROTECTED_ROLES, []string{"admin"})
+ assert.EqualValues(t, constants.EnvData.ALLOWED_ORIGINS, []string{"*"})
}
diff --git a/server/__test__/logout_test.go b/server/__test__/logout_test.go
index 634e036..9788279 100644
--- a/server/__test__/logout_test.go
+++ b/server/__test__/logout_test.go
@@ -1,8 +1,10 @@
package test
import (
+ "fmt"
"testing"
+ "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model"
@@ -25,7 +27,7 @@ func logoutTests(s TestSetup, t *testing.T) {
})
token := *verifyRes.AccessToken
- req.Header.Add("Authorization", "Bearer "+token)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token))
_, err = resolvers.Logout(ctx)
assert.Nil(t, err)
_, err = resolvers.Profile(ctx)
diff --git a/server/__test__/magic_link_login_test.go b/server/__test__/magic_link_login_test.go
index c1771cf..9bc3c0d 100644
--- a/server/__test__/magic_link_login_test.go
+++ b/server/__test__/magic_link_login_test.go
@@ -1,8 +1,10 @@
package test
import (
+ "fmt"
"testing"
+ "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model"
@@ -26,7 +28,7 @@ func magicLinkLoginTests(s TestSetup, t *testing.T) {
})
token := *verifyRes.AccessToken
- req.Header.Add("Authorization", "Bearer "+token)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token))
_, err = resolvers.Profile(ctx)
assert.Nil(t, err)
diff --git a/server/__test__/meta_test.go b/server/__test__/meta_test.go
index f4167c1..9989141 100644
--- a/server/__test__/meta_test.go
+++ b/server/__test__/meta_test.go
@@ -2,6 +2,7 @@ package test
import (
"context"
+ "log"
"testing"
"github.com/authorizerdev/authorizer/server/resolvers"
@@ -12,6 +13,7 @@ func metaTests(s TestSetup, t *testing.T) {
t.Run(`should get meta information`, func(t *testing.T) {
ctx := context.Background()
meta, err := resolvers.Meta(ctx)
+ log.Println("=> meta:", meta)
assert.Nil(t, err)
assert.False(t, meta.IsFacebookLoginEnabled)
assert.False(t, meta.IsGoogleLoginEnabled)
diff --git a/server/__test__/profile_test.go b/server/__test__/profile_test.go
index 8693f37..2c6f853 100644
--- a/server/__test__/profile_test.go
+++ b/server/__test__/profile_test.go
@@ -1,8 +1,10 @@
package test
import (
+ "fmt"
"testing"
+ "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model"
@@ -30,7 +32,7 @@ func profileTests(s TestSetup, t *testing.T) {
})
token := *verifyRes.AccessToken
- req.Header.Add("Authorization", "Bearer "+token)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token))
profileRes, err := resolvers.Profile(ctx)
assert.Nil(t, err)
diff --git a/server/__test__/resolvers_test.go b/server/__test__/resolvers_test.go
index 7eb73d5..e756672 100644
--- a/server/__test__/resolvers_test.go
+++ b/server/__test__/resolvers_test.go
@@ -1,11 +1,13 @@
package test
import (
+ "log"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
+ "github.com/authorizerdev/authorizer/server/env"
)
func TestResolvers(t *testing.T) {
@@ -16,14 +18,36 @@ func TestResolvers(t *testing.T) {
}
for dbType, dbURL := range databases {
- constants.DATABASE_URL = dbURL
- constants.DATABASE_TYPE = dbType
+ constants.EnvData.DATABASE_URL = dbURL
+ constants.EnvData.DATABASE_TYPE = dbType
db.InitDB()
+ // clean the persisted config for test to use fresh config
+ config, err := db.Mgr.GetConfig()
+ if err == nil {
+ config.Config = []byte{}
+ db.Mgr.UpdateConfig(config)
+ }
+ env.PersistEnv()
+
s := testSetup()
defer s.Server.Close()
+ log.Println("EnvData:", constants.EnvData)
t.Run("should pass tests for "+dbType, func(t *testing.T) {
+ // admin tests
+ adminSignupTests(s, t)
+ verificationRequestsTest(s, t)
+ usersTest(s, t)
+ deleteUserTest(s, t)
+ updateUserTest(s, t)
+ adminLoginTests(s, t)
+ adminLogoutTests(s, t)
+ adminSessionTests(s, t)
+ updateConfigTests(s, t)
+ configTests(s, t)
+
+ // user tests
loginTests(s, t)
signupTests(s, t)
forgotPasswordTest(s, t)
@@ -36,12 +60,6 @@ func TestResolvers(t *testing.T) {
magicLinkLoginTests(s, t)
logoutTests(s, t)
metaTests(s, t)
-
- // admin tests
- verificationRequestsTest(s, t)
- usersTest(s, t)
- deleteUserTest(s, t)
- updateUserTest(s, t)
})
}
}
diff --git a/server/__test__/session_test.go b/server/__test__/session_test.go
index 20f02ba..ae764cc 100644
--- a/server/__test__/session_test.go
+++ b/server/__test__/session_test.go
@@ -1,8 +1,10 @@
package test
import (
+ "fmt"
"testing"
+ "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model"
@@ -30,7 +32,8 @@ func sessionTests(s TestSetup, t *testing.T) {
})
token := *verifyRes.AccessToken
- req.Header.Add("Authorization", "Bearer "+token)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token))
+
sessionRes, err := resolvers.Session(ctx, []string{})
assert.Nil(t, err)
diff --git a/server/__test__/test.go b/server/__test__/test.go
index b43232f..39848f6 100644
--- a/server/__test__/test.go
+++ b/server/__test__/test.go
@@ -72,7 +72,8 @@ func testSetup() TestSetup {
Password: "test",
}
- constants.ENV_PATH = "../../.env.sample"
+ constants.EnvData.ENV_PATH = "../../.env.sample"
+
env.InitEnv()
session.InitSession()
diff --git a/server/__test__/update_config_test.go b/server/__test__/update_config_test.go
new file mode 100644
index 0000000..65eda37
--- /dev/null
+++ b/server/__test__/update_config_test.go
@@ -0,0 +1,44 @@
+package test
+
+import (
+ "fmt"
+ "log"
+ "testing"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/graph/model"
+ "github.com/authorizerdev/authorizer/server/resolvers"
+ "github.com/authorizerdev/authorizer/server/utils"
+ "github.com/stretchr/testify/assert"
+)
+
+func updateConfigTests(s TestSetup, t *testing.T) {
+ t.Run(`should update configs`, func(t *testing.T) {
+ req, ctx := createContext(s)
+ originalAppURL := constants.EnvData.APP_URL
+ log.Println("=> originalAppURL:", constants.EnvData.APP_URL)
+
+ data := model.UpdateConfigInput{}
+ _, err := resolvers.UpdateConfigResolver(ctx, data)
+ log.Println("error:", err)
+ assert.NotNil(t, err)
+
+ h, _ := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
+ newURL := "https://test.com"
+ data = model.UpdateConfigInput{
+ AppURL: &newURL,
+ }
+ _, err = resolvers.UpdateConfigResolver(ctx, data)
+ log.Println("error:", err)
+ assert.Nil(t, err)
+ assert.Equal(t, constants.EnvData.APP_URL, newURL)
+ assert.NotEqual(t, constants.EnvData.APP_URL, originalAppURL)
+ data = model.UpdateConfigInput{
+ AppURL: &originalAppURL,
+ }
+ _, err = resolvers.UpdateConfigResolver(ctx, data)
+ assert.Nil(t, err)
+ })
+}
diff --git a/server/__test__/update_profile_test.go b/server/__test__/update_profile_test.go
index 7d6d4d1..6a2e3d4 100644
--- a/server/__test__/update_profile_test.go
+++ b/server/__test__/update_profile_test.go
@@ -1,8 +1,10 @@
package test
import (
+ "fmt"
"testing"
+ "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model"
@@ -33,7 +35,7 @@ func updateProfileTests(s TestSetup, t *testing.T) {
})
token := *verifyRes.AccessToken
- req.Header.Add("Authorization", "Bearer "+token)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token))
_, err = resolvers.UpdateProfile(ctx, model.UpdateProfileInput{
FamilyName: &fName,
})
diff --git a/server/__test__/update_user_test.go b/server/__test__/update_user_test.go
index 45d614a..26a9583 100644
--- a/server/__test__/update_user_test.go
+++ b/server/__test__/update_user_test.go
@@ -1,11 +1,13 @@
package test
import (
+ "fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers"
+ "github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
@@ -29,7 +31,9 @@ func updateUserTest(s TestSetup, t *testing.T) {
})
assert.NotNil(t, err, "unauthorized")
- req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET)
+ h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
+ assert.Nil(t, err)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
_, err = resolvers.UpdateUser(ctx, model.UpdateUserInput{
ID: user.ID,
Roles: newRoles,
diff --git a/server/__test__/users_test.go b/server/__test__/users_test.go
index 6386a8e..abf2741 100644
--- a/server/__test__/users_test.go
+++ b/server/__test__/users_test.go
@@ -1,11 +1,13 @@
package test
import (
+ "fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers"
+ "github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
@@ -22,7 +24,9 @@ func usersTest(s TestSetup, t *testing.T) {
users, err := resolvers.Users(ctx)
assert.NotNil(t, err, "unauthorized")
- req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET)
+ h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
+ assert.Nil(t, err)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
users, err = resolvers.Users(ctx)
assert.Nil(t, err)
rLen := len(users)
diff --git a/server/__test__/validator_test.go b/server/__test__/validator_test.go
index 4999716..7145d74 100644
--- a/server/__test__/validator_test.go
+++ b/server/__test__/validator_test.go
@@ -22,7 +22,7 @@ func TestIsValidEmail(t *testing.T) {
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
- constants.ALLOWED_ORIGINS = []string{"localhost:8080", "*.google.com", "*.google.in", "*abc.*"}
+ constants.EnvData.ALLOWED_ORIGINS = []string{"localhost:8080", "*.google.com", "*.google.in", "*abc.*"}
assert.False(t, utils.IsValidOrigin("http://myapp.com"), "it should be invalid origin")
assert.False(t, utils.IsValidOrigin("http://appgoogle.com"), "it should be invalid origin")
diff --git a/server/__test__/verification_requests_test.go b/server/__test__/verification_requests_test.go
index 22fc26e..21f2886 100644
--- a/server/__test__/verification_requests_test.go
+++ b/server/__test__/verification_requests_test.go
@@ -1,11 +1,13 @@
package test
import (
+ "fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers"
+ "github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
@@ -23,7 +25,9 @@ func verificationRequestsTest(s TestSetup, t *testing.T) {
requests, err := resolvers.VerificationRequests(ctx)
assert.NotNil(t, err, "unauthorizer")
- req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET)
+ h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
+ assert.Nil(t, err)
+ req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
requests, err = resolvers.VerificationRequests(ctx)
assert.Nil(t, err)
diff --git a/server/constants/constants.go b/server/constants/constants.go
index cc50b0e..a2bc497 100644
--- a/server/constants/constants.go
+++ b/server/constants/constants.go
@@ -1,51 +1,62 @@
package constants
-// this constants are configured via env
-var (
- ADMIN_SECRET = ""
- ENV = ""
- ENV_PATH = ""
- VERSION = ""
- DATABASE_TYPE = ""
- DATABASE_URL = ""
- DATABASE_NAME = ""
- SMTP_HOST = ""
- SMTP_PORT = ""
- SMTP_USERNAME = ""
- SMTP_PASSWORD = ""
- SENDER_EMAIL = ""
- JWT_TYPE = ""
- JWT_SECRET = ""
- ALLOWED_ORIGINS = []string{}
- AUTHORIZER_URL = ""
- APP_URL = ""
- PORT = ""
- REDIS_URL = ""
- IS_PROD = false
- COOKIE_NAME = ""
- RESET_PASSWORD_URL = ""
- DISABLE_EMAIL_VERIFICATION = false
- DISABLE_BASIC_AUTHENTICATION = false
- DISABLE_MAGIC_LINK_LOGIN = false
- DISABLE_LOGIN_PAGE = false
+type EnvConst struct {
+ ADMIN_SECRET string
+ ENV string
+ ENV_PATH string
+ VERSION string
+ DATABASE_TYPE string
+ DATABASE_URL string
+ DATABASE_NAME string
+ SMTP_HOST string
+ SMTP_PORT string
+ SMTP_PASSWORD string
+ SMTP_USERNAME string
+ SENDER_EMAIL string
+ JWT_TYPE string
+ JWT_SECRET string
+ ALLOWED_ORIGINS []string
+ AUTHORIZER_URL string
+ APP_URL string
+ PORT string
+ REDIS_URL string
+ COOKIE_NAME string
+ ADMIN_COOKIE_NAME string
+ RESET_PASSWORD_URL string
+ ENCRYPTION_KEY string `json:"-"`
+ IS_PROD bool
+ DISABLE_EMAIL_VERIFICATION bool
+ DISABLE_BASIC_AUTHENTICATION bool
+ DISABLE_MAGIC_LINK_LOGIN bool
+ DISABLE_LOGIN_PAGE bool
// ROLES
- ROLES = []string{}
- PROTECTED_ROLES = []string{}
- DEFAULT_ROLES = []string{}
- JWT_ROLE_CLAIM = "role"
+ ROLES []string
+ PROTECTED_ROLES []string
+ DEFAULT_ROLES []string
+ JWT_ROLE_CLAIM string
// OAuth login
- GOOGLE_CLIENT_ID = ""
- GOOGLE_CLIENT_SECRET = ""
- GITHUB_CLIENT_ID = ""
- GITHUB_CLIENT_SECRET = ""
- FACEBOOK_CLIENT_ID = ""
- FACEBOOK_CLIENT_SECRET = ""
- TWITTER_CLIENT_ID = ""
- TWITTER_CLIENT_SECRET = ""
+ GOOGLE_CLIENT_ID string
+ GOOGLE_CLIENT_SECRET string
+ GITHUB_CLIENT_ID string
+ GITHUB_CLIENT_SECRET string
+ FACEBOOK_CLIENT_ID string
+ FACEBOOK_CLIENT_SECRET string
// Org envs
- ORGANIZATION_NAME = "Authorizer"
- ORGANIZATION_LOGO = "https://authorizer.dev/images/logo.png"
-)
+ ORGANIZATION_NAME string
+ ORGANIZATION_LOGO string
+}
+
+var EnvData = EnvConst{
+ ADMIN_COOKIE_NAME: "authorizer-admin",
+ JWT_ROLE_CLAIM: "role",
+ ORGANIZATION_NAME: "Authorizer",
+ ORGANIZATION_LOGO: "https://authorizer.dev/images/logo.png",
+ DISABLE_EMAIL_VERIFICATION: false,
+ DISABLE_BASIC_AUTHENTICATION: false,
+ DISABLE_MAGIC_LINK_LOGIN: false,
+ DISABLE_LOGIN_PAGE: false,
+ IS_PROD: false,
+}
diff --git a/server/db/arangodb.go b/server/db/arangodb.go
index 1d624ed..f6cdb06 100644
--- a/server/db/arangodb.go
+++ b/server/db/arangodb.go
@@ -17,7 +17,7 @@ import (
func initArangodb() (arangoDriver.Database, error) {
ctx := context.Background()
conn, err := http.NewConnection(http.ConnectionConfig{
- Endpoints: []string{constants.DATABASE_URL},
+ Endpoints: []string{constants.EnvData.DATABASE_URL},
})
if err != nil {
return nil, err
@@ -32,16 +32,16 @@ func initArangodb() (arangoDriver.Database, error) {
var arangodb driver.Database
- arangodb_exists, err := arangoClient.DatabaseExists(nil, constants.DATABASE_NAME)
+ arangodb_exists, err := arangoClient.DatabaseExists(nil, constants.EnvData.DATABASE_NAME)
if arangodb_exists {
- log.Println(constants.DATABASE_NAME + " db exists already")
- arangodb, err = arangoClient.Database(nil, constants.DATABASE_NAME)
+ log.Println(constants.EnvData.DATABASE_NAME + " db exists already")
+ arangodb, err = arangoClient.Database(nil, constants.EnvData.DATABASE_NAME)
if err != nil {
return nil, err
}
} else {
- arangodb, err = arangoClient.CreateDatabase(nil, constants.DATABASE_NAME, nil)
+ arangodb, err = arangoClient.CreateDatabase(nil, constants.EnvData.DATABASE_NAME, nil)
if err != nil {
return nil, err
}
@@ -100,5 +100,15 @@ func initArangodb() (arangoDriver.Database, error) {
Sparse: true,
})
+ configCollectionExists, err := arangodb.CollectionExists(ctx, Collections.Config)
+ if configCollectionExists {
+ log.Println(Collections.Config + " collection exists already")
+ } else {
+ _, err = arangodb.CreateCollection(ctx, Collections.Config, nil)
+ if err != nil {
+ log.Println("error creating collection("+Collections.Config+"):", err)
+ }
+ }
+
return arangodb, err
}
diff --git a/server/db/config.go b/server/db/config.go
new file mode 100644
index 0000000..d4f724a
--- /dev/null
+++ b/server/db/config.go
@@ -0,0 +1,161 @@
+package db
+
+import (
+ "fmt"
+ "log"
+ "time"
+
+ arangoDriver "github.com/arangodb/go-driver"
+ "github.com/google/uuid"
+ "go.mongodb.org/mongo-driver/bson"
+ "go.mongodb.org/mongo-driver/mongo/options"
+)
+
+type Config struct {
+ Key string `json:"_key,omitempty" bson:"_key"` // for arangodb
+ ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"`
+ Config []byte `gorm:"type:text" json:"config" bson:"config"`
+ Hash string `gorm:"type:hash" json:"hash" bson:"hash"`
+ UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"`
+ CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"`
+}
+
+// AddConfig function to add config
+func (mgr *manager) AddConfig(config Config) (Config, error) {
+ if config.ID == "" {
+ config.ID = uuid.New().String()
+ }
+
+ if IsORMSupported {
+ // copy id as value for fields required for mongodb & arangodb
+ config.Key = config.ID
+ result := mgr.sqlDB.Create(&config)
+
+ if result.Error != nil {
+ log.Println("error adding config:", result.Error)
+ return config, result.Error
+ }
+ }
+
+ if IsArangoDB {
+ config.CreatedAt = time.Now().Unix()
+ config.UpdatedAt = time.Now().Unix()
+ configCollection, _ := mgr.arangodb.Collection(nil, Collections.Config)
+ meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(nil), config)
+ if err != nil {
+ log.Println("error adding config:", err)
+ return config, err
+ }
+ config.Key = meta.Key
+ config.ID = meta.ID.String()
+ }
+
+ if IsMongoDB {
+ config.CreatedAt = time.Now().Unix()
+ config.UpdatedAt = time.Now().Unix()
+ config.Key = config.ID
+ configCollection := mgr.mongodb.Collection(Collections.Config, options.Collection())
+ _, err := configCollection.InsertOne(nil, config)
+ if err != nil {
+ log.Println("error adding config:", err)
+ return config, err
+ }
+ }
+
+ return config, nil
+}
+
+// UpdateConfig function to update config
+func (mgr *manager) UpdateConfig(config Config) (Config, error) {
+ config.UpdatedAt = time.Now().Unix()
+
+ if IsORMSupported {
+ result := mgr.sqlDB.Save(&config)
+
+ if result.Error != nil {
+ log.Println("error updating config:", result.Error)
+ return config, result.Error
+ }
+ }
+
+ if IsArangoDB {
+ collection, _ := mgr.arangodb.Collection(nil, Collections.Config)
+ meta, err := collection.UpdateDocument(nil, config.Key, config)
+ if err != nil {
+ log.Println("error updating config:", err)
+ return config, err
+ }
+
+ config.Key = meta.Key
+ config.ID = meta.ID.String()
+ }
+
+ if IsMongoDB {
+ configCollection := mgr.mongodb.Collection(Collections.Config, options.Collection())
+ _, err := configCollection.UpdateOne(nil, bson.M{"_id": bson.M{"$eq": config.ID}}, bson.M{"$set": config}, options.MergeUpdateOptions())
+ if err != nil {
+ log.Println("error updating config:", err)
+ return config, err
+ }
+ }
+
+ return config, nil
+}
+
+// GetConfig function to get config
+func (mgr *manager) GetConfig() (Config, error) {
+ var config Config
+
+ if IsORMSupported {
+ result := mgr.sqlDB.First(&config)
+
+ if result.Error != nil {
+ return config, result.Error
+ }
+ }
+
+ if IsArangoDB {
+ query := fmt.Sprintf("FOR d in %s RETURN d", Collections.Config)
+
+ cursor, err := mgr.arangodb.Query(nil, query, nil)
+ if err != nil {
+ return config, err
+ }
+ defer cursor.Close()
+
+ for {
+ if !cursor.HasMore() {
+ if config.Key == "" {
+ return config, fmt.Errorf("config not found")
+ }
+ break
+ }
+ _, err := cursor.ReadDocument(nil, &config)
+ if err != nil {
+ return config, err
+ }
+ }
+ }
+
+ if IsMongoDB {
+ configCollection := mgr.mongodb.Collection(Collections.Config, options.Collection())
+ cursor, err := configCollection.Find(nil, bson.M{}, options.Find())
+ if err != nil {
+ return config, err
+ }
+ defer cursor.Close(nil)
+
+ for cursor.Next(nil) {
+ err := cursor.Decode(&config)
+ if err != nil {
+ return config, err
+ }
+ }
+
+ if config.ID == "" {
+ return config, fmt.Errorf("config not found")
+ }
+ }
+
+ return config, nil
+}
diff --git a/server/db/db.go b/server/db/db.go
index f8e7256..8727da5 100644
--- a/server/db/db.go
+++ b/server/db/db.go
@@ -29,6 +29,9 @@ type Manager interface {
GetVerificationByEmail(email string, identifier string) (VerificationRequest, error)
AddSession(session Session) error
DeleteUserSession(userId string) error
+ AddConfig(config Config) (Config, error)
+ UpdateConfig(config Config) (Config, error)
+ GetConfig() (Config, error)
}
type manager struct {
@@ -42,6 +45,7 @@ type CollectionList struct {
User string
VerificationRequest string
Session string
+ Config string
}
var (
@@ -54,6 +58,7 @@ var (
User: Prefix + "users",
VerificationRequest: Prefix + "verification_requests",
Session: Prefix + "sessions",
+ Config: Prefix + "config",
}
)
@@ -61,9 +66,9 @@ func InitDB() {
var sqlDB *gorm.DB
var err error
- IsORMSupported = constants.DATABASE_TYPE != enum.Arangodb.String() && constants.DATABASE_TYPE != enum.Mongodb.String()
- IsArangoDB = constants.DATABASE_TYPE == enum.Arangodb.String()
- IsMongoDB = constants.DATABASE_TYPE == enum.Mongodb.String()
+ IsORMSupported = constants.EnvData.DATABASE_TYPE != enum.Arangodb.String() && constants.EnvData.DATABASE_TYPE != enum.Mongodb.String()
+ IsArangoDB = constants.EnvData.DATABASE_TYPE == enum.Arangodb.String()
+ IsMongoDB = constants.EnvData.DATABASE_TYPE == enum.Mongodb.String()
// sql db orm config
ormConfig := &gorm.Config{
@@ -72,20 +77,20 @@ func InitDB() {
},
}
- log.Println("db type:", constants.DATABASE_TYPE)
+ log.Println("db type:", constants.EnvData.DATABASE_TYPE)
- switch constants.DATABASE_TYPE {
+ switch constants.EnvData.DATABASE_TYPE {
case enum.Postgres.String():
- sqlDB, err = gorm.Open(postgres.Open(constants.DATABASE_URL), ormConfig)
+ sqlDB, err = gorm.Open(postgres.Open(constants.EnvData.DATABASE_URL), ormConfig)
break
case enum.Sqlite.String():
- sqlDB, err = gorm.Open(sqlite.Open(constants.DATABASE_URL), ormConfig)
+ sqlDB, err = gorm.Open(sqlite.Open(constants.EnvData.DATABASE_URL), ormConfig)
break
case enum.Mysql.String():
- sqlDB, err = gorm.Open(mysql.Open(constants.DATABASE_URL), ormConfig)
+ sqlDB, err = gorm.Open(mysql.Open(constants.EnvData.DATABASE_URL), ormConfig)
break
case enum.SQLServer.String():
- sqlDB, err = gorm.Open(sqlserver.Open(constants.DATABASE_URL), ormConfig)
+ sqlDB, err = gorm.Open(sqlserver.Open(constants.EnvData.DATABASE_URL), ormConfig)
break
case enum.Arangodb.String():
arangodb, err := initArangodb()
@@ -118,7 +123,7 @@ func InitDB() {
if err != nil {
log.Fatal("Failed to init sqlDB:", err)
} else {
- sqlDB.AutoMigrate(&User{}, &VerificationRequest{}, &Session{})
+ sqlDB.AutoMigrate(&User{}, &VerificationRequest{}, &Session{}, &Config{})
}
Mgr = &manager{
sqlDB: sqlDB,
diff --git a/server/db/mongodb.go b/server/db/mongodb.go
index c69f5bc..21d9320 100644
--- a/server/db/mongodb.go
+++ b/server/db/mongodb.go
@@ -12,7 +12,7 @@ import (
)
func initMongodb() (*mongo.Database, error) {
- mongodbOptions := options.Client().ApplyURI(constants.DATABASE_URL)
+ mongodbOptions := options.Client().ApplyURI(constants.EnvData.DATABASE_URL)
maxWait := time.Duration(5 * time.Second)
mongodbOptions.ConnectTimeout = &maxWait
mongoClient, err := mongo.NewClient(mongodbOptions)
@@ -30,7 +30,7 @@ func initMongodb() (*mongo.Database, error) {
return nil, err
}
- mongodb := mongoClient.Database(constants.DATABASE_NAME, options.Database())
+ mongodb := mongoClient.Database(constants.EnvData.DATABASE_NAME, options.Database())
mongodb.CreateCollection(ctx, Collections.User, options.CreateCollection())
userCollection := mongodb.Collection(Collections.User, options.Collection())
@@ -73,5 +73,7 @@ func initMongodb() (*mongo.Database, error) {
},
}, options.CreateIndexes())
+ mongodb.CreateCollection(ctx, Collections.Config, options.CreateCollection())
+
return mongodb, nil
}
diff --git a/server/db/user.go b/server/db/user.go
index 60254fa..f020dcf 100644
--- a/server/db/user.go
+++ b/server/db/user.go
@@ -43,7 +43,7 @@ func (mgr *manager) AddUser(user User) (User, error) {
}
if user.Roles == "" {
- user.Roles = constants.DEFAULT_ROLES[0]
+ user.Roles = constants.EnvData.DEFAULT_ROLES[0]
}
if IsORMSupported {
diff --git a/server/email/email.go b/server/email/email.go
index e598fcd..843bf0f 100644
--- a/server/email/email.go
+++ b/server/email/email.go
@@ -11,13 +11,13 @@ import (
func SendMail(to []string, Subject, bodyMessage string) error {
m := gomail.NewMessage()
- m.SetHeader("From", constants.SENDER_EMAIL)
+ m.SetHeader("From", constants.EnvData.SENDER_EMAIL)
m.SetHeader("To", to...)
m.SetHeader("Subject", Subject)
m.SetBody("text/html", bodyMessage)
- port, _ := strconv.Atoi(constants.SMTP_PORT)
- d := gomail.NewDialer(constants.SMTP_HOST, port, constants.SMTP_USERNAME, constants.SMTP_PASSWORD)
- if constants.ENV == "development" {
+ port, _ := strconv.Atoi(constants.EnvData.SMTP_PORT)
+ d := gomail.NewDialer(constants.EnvData.SMTP_HOST, port, constants.EnvData.SMTP_USERNAME, constants.EnvData.SMTP_PASSWORD)
+ if constants.EnvData.ENV == "development" {
d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
}
if err := d.DialAndSend(m); err != nil {
diff --git a/server/env/env.go b/server/env/env.go
index fb5e4f0..66a632d 100644
--- a/server/env/env.go
+++ b/server/env/env.go
@@ -7,6 +7,7 @@ import (
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/utils"
+ "github.com/google/uuid"
"github.com/joho/godotenv"
)
@@ -20,167 +21,173 @@ var (
// InitEnv -> to initialize env and through error if required env are not present
func InitEnv() {
- if constants.ENV_PATH == "" {
- constants.ENV_PATH = `.env`
+ if constants.EnvData.ENV_PATH == "" {
+ constants.EnvData.ENV_PATH = `.env`
}
if ARG_ENV_FILE != nil && *ARG_ENV_FILE != "" {
- constants.ENV_PATH = *ARG_ENV_FILE
+ constants.EnvData.ENV_PATH = *ARG_ENV_FILE
}
- err := godotenv.Load(constants.ENV_PATH)
+ err := godotenv.Load(constants.EnvData.ENV_PATH)
if err != nil {
- log.Printf("error loading %s file", constants.ENV_PATH)
+ log.Printf("error loading %s file", constants.EnvData.ENV_PATH)
}
- if constants.ADMIN_SECRET == "" {
- constants.ADMIN_SECRET = os.Getenv("ADMIN_SECRET")
- if constants.ADMIN_SECRET == "" {
- panic("root admin secret is required")
- }
+ if constants.EnvData.ADMIN_SECRET == "" {
+ constants.EnvData.ADMIN_SECRET = os.Getenv("ADMIN_SECRET")
}
- if constants.ENV == "" {
- constants.ENV = os.Getenv("ENV")
- if constants.ENV == "" {
- constants.ENV = "production"
- }
-
- if constants.ENV == "production" {
- constants.IS_PROD = true
- os.Setenv("GIN_MODE", "release")
- } else {
- constants.IS_PROD = false
- }
- }
-
- if constants.DATABASE_TYPE == "" {
- constants.DATABASE_TYPE = os.Getenv("DATABASE_TYPE")
- log.Println(constants.DATABASE_TYPE)
+ if constants.EnvData.DATABASE_TYPE == "" {
+ constants.EnvData.DATABASE_TYPE = os.Getenv("DATABASE_TYPE")
+ log.Println(constants.EnvData.DATABASE_TYPE)
if ARG_DB_TYPE != nil && *ARG_DB_TYPE != "" {
- constants.DATABASE_TYPE = *ARG_DB_TYPE
+ constants.EnvData.DATABASE_TYPE = *ARG_DB_TYPE
}
- if constants.DATABASE_TYPE == "" {
+ if constants.EnvData.DATABASE_TYPE == "" {
panic("DATABASE_TYPE is required")
}
}
- if constants.DATABASE_URL == "" {
- constants.DATABASE_URL = os.Getenv("DATABASE_URL")
+ if constants.EnvData.DATABASE_URL == "" {
+ constants.EnvData.DATABASE_URL = os.Getenv("DATABASE_URL")
if ARG_DB_URL != nil && *ARG_DB_URL != "" {
- constants.DATABASE_URL = *ARG_DB_URL
+ constants.EnvData.DATABASE_URL = *ARG_DB_URL
}
- if constants.DATABASE_URL == "" {
+ if constants.EnvData.DATABASE_URL == "" {
panic("DATABASE_URL is required")
}
}
- if constants.DATABASE_NAME == "" {
- constants.DATABASE_NAME = os.Getenv("DATABASE_NAME")
- if constants.DATABASE_NAME == "" {
- constants.DATABASE_NAME = "authorizer"
+ if constants.EnvData.DATABASE_NAME == "" {
+ constants.EnvData.DATABASE_NAME = os.Getenv("DATABASE_NAME")
+ if constants.EnvData.DATABASE_NAME == "" {
+ constants.EnvData.DATABASE_NAME = "authorizer"
}
}
- if constants.SMTP_HOST == "" {
- constants.SMTP_HOST = os.Getenv("SMTP_HOST")
- }
+ if constants.EnvData.ENV == "" {
+ constants.EnvData.ENV = os.Getenv("ENV")
+ if constants.EnvData.ENV == "" {
+ constants.EnvData.ENV = "production"
+ }
- if constants.SMTP_PORT == "" {
- constants.SMTP_PORT = os.Getenv("SMTP_PORT")
- }
-
- if constants.SMTP_USERNAME == "" {
- constants.SMTP_USERNAME = os.Getenv("SMTP_USERNAME")
- }
-
- if constants.SMTP_PASSWORD == "" {
- constants.SMTP_PASSWORD = os.Getenv("SMTP_PASSWORD")
- }
-
- if constants.SENDER_EMAIL == "" {
- constants.SENDER_EMAIL = os.Getenv("SENDER_EMAIL")
- }
-
- if constants.JWT_SECRET == "" {
- constants.JWT_SECRET = os.Getenv("JWT_SECRET")
- }
-
- if constants.JWT_TYPE == "" {
- constants.JWT_TYPE = os.Getenv("JWT_TYPE")
- }
-
- if constants.JWT_ROLE_CLAIM == "" {
- constants.JWT_ROLE_CLAIM = os.Getenv("JWT_ROLE_CLAIM")
-
- if constants.JWT_ROLE_CLAIM == "" {
- constants.JWT_ROLE_CLAIM = "role"
+ if constants.EnvData.ENV == "production" {
+ constants.EnvData.IS_PROD = true
+ os.Setenv("GIN_MODE", "release")
+ } else {
+ constants.EnvData.IS_PROD = false
}
}
- if constants.AUTHORIZER_URL == "" {
- constants.AUTHORIZER_URL = strings.TrimSuffix(os.Getenv("AUTHORIZER_URL"), "/")
+ if constants.EnvData.SMTP_HOST == "" {
+ constants.EnvData.SMTP_HOST = os.Getenv("SMTP_HOST")
+ }
+
+ if constants.EnvData.SMTP_PORT == "" {
+ constants.EnvData.SMTP_PORT = os.Getenv("SMTP_PORT")
+ }
+
+ if constants.EnvData.SMTP_USERNAME == "" {
+ constants.EnvData.SMTP_USERNAME = os.Getenv("SMTP_USERNAME")
+ }
+
+ if constants.EnvData.SMTP_PASSWORD == "" {
+ constants.EnvData.SMTP_PASSWORD = os.Getenv("SMTP_PASSWORD")
+ }
+
+ if constants.EnvData.SENDER_EMAIL == "" {
+ constants.EnvData.SENDER_EMAIL = os.Getenv("SENDER_EMAIL")
+ }
+
+ if constants.EnvData.JWT_SECRET == "" {
+ constants.EnvData.JWT_SECRET = os.Getenv("JWT_SECRET")
+ if constants.EnvData.JWT_SECRET == "" {
+ constants.EnvData.JWT_SECRET = uuid.New().String()
+ }
+ }
+
+ if constants.EnvData.JWT_TYPE == "" {
+ constants.EnvData.JWT_TYPE = os.Getenv("JWT_TYPE")
+ if constants.EnvData.JWT_TYPE == "" {
+ constants.EnvData.JWT_TYPE = "HS256"
+ }
+ }
+
+ if constants.EnvData.JWT_ROLE_CLAIM == "" {
+ constants.EnvData.JWT_ROLE_CLAIM = os.Getenv("JWT_ROLE_CLAIM")
+
+ if constants.EnvData.JWT_ROLE_CLAIM == "" {
+ constants.EnvData.JWT_ROLE_CLAIM = "role"
+ }
+ }
+
+ if constants.EnvData.AUTHORIZER_URL == "" {
+ constants.EnvData.AUTHORIZER_URL = strings.TrimSuffix(os.Getenv("AUTHORIZER_URL"), "/")
if ARG_AUTHORIZER_URL != nil && *ARG_AUTHORIZER_URL != "" {
- constants.AUTHORIZER_URL = *ARG_AUTHORIZER_URL
+ constants.EnvData.AUTHORIZER_URL = *ARG_AUTHORIZER_URL
}
}
- if constants.PORT == "" {
- constants.PORT = os.Getenv("PORT")
- if constants.PORT == "" {
- constants.PORT = "8080"
+ if constants.EnvData.PORT == "" {
+ constants.EnvData.PORT = os.Getenv("PORT")
+ if constants.EnvData.PORT == "" {
+ constants.EnvData.PORT = "8080"
}
}
- if constants.REDIS_URL == "" {
- constants.REDIS_URL = os.Getenv("REDIS_URL")
+ if constants.EnvData.REDIS_URL == "" {
+ constants.EnvData.REDIS_URL = os.Getenv("REDIS_URL")
}
- if constants.COOKIE_NAME == "" {
- constants.COOKIE_NAME = os.Getenv("COOKIE_NAME")
+ if constants.EnvData.COOKIE_NAME == "" {
+ constants.EnvData.COOKIE_NAME = os.Getenv("COOKIE_NAME")
+ if constants.EnvData.COOKIE_NAME == "" {
+ constants.EnvData.COOKIE_NAME = "authorizer"
+ }
}
- if constants.GOOGLE_CLIENT_ID == "" {
- constants.GOOGLE_CLIENT_ID = os.Getenv("GOOGLE_CLIENT_ID")
+ if constants.EnvData.GOOGLE_CLIENT_ID == "" {
+ constants.EnvData.GOOGLE_CLIENT_ID = os.Getenv("GOOGLE_CLIENT_ID")
}
- if constants.GOOGLE_CLIENT_SECRET == "" {
- constants.GOOGLE_CLIENT_SECRET = os.Getenv("GOOGLE_CLIENT_SECRET")
+ if constants.EnvData.GOOGLE_CLIENT_SECRET == "" {
+ constants.EnvData.GOOGLE_CLIENT_SECRET = os.Getenv("GOOGLE_CLIENT_SECRET")
}
- if constants.GITHUB_CLIENT_ID == "" {
- constants.GITHUB_CLIENT_ID = os.Getenv("GITHUB_CLIENT_ID")
+ if constants.EnvData.GITHUB_CLIENT_ID == "" {
+ constants.EnvData.GITHUB_CLIENT_ID = os.Getenv("GITHUB_CLIENT_ID")
}
- if constants.GITHUB_CLIENT_SECRET == "" {
- constants.GITHUB_CLIENT_SECRET = os.Getenv("GITHUB_CLIENT_SECRET")
+ if constants.EnvData.GITHUB_CLIENT_SECRET == "" {
+ constants.EnvData.GITHUB_CLIENT_SECRET = os.Getenv("GITHUB_CLIENT_SECRET")
}
- if constants.FACEBOOK_CLIENT_ID == "" {
- constants.FACEBOOK_CLIENT_ID = os.Getenv("FACEBOOK_CLIENT_ID")
+ if constants.EnvData.FACEBOOK_CLIENT_ID == "" {
+ constants.EnvData.FACEBOOK_CLIENT_ID = os.Getenv("FACEBOOK_CLIENT_ID")
}
- if constants.FACEBOOK_CLIENT_SECRET == "" {
- constants.FACEBOOK_CLIENT_SECRET = os.Getenv("FACEBOOK_CLIENT_SECRET")
+ if constants.EnvData.FACEBOOK_CLIENT_SECRET == "" {
+ constants.EnvData.FACEBOOK_CLIENT_SECRET = os.Getenv("FACEBOOK_CLIENT_SECRET")
}
- if constants.RESET_PASSWORD_URL == "" {
- constants.RESET_PASSWORD_URL = strings.TrimPrefix(os.Getenv("RESET_PASSWORD_URL"), "/")
+ if constants.EnvData.RESET_PASSWORD_URL == "" {
+ constants.EnvData.RESET_PASSWORD_URL = strings.TrimPrefix(os.Getenv("RESET_PASSWORD_URL"), "/")
}
- constants.DISABLE_BASIC_AUTHENTICATION = os.Getenv("DISABLE_BASIC_AUTHENTICATION") == "true"
- constants.DISABLE_EMAIL_VERIFICATION = os.Getenv("DISABLE_EMAIL_VERIFICATION") == "true"
- constants.DISABLE_MAGIC_LINK_LOGIN = os.Getenv("DISABLE_MAGIC_LINK_LOGIN") == "true"
- constants.DISABLE_LOGIN_PAGE = os.Getenv("DISABLE_LOGIN_PAGE") == "true"
+ constants.EnvData.DISABLE_BASIC_AUTHENTICATION = os.Getenv("DISABLE_BASIC_AUTHENTICATION") == "true"
+ constants.EnvData.DISABLE_EMAIL_VERIFICATION = os.Getenv("DISABLE_EMAIL_VERIFICATION") == "true"
+ constants.EnvData.DISABLE_MAGIC_LINK_LOGIN = os.Getenv("DISABLE_MAGIC_LINK_LOGIN") == "true"
+ constants.EnvData.DISABLE_LOGIN_PAGE = os.Getenv("DISABLE_LOGIN_PAGE") == "true"
- if constants.SMTP_HOST == "" || constants.SMTP_USERNAME == "" || constants.SMTP_PASSWORD == "" || constants.SENDER_EMAIL == "" {
- constants.DISABLE_EMAIL_VERIFICATION = true
- constants.DISABLE_MAGIC_LINK_LOGIN = true
+ if constants.EnvData.SMTP_HOST == "" || constants.EnvData.SMTP_USERNAME == "" || constants.EnvData.SMTP_PASSWORD == "" || constants.EnvData.SENDER_EMAIL == "" {
+ constants.EnvData.DISABLE_EMAIL_VERIFICATION = true
+ constants.EnvData.DISABLE_MAGIC_LINK_LOGIN = true
}
allowedOriginsSplit := strings.Split(os.Getenv("ALLOWED_ORIGINS"), ",")
@@ -209,18 +216,10 @@ func InitEnv() {
allowedOrigins = []string{"*"}
}
- constants.ALLOWED_ORIGINS = allowedOrigins
+ constants.EnvData.ALLOWED_ORIGINS = allowedOrigins
- if constants.JWT_TYPE == "" {
- constants.JWT_TYPE = "HS256"
- }
-
- if constants.COOKIE_NAME == "" {
- constants.COOKIE_NAME = "authorizer"
- }
-
- if constants.DISABLE_EMAIL_VERIFICATION {
- constants.DISABLE_MAGIC_LINK_LOGIN = true
+ if constants.EnvData.DISABLE_EMAIL_VERIFICATION {
+ constants.EnvData.DISABLE_MAGIC_LINK_LOGIN = true
}
rolesEnv := strings.TrimSpace(os.Getenv("ROLES"))
@@ -260,19 +259,19 @@ func InitEnv() {
}
}
- if len(roles) > 0 && len(defaultRoles) == 0 && len(defaultRoleSplit) > 0 {
+ if len(roles) > 0 && len(defaultRoles) == 0 && len(defaultRolesEnv) > 0 {
panic(`Invalid DEFAULT_ROLE environment variable. It can be one from give ROLES environment variable value`)
}
- constants.ROLES = roles
- constants.DEFAULT_ROLES = defaultRoles
- constants.PROTECTED_ROLES = protectedRoles
+ constants.EnvData.ROLES = roles
+ constants.EnvData.DEFAULT_ROLES = defaultRoles
+ constants.EnvData.PROTECTED_ROLES = protectedRoles
if os.Getenv("ORGANIZATION_NAME") != "" {
- constants.ORGANIZATION_NAME = os.Getenv("ORGANIZATION_NAME")
+ constants.EnvData.ORGANIZATION_NAME = os.Getenv("ORGANIZATION_NAME")
}
if os.Getenv("ORGANIZATION_LOGO") != "" {
- constants.ORGANIZATION_LOGO = os.Getenv("ORGANIZATION_LOGO")
+ constants.EnvData.ORGANIZATION_LOGO = os.Getenv("ORGANIZATION_LOGO")
}
}
diff --git a/server/env/persist_env.go b/server/env/persist_env.go
new file mode 100644
index 0000000..23c3560
--- /dev/null
+++ b/server/env/persist_env.go
@@ -0,0 +1,138 @@
+package env
+
+import (
+ "encoding/json"
+ "log"
+ "os"
+ "reflect"
+ "strings"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/db"
+ "github.com/authorizerdev/authorizer/server/utils"
+ "github.com/google/uuid"
+)
+
+func PersistEnv() error {
+ config, err := db.Mgr.GetConfig()
+ // config not found in db
+ if err != 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]
+ constants.EnvData.ENCRYPTION_KEY = hash
+ encodedHash := utils.EncryptB64(hash)
+
+ configData, err := json.Marshal(constants.EnvData)
+ if err != nil {
+ return err
+ }
+ encryptedConfig, err := utils.EncryptAES(configData)
+ if err != nil {
+ return err
+ }
+
+ config = db.Config{
+ Hash: encodedHash,
+ Config: encryptedConfig,
+ }
+
+ db.Mgr.AddConfig(config)
+ } else {
+ // decrypt the config data from db
+ // decryption can be done using the hash stored in db
+ encryptionKey := config.Hash
+ decryptedEncryptionKey, err := utils.DecryptB64(encryptionKey)
+ if err != nil {
+ return err
+ }
+ constants.EnvData.ENCRYPTION_KEY = decryptedEncryptionKey
+ decryptedConfigs, err := utils.DecryptAES(config.Config)
+ if err != nil {
+ return err
+ }
+
+ // temp json to validate with env
+ var jsonData map[string]interface{}
+
+ err = json.Unmarshal(decryptedConfigs, &jsonData)
+ if err != nil {
+ 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 jsonData {
+ fieldType := reflect.TypeOf(value).String()
+
+ // 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
+ envValue := strings.TrimSpace(os.Getenv(key))
+
+ // env is not empty
+ if envValue != "" {
+ // check the type
+ // currently we have 3 types of env vars: string, bool, []string{}
+ if fieldType == "string" {
+ if value != envValue {
+ jsonData[key] = envValue
+ hasChanged = true
+ }
+ }
+
+ if fieldType == "bool" {
+ newValue := envValue == "true"
+ if value != newValue {
+ jsonData[key] = newValue
+ hasChanged = true
+ }
+ }
+
+ if fieldType == "[]interface {}" {
+ stringArr := []string{}
+ envStringArr := strings.Split(envValue, ",")
+ for _, v := range value.([]interface{}) {
+ stringArr = append(stringArr, v.(string))
+ }
+ if !utils.IsStringArrayEqual(stringArr, envStringArr) {
+ jsonData[key] = envStringArr
+ }
+ }
+ }
+ }
+
+ // handle derivative cases like disabling email verification & magic login
+ // in case SMTP is off but env is set to true
+ if jsonData["SMTP_HOST"] == "" || jsonData["SENDER_EMAIL"] == "" || jsonData["SENDER_PASSWORD"] == "" {
+ if !jsonData["DISABLE_EMAIL_VERIFICATION"].(bool) {
+ jsonData["DISABLE_EMAIL_VERIFICATION"] = true
+ hasChanged = true
+ }
+
+ if !jsonData["DISABLE_MAGIC_LINK_LOGIN"].(bool) {
+ jsonData["DISABLE_MAGIC_LINK_LOGIN"] = true
+ hasChanged = true
+ }
+ }
+
+ if hasChanged {
+ encryptedConfig, err := utils.EncryptConfig(jsonData)
+ if err != nil {
+ return err
+ }
+
+ config.Config = encryptedConfig
+ _, err = db.Mgr.UpdateConfig(config)
+ if err != nil {
+ log.Println("error updating config:", err)
+ return err
+ }
+ }
+
+ }
+
+ return nil
+}
diff --git a/server/go.mod b/server/go.mod
index 6168c55..efd8cb6 100644
--- a/server/go.mod
+++ b/server/go.mod
@@ -20,7 +20,6 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f
- github.com/stretchr/testify v1.7.0
github.com/ugorji/go v1.2.6 // indirect
github.com/vektah/gqlparser/v2 v2.2.0
go.mongodb.org/mongo-driver v1.8.1
@@ -30,7 +29,7 @@ require (
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
- gopkg.in/mail.v2 v2.3.1 // indirect
+ gopkg.in/mail.v2 v2.3.1
gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/driver/mysql v1.2.1
gorm.io/driver/postgres v1.2.3
diff --git a/server/graph/generated/generated.go b/server/graph/generated/generated.go
index 300307a..3a336d9 100644
--- a/server/graph/generated/generated.go
+++ b/server/graph/generated/generated.go
@@ -50,6 +50,42 @@ type ComplexityRoot struct {
User func(childComplexity int) int
}
+ Config struct {
+ AdminSecret func(childComplexity int) int
+ AllowedOrigins func(childComplexity int) int
+ AppURL func(childComplexity int) int
+ AuthorizerURL func(childComplexity int) int
+ CookieName func(childComplexity int) int
+ DatabaseName func(childComplexity int) int
+ DatabaseType func(childComplexity int) int
+ DatabaseURL func(childComplexity int) int
+ DefaultRoles func(childComplexity int) int
+ DisableBasicAuthentication func(childComplexity int) int
+ DisableEmailVerification func(childComplexity int) int
+ DisableLoginPage func(childComplexity int) int
+ DisableMagicLinkLogin func(childComplexity int) int
+ FacebookClientID func(childComplexity int) int
+ FacebookClientSecret func(childComplexity int) int
+ GithubClientID func(childComplexity int) int
+ GithubClientSecret func(childComplexity int) int
+ GoogleClientID func(childComplexity int) int
+ GoogleClientSecret func(childComplexity int) int
+ JwtRoleClaim func(childComplexity int) int
+ JwtSecret func(childComplexity int) int
+ JwtType func(childComplexity int) int
+ OrganizationLogo func(childComplexity int) int
+ OrganizationName func(childComplexity int) int
+ ProtectedRoles func(childComplexity int) int
+ RedisURL func(childComplexity int) int
+ ResetPasswordURL func(childComplexity int) int
+ Roles func(childComplexity int) int
+ SMTPHost func(childComplexity int) int
+ SMTPPassword func(childComplexity int) int
+ SMTPPort func(childComplexity int) int
+ SMTPUsername func(childComplexity int) int
+ SenderEmail func(childComplexity int) int
+ }
+
Error struct {
Message func(childComplexity int) int
Reason func(childComplexity int) int
@@ -66,6 +102,9 @@ type ComplexityRoot struct {
}
Mutation struct {
+ AdminLogin func(childComplexity int, params model.AdminLoginInput) int
+ AdminLogout func(childComplexity int) int
+ AdminSignup func(childComplexity int, params model.AdminSignupInput) int
DeleteUser func(childComplexity int, params model.DeleteUserInput) int
ForgotPassword func(childComplexity int, params model.ForgotPasswordInput) int
Login func(childComplexity int, params model.LoginInput) int
@@ -74,12 +113,15 @@ type ComplexityRoot struct {
ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int
ResetPassword func(childComplexity int, params model.ResetPasswordInput) int
Signup func(childComplexity int, params model.SignUpInput) int
+ UpdateConfig func(childComplexity int, params model.UpdateConfigInput) int
UpdateProfile func(childComplexity int, params model.UpdateProfileInput) int
UpdateUser func(childComplexity int, params model.UpdateUserInput) int
VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int
}
Query struct {
+ AdminSession func(childComplexity int) int
+ Config func(childComplexity int) int
Meta func(childComplexity int) int
Profile func(childComplexity int) int
Session func(childComplexity int, roles []string) int
@@ -134,6 +176,10 @@ type MutationResolver interface {
ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*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)
+ AdminLogout(ctx context.Context) (*model.Response, error)
+ UpdateConfig(ctx context.Context, params model.UpdateConfigInput) (*model.Response, error)
}
type QueryResolver interface {
Meta(ctx context.Context) (*model.Meta, error)
@@ -141,6 +187,8 @@ type QueryResolver interface {
Profile(ctx context.Context) (*model.User, error)
Users(ctx context.Context) ([]*model.User, error)
VerificationRequests(ctx context.Context) ([]*model.VerificationRequest, error)
+ AdminSession(ctx context.Context) (*model.Response, error)
+ Config(ctx context.Context) (*model.Config, error)
}
type executableSchema struct {
@@ -186,6 +234,237 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.AuthResponse.User(childComplexity), true
+ case "Config.ADMIN_SECRET":
+ if e.complexity.Config.AdminSecret == nil {
+ break
+ }
+
+ return e.complexity.Config.AdminSecret(childComplexity), true
+
+ case "Config.ALLOWED_ORIGINS":
+ if e.complexity.Config.AllowedOrigins == nil {
+ break
+ }
+
+ return e.complexity.Config.AllowedOrigins(childComplexity), true
+
+ case "Config.APP_URL":
+ if e.complexity.Config.AppURL == nil {
+ break
+ }
+
+ return e.complexity.Config.AppURL(childComplexity), true
+
+ case "Config.AUTHORIZER_URL":
+ if e.complexity.Config.AuthorizerURL == nil {
+ break
+ }
+
+ return e.complexity.Config.AuthorizerURL(childComplexity), true
+
+ case "Config.COOKIE_NAME":
+ if e.complexity.Config.CookieName == nil {
+ break
+ }
+
+ return e.complexity.Config.CookieName(childComplexity), true
+
+ case "Config.DATABASE_NAME":
+ if e.complexity.Config.DatabaseName == nil {
+ break
+ }
+
+ return e.complexity.Config.DatabaseName(childComplexity), true
+
+ case "Config.DATABASE_TYPE":
+ if e.complexity.Config.DatabaseType == nil {
+ break
+ }
+
+ return e.complexity.Config.DatabaseType(childComplexity), true
+
+ case "Config.DATABASE_URL":
+ if e.complexity.Config.DatabaseURL == nil {
+ break
+ }
+
+ return e.complexity.Config.DatabaseURL(childComplexity), true
+
+ case "Config.DEFAULT_ROLES":
+ if e.complexity.Config.DefaultRoles == nil {
+ break
+ }
+
+ return e.complexity.Config.DefaultRoles(childComplexity), true
+
+ case "Config.DISABLE_BASIC_AUTHENTICATION":
+ if e.complexity.Config.DisableBasicAuthentication == nil {
+ break
+ }
+
+ return e.complexity.Config.DisableBasicAuthentication(childComplexity), true
+
+ case "Config.DISABLE_EMAIL_VERIFICATION":
+ if e.complexity.Config.DisableEmailVerification == nil {
+ break
+ }
+
+ return e.complexity.Config.DisableEmailVerification(childComplexity), true
+
+ case "Config.DISABLE_LOGIN_PAGE":
+ if e.complexity.Config.DisableLoginPage == nil {
+ break
+ }
+
+ return e.complexity.Config.DisableLoginPage(childComplexity), true
+
+ case "Config.DISABLE_MAGIC_LINK_LOGIN":
+ if e.complexity.Config.DisableMagicLinkLogin == nil {
+ break
+ }
+
+ return e.complexity.Config.DisableMagicLinkLogin(childComplexity), true
+
+ case "Config.FACEBOOK_CLIENT_ID":
+ if e.complexity.Config.FacebookClientID == nil {
+ break
+ }
+
+ return e.complexity.Config.FacebookClientID(childComplexity), true
+
+ case "Config.FACEBOOK_CLIENT_SECRET":
+ if e.complexity.Config.FacebookClientSecret == nil {
+ break
+ }
+
+ return e.complexity.Config.FacebookClientSecret(childComplexity), true
+
+ case "Config.GITHUB_CLIENT_ID":
+ if e.complexity.Config.GithubClientID == nil {
+ break
+ }
+
+ return e.complexity.Config.GithubClientID(childComplexity), true
+
+ case "Config.GITHUB_CLIENT_SECRET":
+ if e.complexity.Config.GithubClientSecret == nil {
+ break
+ }
+
+ return e.complexity.Config.GithubClientSecret(childComplexity), true
+
+ case "Config.GOOGLE_CLIENT_ID":
+ if e.complexity.Config.GoogleClientID == nil {
+ break
+ }
+
+ return e.complexity.Config.GoogleClientID(childComplexity), true
+
+ case "Config.GOOGLE_CLIENT_SECRET":
+ if e.complexity.Config.GoogleClientSecret == nil {
+ break
+ }
+
+ return e.complexity.Config.GoogleClientSecret(childComplexity), true
+
+ case "Config.JWT_ROLE_CLAIM":
+ if e.complexity.Config.JwtRoleClaim == nil {
+ break
+ }
+
+ return e.complexity.Config.JwtRoleClaim(childComplexity), true
+
+ case "Config.JWT_SECRET":
+ if e.complexity.Config.JwtSecret == nil {
+ break
+ }
+
+ return e.complexity.Config.JwtSecret(childComplexity), true
+
+ case "Config.JWT_TYPE":
+ if e.complexity.Config.JwtType == nil {
+ break
+ }
+
+ return e.complexity.Config.JwtType(childComplexity), true
+
+ case "Config.ORGANIZATION_LOGO":
+ if e.complexity.Config.OrganizationLogo == nil {
+ break
+ }
+
+ return e.complexity.Config.OrganizationLogo(childComplexity), true
+
+ case "Config.ORGANIZATION_NAME":
+ if e.complexity.Config.OrganizationName == nil {
+ break
+ }
+
+ return e.complexity.Config.OrganizationName(childComplexity), true
+
+ case "Config.PROTECTED_ROLES":
+ if e.complexity.Config.ProtectedRoles == nil {
+ break
+ }
+
+ return e.complexity.Config.ProtectedRoles(childComplexity), true
+
+ case "Config.REDIS_URL":
+ if e.complexity.Config.RedisURL == nil {
+ break
+ }
+
+ return e.complexity.Config.RedisURL(childComplexity), true
+
+ case "Config.RESET_PASSWORD_URL":
+ if e.complexity.Config.ResetPasswordURL == nil {
+ break
+ }
+
+ return e.complexity.Config.ResetPasswordURL(childComplexity), true
+
+ case "Config.ROLES":
+ if e.complexity.Config.Roles == nil {
+ break
+ }
+
+ return e.complexity.Config.Roles(childComplexity), true
+
+ case "Config.SMTP_HOST":
+ if e.complexity.Config.SMTPHost == nil {
+ break
+ }
+
+ return e.complexity.Config.SMTPHost(childComplexity), true
+
+ case "Config.SMTP_PASSWORD":
+ if e.complexity.Config.SMTPPassword == nil {
+ break
+ }
+
+ return e.complexity.Config.SMTPPassword(childComplexity), true
+
+ case "Config.SMTP_PORT":
+ if e.complexity.Config.SMTPPort == nil {
+ break
+ }
+
+ return e.complexity.Config.SMTPPort(childComplexity), true
+
+ case "Config.SMTP_USERNAME":
+ if e.complexity.Config.SMTPUsername == nil {
+ break
+ }
+
+ return e.complexity.Config.SMTPUsername(childComplexity), true
+
+ case "Config.SENDER_EMAIL":
+ if e.complexity.Config.SenderEmail == nil {
+ break
+ }
+
+ return e.complexity.Config.SenderEmail(childComplexity), true
+
case "Error.message":
if e.complexity.Error.Message == nil {
break
@@ -249,6 +528,37 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Meta.Version(childComplexity), true
+ case "Mutation._admin_login":
+ if e.complexity.Mutation.AdminLogin == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation__admin_login_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.AdminLogin(childComplexity, args["params"].(model.AdminLoginInput)), true
+
+ case "Mutation._admin_logout":
+ if e.complexity.Mutation.AdminLogout == nil {
+ break
+ }
+
+ return e.complexity.Mutation.AdminLogout(childComplexity), true
+
+ case "Mutation._admin_signup":
+ if e.complexity.Mutation.AdminSignup == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation__admin_signup_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.AdminSignup(childComplexity, args["params"].(model.AdminSignupInput)), true
+
case "Mutation._delete_user":
if e.complexity.Mutation.DeleteUser == nil {
break
@@ -340,6 +650,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.Signup(childComplexity, args["params"].(model.SignUpInput)), true
+ case "Mutation._update_config":
+ if e.complexity.Mutation.UpdateConfig == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation__update_config_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.UpdateConfig(childComplexity, args["params"].(model.UpdateConfigInput)), true
+
case "Mutation.update_profile":
if e.complexity.Mutation.UpdateProfile == nil {
break
@@ -376,6 +698,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.VerifyEmail(childComplexity, args["params"].(model.VerifyEmailInput)), true
+ case "Query._admin_session":
+ if e.complexity.Query.AdminSession == nil {
+ break
+ }
+
+ return e.complexity.Query.AdminSession(childComplexity), true
+
+ case "Query._config":
+ if e.complexity.Query.Config == nil {
+ break
+ }
+
+ return e.complexity.Query.Config(childComplexity), true
+
case "Query.meta":
if e.complexity.Query.Meta == nil {
break
@@ -719,6 +1055,85 @@ type Response {
message: String!
}
+type Config {
+ ADMIN_SECRET: String
+ DATABASE_TYPE: String
+ DATABASE_URL: String
+ DATABASE_NAME: String
+ SMTP_HOST: String
+ SMTP_PORT: String
+ SMTP_USERNAME: String
+ SMTP_PASSWORD: String
+ SENDER_EMAIL: String
+ JWT_TYPE: String
+ JWT_SECRET: String
+ ALLOWED_ORIGINS: [String!]
+ AUTHORIZER_URL: String
+ APP_URL: String
+ REDIS_URL: String
+ COOKIE_NAME: String
+ RESET_PASSWORD_URL: String
+ DISABLE_EMAIL_VERIFICATION: Boolean
+ DISABLE_BASIC_AUTHENTICATION: Boolean
+ DISABLE_MAGIC_LINK_LOGIN: Boolean
+ DISABLE_LOGIN_PAGE: Boolean
+ ROLES: [String!]
+ PROTECTED_ROLES: [String!]
+ DEFAULT_ROLES: [String!]
+ JWT_ROLE_CLAIM: String
+ GOOGLE_CLIENT_ID: String
+ GOOGLE_CLIENT_SECRET: String
+ GITHUB_CLIENT_ID: String
+ GITHUB_CLIENT_SECRET: String
+ FACEBOOK_CLIENT_ID: String
+ FACEBOOK_CLIENT_SECRET: String
+ ORGANIZATION_NAME: String
+ ORGANIZATION_LOGO: String
+}
+
+input UpdateConfigInput {
+ ADMIN_SECRET: String
+ DATABASE_TYPE: String
+ DATABASE_URL: String
+ DATABASE_NAME: String
+ SMTP_HOST: String
+ SMTP_PORT: String
+ SENDER_EMAIL: String
+ SENDER_PASSWORD: String
+ JWT_TYPE: String
+ JWT_SECRET: String
+ ALLOWED_ORIGINS: [String!]
+ AUTHORIZER_URL: String
+ APP_URL: String
+ REDIS_URL: String
+ COOKIE_NAME: String
+ RESET_PASSWORD_URL: String
+ DISABLE_EMAIL_VERIFICATION: Boolean
+ DISABLE_BASIC_AUTHENTICATION: Boolean
+ DISABLE_MAGIC_LINK_LOGIN: Boolean
+ DISABLE_LOGIN_PAGE: Boolean
+ ROLES: [String!]
+ PROTECTED_ROLES: [String!]
+ DEFAULT_ROLES: [String!]
+ JWT_ROLE_CLAIM: String
+ GOOGLE_CLIENT_ID: String
+ GOOGLE_CLIENT_SECRET: String
+ GITHUB_CLIENT_ID: String
+ GITHUB_CLIENT_SECRET: String
+ FACEBOOK_CLIENT_ID: String
+ FACEBOOK_CLIENT_SECRET: String
+ ORGANIZATION_NAME: String
+ ORGANIZATION_LOGO: String
+}
+
+input AdminLoginInput {
+ admin_secret: String!
+}
+
+input AdminSignupInput {
+ admin_secret: String!
+}
+
input SignUpInput {
email: String!
given_name: String
@@ -810,15 +1225,21 @@ type Mutation {
# admin only apis
_delete_user(params: DeleteUserInput!): Response!
_update_user(params: UpdateUserInput!): User!
+ _admin_signup(params: AdminSignupInput!): Response!
+ _admin_login(params: AdminLoginInput!): Response!
+ _admin_logout: Response!
+ _update_config(params: UpdateConfigInput!): Response!
}
type Query {
meta: Meta!
- session(roles: [String!]): AuthResponse
+ session(roles: [String!]): AuthResponse!
profile: User!
# admin only apis
_users: [User!]!
_verification_requests: [VerificationRequest!]!
+ _admin_session: Response!
+ _config: Config!
}
`, BuiltIn: false},
}
@@ -828,6 +1249,36 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...)
// region ***************************** args.gotpl *****************************
+func (ec *executionContext) field_Mutation__admin_login_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, 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["params"] = arg0
+ return args, 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
+ 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
+ }
+ }
+ args["params"] = arg0
+ return args, 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{}{}
@@ -843,6 +1294,21 @@ func (ec *executionContext) field_Mutation__delete_user_args(ctx context.Context
return args, nil
}
+func (ec *executionContext) field_Mutation__update_config_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+ var err error
+ args := map[string]interface{}{}
+ var arg0 model.UpdateConfigInput
+ if tmp, ok := rawArgs["params"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params"))
+ arg0, err = ec.unmarshalNUpdateConfigInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateConfigInput(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["params"] = arg0
+ return args, nil
+}
+
func (ec *executionContext) field_Mutation__update_user_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
@@ -1177,6 +1643,1062 @@ func (ec *executionContext) _AuthResponse_user(ctx context.Context, field graphq
return ec.marshalOUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res)
}
+func (ec *executionContext) _Config_ADMIN_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.AdminSecret, 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) _Config_DATABASE_TYPE(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DatabaseType, 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) _Config_DATABASE_URL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DatabaseURL, 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) _Config_DATABASE_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DatabaseName, 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) _Config_SMTP_HOST(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.SMTPHost, 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) _Config_SMTP_PORT(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.SMTPPort, 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) _Config_SMTP_USERNAME(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.SMTPUsername, 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) _Config_SMTP_PASSWORD(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.SMTPPassword, 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) _Config_SENDER_EMAIL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.SenderEmail, 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) _Config_JWT_TYPE(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.JwtType, 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) _Config_JWT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.JwtSecret, 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) _Config_ALLOWED_ORIGINS(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.AllowedOrigins, 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) _Config_AUTHORIZER_URL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.AuthorizerURL, 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) _Config_APP_URL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.AppURL, 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) _Config_REDIS_URL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.RedisURL, 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) _Config_COOKIE_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.CookieName, 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) _Config_RESET_PASSWORD_URL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.ResetPasswordURL, 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) _Config_DISABLE_EMAIL_VERIFICATION(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DisableEmailVerification, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*bool)
+ fc.Result = res
+ return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) _Config_DISABLE_BASIC_AUTHENTICATION(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DisableBasicAuthentication, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*bool)
+ fc.Result = res
+ return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) _Config_DISABLE_MAGIC_LINK_LOGIN(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DisableMagicLinkLogin, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*bool)
+ fc.Result = res
+ return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) _Config_DISABLE_LOGIN_PAGE(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DisableLoginPage, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*bool)
+ fc.Result = res
+ return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) _Config_ROLES(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Roles, 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) _Config_PROTECTED_ROLES(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.ProtectedRoles, 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) _Config_DEFAULT_ROLES(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DefaultRoles, 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) _Config_JWT_ROLE_CLAIM(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.JwtRoleClaim, 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) _Config_GOOGLE_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.GoogleClientID, 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) _Config_GOOGLE_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.GoogleClientSecret, 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) _Config_GITHUB_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.GithubClientID, 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) _Config_GITHUB_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.GithubClientSecret, 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) _Config_FACEBOOK_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.FacebookClientID, 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) _Config_FACEBOOK_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.FacebookClientSecret, 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) _Config_ORGANIZATION_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.OrganizationName, 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) _Config_ORGANIZATION_LOGO(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Config",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.OrganizationLogo, 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) _Error_message(ctx context.Context, field graphql.CollectedField, obj *model.Error) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@@ -1947,6 +3469,167 @@ func (ec *executionContext) _Mutation__update_user(ctx context.Context, field gr
return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res)
}
+func (ec *executionContext) _Mutation__admin_signup(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ Args: nil,
+ IsMethod: true,
+ IsResolver: true,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ rawArgs := field.ArgumentMap(ec.Variables)
+ args, err := ec.field_Mutation__admin_signup_args(ctx, rawArgs)
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ fc.Args = args
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().AdminSignup(rctx, args["params"].(model.AdminSignupInput))
+ })
+ 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) _Mutation__admin_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ Args: nil,
+ IsMethod: true,
+ IsResolver: true,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ rawArgs := field.ArgumentMap(ec.Variables)
+ args, err := ec.field_Mutation__admin_login_args(ctx, rawArgs)
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ fc.Args = args
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().AdminLogin(rctx, args["params"].(model.AdminLoginInput))
+ })
+ 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) _Mutation__admin_logout(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ Args: nil,
+ IsMethod: true,
+ IsResolver: true,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().AdminLogout(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) _Mutation__update_config(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ Args: nil,
+ IsMethod: true,
+ IsResolver: true,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ rawArgs := field.ArgumentMap(ec.Variables)
+ args, err := ec.field_Mutation__update_config_args(ctx, rawArgs)
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ fc.Args = args
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().UpdateConfig(rctx, args["params"].(model.UpdateConfigInput))
+ })
+ 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) _Query_meta(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@@ -2014,11 +3697,14 @@ func (ec *executionContext) _Query_session(ctx context.Context, field graphql.Co
return graphql.Null
}
if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
return graphql.Null
}
res := resTmp.(*model.AuthResponse)
fc.Result = res
- return ec.marshalOAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res)
+ return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res)
}
func (ec *executionContext) _Query_profile(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -2126,6 +3812,76 @@ func (ec *executionContext) _Query__verification_requests(ctx context.Context, f
return ec.marshalNVerificationRequest2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerificationRequestᚄ(ctx, field.Selections, res)
}
+func (ec *executionContext) _Query__admin_session(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Query",
+ Field: field,
+ Args: nil,
+ IsMethod: true,
+ IsResolver: true,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ 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) _Query__config(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Query",
+ Field: field,
+ Args: nil,
+ IsMethod: true,
+ IsResolver: true,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Query().Config(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.Config)
+ fc.Result = res
+ return ec.marshalNConfig2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐConfig(ctx, field.Selections, res)
+}
+
func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@@ -4140,6 +5896,52 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co
// region **************************** input.gotpl *****************************
+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{}) {
+ asMap[k] = v
+ }
+
+ for k, v := range asMap {
+ switch k {
+ case "admin_secret":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("admin_secret"))
+ it.AdminSecret, err = ec.unmarshalNString2string(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ }
+ }
+
+ 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{}) {
+ asMap[k] = v
+ }
+
+ for k, v := range asMap {
+ switch k {
+ case "admin_secret":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("admin_secret"))
+ it.AdminSecret, err = ec.unmarshalNString2string(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ }
+ }
+
+ return it, nil
+}
+
func (ec *executionContext) unmarshalInputDeleteUserInput(ctx context.Context, obj interface{}) (model.DeleteUserInput, error) {
var it model.DeleteUserInput
asMap := map[string]interface{}{}
@@ -4437,6 +6239,277 @@ func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj i
return it, nil
}
+func (ec *executionContext) unmarshalInputUpdateConfigInput(ctx context.Context, obj interface{}) (model.UpdateConfigInput, error) {
+ var it model.UpdateConfigInput
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ for k, v := range asMap {
+ switch k {
+ case "ADMIN_SECRET":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ADMIN_SECRET"))
+ it.AdminSecret, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "DATABASE_TYPE":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DATABASE_TYPE"))
+ it.DatabaseType, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "DATABASE_URL":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DATABASE_URL"))
+ it.DatabaseURL, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "DATABASE_NAME":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DATABASE_NAME"))
+ it.DatabaseName, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "SMTP_HOST":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("SMTP_HOST"))
+ it.SMTPHost, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "SMTP_PORT":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("SMTP_PORT"))
+ it.SMTPPort, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "SENDER_EMAIL":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("SENDER_EMAIL"))
+ it.SenderEmail, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "SENDER_PASSWORD":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("SENDER_PASSWORD"))
+ it.SenderPassword, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "JWT_TYPE":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("JWT_TYPE"))
+ it.JwtType, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "JWT_SECRET":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("JWT_SECRET"))
+ it.JwtSecret, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "ALLOWED_ORIGINS":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ALLOWED_ORIGINS"))
+ it.AllowedOrigins, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "AUTHORIZER_URL":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("AUTHORIZER_URL"))
+ it.AuthorizerURL, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "APP_URL":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("APP_URL"))
+ it.AppURL, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "REDIS_URL":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("REDIS_URL"))
+ it.RedisURL, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "COOKIE_NAME":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("COOKIE_NAME"))
+ it.CookieName, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "RESET_PASSWORD_URL":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("RESET_PASSWORD_URL"))
+ it.ResetPasswordURL, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "DISABLE_EMAIL_VERIFICATION":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_EMAIL_VERIFICATION"))
+ it.DisableEmailVerification, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "DISABLE_BASIC_AUTHENTICATION":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_BASIC_AUTHENTICATION"))
+ it.DisableBasicAuthentication, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "DISABLE_MAGIC_LINK_LOGIN":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_MAGIC_LINK_LOGIN"))
+ it.DisableMagicLinkLogin, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "DISABLE_LOGIN_PAGE":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_LOGIN_PAGE"))
+ it.DisableLoginPage, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "ROLES":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ROLES"))
+ it.Roles, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "PROTECTED_ROLES":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("PROTECTED_ROLES"))
+ it.ProtectedRoles, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "DEFAULT_ROLES":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DEFAULT_ROLES"))
+ it.DefaultRoles, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "JWT_ROLE_CLAIM":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("JWT_ROLE_CLAIM"))
+ it.JwtRoleClaim, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "GOOGLE_CLIENT_ID":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("GOOGLE_CLIENT_ID"))
+ it.GoogleClientID, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "GOOGLE_CLIENT_SECRET":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("GOOGLE_CLIENT_SECRET"))
+ it.GoogleClientSecret, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "GITHUB_CLIENT_ID":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("GITHUB_CLIENT_ID"))
+ it.GithubClientID, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "GITHUB_CLIENT_SECRET":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("GITHUB_CLIENT_SECRET"))
+ it.GithubClientSecret, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "FACEBOOK_CLIENT_ID":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("FACEBOOK_CLIENT_ID"))
+ it.FacebookClientID, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "FACEBOOK_CLIENT_SECRET":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("FACEBOOK_CLIENT_SECRET"))
+ it.FacebookClientSecret, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "ORGANIZATION_NAME":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ORGANIZATION_NAME"))
+ it.OrganizationName, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "ORGANIZATION_LOGO":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ORGANIZATION_LOGO"))
+ it.OrganizationLogo, err = ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ }
+ }
+
+ return it, nil
+}
+
func (ec *executionContext) unmarshalInputUpdateProfileInput(ctx context.Context, obj interface{}) (model.UpdateProfileInput, error) {
var it model.UpdateProfileInput
asMap := map[string]interface{}{}
@@ -4715,6 +6788,94 @@ func (ec *executionContext) _AuthResponse(ctx context.Context, sel ast.Selection
return out
}
+var configImplementors = []string{"Config"}
+
+func (ec *executionContext) _Config(ctx context.Context, sel ast.SelectionSet, obj *model.Config) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, configImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ var invalids uint32
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("Config")
+ case "ADMIN_SECRET":
+ out.Values[i] = ec._Config_ADMIN_SECRET(ctx, field, obj)
+ case "DATABASE_TYPE":
+ out.Values[i] = ec._Config_DATABASE_TYPE(ctx, field, obj)
+ case "DATABASE_URL":
+ out.Values[i] = ec._Config_DATABASE_URL(ctx, field, obj)
+ case "DATABASE_NAME":
+ out.Values[i] = ec._Config_DATABASE_NAME(ctx, field, obj)
+ case "SMTP_HOST":
+ out.Values[i] = ec._Config_SMTP_HOST(ctx, field, obj)
+ case "SMTP_PORT":
+ out.Values[i] = ec._Config_SMTP_PORT(ctx, field, obj)
+ case "SMTP_USERNAME":
+ out.Values[i] = ec._Config_SMTP_USERNAME(ctx, field, obj)
+ case "SMTP_PASSWORD":
+ out.Values[i] = ec._Config_SMTP_PASSWORD(ctx, field, obj)
+ case "SENDER_EMAIL":
+ out.Values[i] = ec._Config_SENDER_EMAIL(ctx, field, obj)
+ case "JWT_TYPE":
+ out.Values[i] = ec._Config_JWT_TYPE(ctx, field, obj)
+ case "JWT_SECRET":
+ out.Values[i] = ec._Config_JWT_SECRET(ctx, field, obj)
+ case "ALLOWED_ORIGINS":
+ out.Values[i] = ec._Config_ALLOWED_ORIGINS(ctx, field, obj)
+ case "AUTHORIZER_URL":
+ out.Values[i] = ec._Config_AUTHORIZER_URL(ctx, field, obj)
+ case "APP_URL":
+ out.Values[i] = ec._Config_APP_URL(ctx, field, obj)
+ case "REDIS_URL":
+ out.Values[i] = ec._Config_REDIS_URL(ctx, field, obj)
+ case "COOKIE_NAME":
+ out.Values[i] = ec._Config_COOKIE_NAME(ctx, field, obj)
+ case "RESET_PASSWORD_URL":
+ out.Values[i] = ec._Config_RESET_PASSWORD_URL(ctx, field, obj)
+ case "DISABLE_EMAIL_VERIFICATION":
+ out.Values[i] = ec._Config_DISABLE_EMAIL_VERIFICATION(ctx, field, obj)
+ case "DISABLE_BASIC_AUTHENTICATION":
+ out.Values[i] = ec._Config_DISABLE_BASIC_AUTHENTICATION(ctx, field, obj)
+ case "DISABLE_MAGIC_LINK_LOGIN":
+ out.Values[i] = ec._Config_DISABLE_MAGIC_LINK_LOGIN(ctx, field, obj)
+ case "DISABLE_LOGIN_PAGE":
+ out.Values[i] = ec._Config_DISABLE_LOGIN_PAGE(ctx, field, obj)
+ case "ROLES":
+ out.Values[i] = ec._Config_ROLES(ctx, field, obj)
+ case "PROTECTED_ROLES":
+ out.Values[i] = ec._Config_PROTECTED_ROLES(ctx, field, obj)
+ case "DEFAULT_ROLES":
+ out.Values[i] = ec._Config_DEFAULT_ROLES(ctx, field, obj)
+ case "JWT_ROLE_CLAIM":
+ out.Values[i] = ec._Config_JWT_ROLE_CLAIM(ctx, field, obj)
+ case "GOOGLE_CLIENT_ID":
+ out.Values[i] = ec._Config_GOOGLE_CLIENT_ID(ctx, field, obj)
+ case "GOOGLE_CLIENT_SECRET":
+ out.Values[i] = ec._Config_GOOGLE_CLIENT_SECRET(ctx, field, obj)
+ case "GITHUB_CLIENT_ID":
+ out.Values[i] = ec._Config_GITHUB_CLIENT_ID(ctx, field, obj)
+ case "GITHUB_CLIENT_SECRET":
+ out.Values[i] = ec._Config_GITHUB_CLIENT_SECRET(ctx, field, obj)
+ case "FACEBOOK_CLIENT_ID":
+ out.Values[i] = ec._Config_FACEBOOK_CLIENT_ID(ctx, field, obj)
+ case "FACEBOOK_CLIENT_SECRET":
+ out.Values[i] = ec._Config_FACEBOOK_CLIENT_SECRET(ctx, field, obj)
+ case "ORGANIZATION_NAME":
+ out.Values[i] = ec._Config_ORGANIZATION_NAME(ctx, field, obj)
+ case "ORGANIZATION_LOGO":
+ out.Values[i] = ec._Config_ORGANIZATION_LOGO(ctx, field, obj)
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch()
+ if invalids > 0 {
+ return graphql.Null
+ }
+ return out
+}
+
var errorImplementors = []string{"Error"}
func (ec *executionContext) _Error(ctx context.Context, sel ast.SelectionSet, obj *model.Error) graphql.Marshaler {
@@ -4874,6 +7035,26 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
invalids++
}
+ case "_admin_signup":
+ out.Values[i] = ec._Mutation__admin_signup(ctx, field)
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
+ case "_admin_login":
+ out.Values[i] = ec._Mutation__admin_login(ctx, field)
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
+ case "_admin_logout":
+ out.Values[i] = ec._Mutation__admin_logout(ctx, field)
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
+ case "_update_config":
+ out.Values[i] = ec._Mutation__update_config(ctx, field)
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@@ -4923,6 +7104,9 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
}
}()
res = ec._Query_session(ctx, field)
+ if res == graphql.Null {
+ atomic.AddUint32(&invalids, 1)
+ }
return res
})
case "profile":
@@ -4967,6 +7151,34 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
}
return res
})
+ case "_admin_session":
+ field := field
+ out.Concurrently(i, func() (res graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ }
+ }()
+ res = ec._Query__admin_session(ctx, field)
+ if res == graphql.Null {
+ atomic.AddUint32(&invalids, 1)
+ }
+ return res
+ })
+ case "_config":
+ field := field
+ out.Concurrently(i, func() (res graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ }
+ }()
+ res = ec._Query__config(ctx, field)
+ if res == graphql.Null {
+ atomic.AddUint32(&invalids, 1)
+ }
+ return res
+ })
case "__type":
out.Values[i] = ec._Query___type(ctx, field)
case "__schema":
@@ -5369,6 +7581,16 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o
// region ***************************** type.gotpl *****************************
+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)
+ 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)
+ 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 {
return ec._AuthResponse(ctx, sel, &v)
}
@@ -5398,6 +7620,20 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se
return res
}
+func (ec *executionContext) marshalNConfig2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐConfig(ctx context.Context, sel ast.SelectionSet, v model.Config) graphql.Marshaler {
+ return ec._Config(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalNConfig2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐConfig(ctx context.Context, sel ast.SelectionSet, v *model.Config) graphql.Marshaler {
+ if v == nil {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ return ec._Config(ctx, sel, v)
+}
+
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)
return res, graphql.ErrorOnPath(ctx, err)
@@ -5527,6 +7763,11 @@ func (ec *executionContext) marshalNString2ᚕstringᚄ(ctx context.Context, sel
return ret
}
+func (ec *executionContext) unmarshalNUpdateConfigInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateConfigInput(ctx context.Context, v interface{}) (model.UpdateConfigInput, error) {
+ res, err := ec.unmarshalInputUpdateConfigInput(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)
return res, graphql.ErrorOnPath(ctx, err)
@@ -5911,13 +8152,6 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a
return res
}
-func (ec *executionContext) marshalOAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx context.Context, sel ast.SelectionSet, v *model.AuthResponse) graphql.Marshaler {
- if v == nil {
- return graphql.Null
- }
- return ec._AuthResponse(ctx, sel, v)
-}
-
func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) {
res, err := graphql.UnmarshalBoolean(v)
return res, graphql.ErrorOnPath(ctx, err)
diff --git a/server/graph/model/models_gen.go b/server/graph/model/models_gen.go
index ffd76ea..acde6b3 100644
--- a/server/graph/model/models_gen.go
+++ b/server/graph/model/models_gen.go
@@ -2,6 +2,14 @@
package model
+type AdminLoginInput struct {
+ AdminSecret string `json:"admin_secret"`
+}
+
+type AdminSignupInput struct {
+ AdminSecret string `json:"admin_secret"`
+}
+
type AuthResponse struct {
Message string `json:"message"`
AccessToken *string `json:"access_token"`
@@ -9,6 +17,42 @@ type AuthResponse struct {
User *User `json:"user"`
}
+type Config struct {
+ AdminSecret *string `json:"ADMIN_SECRET"`
+ DatabaseType *string `json:"DATABASE_TYPE"`
+ DatabaseURL *string `json:"DATABASE_URL"`
+ DatabaseName *string `json:"DATABASE_NAME"`
+ SMTPHost *string `json:"SMTP_HOST"`
+ SMTPPort *string `json:"SMTP_PORT"`
+ SMTPUsername *string `json:"SMTP_USERNAME"`
+ SMTPPassword *string `json:"SMTP_PASSWORD"`
+ SenderEmail *string `json:"SENDER_EMAIL"`
+ JwtType *string `json:"JWT_TYPE"`
+ JwtSecret *string `json:"JWT_SECRET"`
+ AllowedOrigins []string `json:"ALLOWED_ORIGINS"`
+ AuthorizerURL *string `json:"AUTHORIZER_URL"`
+ AppURL *string `json:"APP_URL"`
+ RedisURL *string `json:"REDIS_URL"`
+ CookieName *string `json:"COOKIE_NAME"`
+ ResetPasswordURL *string `json:"RESET_PASSWORD_URL"`
+ DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION"`
+ DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION"`
+ DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN"`
+ DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE"`
+ Roles []string `json:"ROLES"`
+ ProtectedRoles []string `json:"PROTECTED_ROLES"`
+ DefaultRoles []string `json:"DEFAULT_ROLES"`
+ JwtRoleClaim *string `json:"JWT_ROLE_CLAIM"`
+ GoogleClientID *string `json:"GOOGLE_CLIENT_ID"`
+ GoogleClientSecret *string `json:"GOOGLE_CLIENT_SECRET"`
+ GithubClientID *string `json:"GITHUB_CLIENT_ID"`
+ GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"`
+ FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"`
+ FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"`
+ OrganizationName *string `json:"ORGANIZATION_NAME"`
+ OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
+}
+
type DeleteUserInput struct {
Email string `json:"email"`
}
@@ -73,6 +117,41 @@ type SignUpInput struct {
Roles []string `json:"roles"`
}
+type UpdateConfigInput struct {
+ AdminSecret *string `json:"ADMIN_SECRET"`
+ DatabaseType *string `json:"DATABASE_TYPE"`
+ DatabaseURL *string `json:"DATABASE_URL"`
+ DatabaseName *string `json:"DATABASE_NAME"`
+ SMTPHost *string `json:"SMTP_HOST"`
+ SMTPPort *string `json:"SMTP_PORT"`
+ SenderEmail *string `json:"SENDER_EMAIL"`
+ SenderPassword *string `json:"SENDER_PASSWORD"`
+ JwtType *string `json:"JWT_TYPE"`
+ JwtSecret *string `json:"JWT_SECRET"`
+ AllowedOrigins []string `json:"ALLOWED_ORIGINS"`
+ AuthorizerURL *string `json:"AUTHORIZER_URL"`
+ AppURL *string `json:"APP_URL"`
+ RedisURL *string `json:"REDIS_URL"`
+ CookieName *string `json:"COOKIE_NAME"`
+ ResetPasswordURL *string `json:"RESET_PASSWORD_URL"`
+ DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION"`
+ DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION"`
+ DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN"`
+ DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE"`
+ Roles []string `json:"ROLES"`
+ ProtectedRoles []string `json:"PROTECTED_ROLES"`
+ DefaultRoles []string `json:"DEFAULT_ROLES"`
+ JwtRoleClaim *string `json:"JWT_ROLE_CLAIM"`
+ GoogleClientID *string `json:"GOOGLE_CLIENT_ID"`
+ GoogleClientSecret *string `json:"GOOGLE_CLIENT_SECRET"`
+ GithubClientID *string `json:"GITHUB_CLIENT_ID"`
+ GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"`
+ FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"`
+ FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"`
+ OrganizationName *string `json:"ORGANIZATION_NAME"`
+ OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
+}
+
type UpdateProfileInput struct {
OldPassword *string `json:"old_password"`
NewPassword *string `json:"new_password"`
diff --git a/server/graph/schema.graphqls b/server/graph/schema.graphqls
index 4353073..741e9dd 100644
--- a/server/graph/schema.graphqls
+++ b/server/graph/schema.graphqls
@@ -62,6 +62,85 @@ type Response {
message: String!
}
+type Config {
+ ADMIN_SECRET: String
+ DATABASE_TYPE: String
+ DATABASE_URL: String
+ DATABASE_NAME: String
+ SMTP_HOST: String
+ SMTP_PORT: String
+ SMTP_USERNAME: String
+ SMTP_PASSWORD: String
+ SENDER_EMAIL: String
+ JWT_TYPE: String
+ JWT_SECRET: String
+ ALLOWED_ORIGINS: [String!]
+ AUTHORIZER_URL: String
+ APP_URL: String
+ REDIS_URL: String
+ COOKIE_NAME: String
+ RESET_PASSWORD_URL: String
+ DISABLE_EMAIL_VERIFICATION: Boolean
+ DISABLE_BASIC_AUTHENTICATION: Boolean
+ DISABLE_MAGIC_LINK_LOGIN: Boolean
+ DISABLE_LOGIN_PAGE: Boolean
+ ROLES: [String!]
+ PROTECTED_ROLES: [String!]
+ DEFAULT_ROLES: [String!]
+ JWT_ROLE_CLAIM: String
+ GOOGLE_CLIENT_ID: String
+ GOOGLE_CLIENT_SECRET: String
+ GITHUB_CLIENT_ID: String
+ GITHUB_CLIENT_SECRET: String
+ FACEBOOK_CLIENT_ID: String
+ FACEBOOK_CLIENT_SECRET: String
+ ORGANIZATION_NAME: String
+ ORGANIZATION_LOGO: String
+}
+
+input UpdateConfigInput {
+ ADMIN_SECRET: String
+ DATABASE_TYPE: String
+ DATABASE_URL: String
+ DATABASE_NAME: String
+ SMTP_HOST: String
+ SMTP_PORT: String
+ SENDER_EMAIL: String
+ SENDER_PASSWORD: String
+ JWT_TYPE: String
+ JWT_SECRET: String
+ ALLOWED_ORIGINS: [String!]
+ AUTHORIZER_URL: String
+ APP_URL: String
+ REDIS_URL: String
+ COOKIE_NAME: String
+ RESET_PASSWORD_URL: String
+ DISABLE_EMAIL_VERIFICATION: Boolean
+ DISABLE_BASIC_AUTHENTICATION: Boolean
+ DISABLE_MAGIC_LINK_LOGIN: Boolean
+ DISABLE_LOGIN_PAGE: Boolean
+ ROLES: [String!]
+ PROTECTED_ROLES: [String!]
+ DEFAULT_ROLES: [String!]
+ JWT_ROLE_CLAIM: String
+ GOOGLE_CLIENT_ID: String
+ GOOGLE_CLIENT_SECRET: String
+ GITHUB_CLIENT_ID: String
+ GITHUB_CLIENT_SECRET: String
+ FACEBOOK_CLIENT_ID: String
+ FACEBOOK_CLIENT_SECRET: String
+ ORGANIZATION_NAME: String
+ ORGANIZATION_LOGO: String
+}
+
+input AdminLoginInput {
+ admin_secret: String!
+}
+
+input AdminSignupInput {
+ admin_secret: String!
+}
+
input SignUpInput {
email: String!
given_name: String
@@ -153,13 +232,19 @@ type Mutation {
# admin only apis
_delete_user(params: DeleteUserInput!): Response!
_update_user(params: UpdateUserInput!): User!
+ _admin_signup(params: AdminSignupInput!): Response!
+ _admin_login(params: AdminLoginInput!): Response!
+ _admin_logout: Response!
+ _update_config(params: UpdateConfigInput!): Response!
}
type Query {
meta: Meta!
- session(roles: [String!]): AuthResponse
+ session(roles: [String!]): AuthResponse!
profile: User!
# admin only apis
_users: [User!]!
_verification_requests: [VerificationRequest!]!
+ _admin_session: Response!
+ _config: Config!
}
diff --git a/server/graph/schema.resolvers.go b/server/graph/schema.resolvers.go
index 9510800..52aa7c4 100644
--- a/server/graph/schema.resolvers.go
+++ b/server/graph/schema.resolvers.go
@@ -55,6 +55,22 @@ func (r *mutationResolver) UpdateUser(ctx context.Context, params model.UpdateUs
return resolvers.UpdateUser(ctx, params)
}
+func (r *mutationResolver) AdminSignup(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) {
+ return resolvers.AdminSignupResolver(ctx, params)
+}
+
+func (r *mutationResolver) AdminLogin(ctx context.Context, params model.AdminLoginInput) (*model.Response, error) {
+ return resolvers.AdminLoginResolver(ctx, params)
+}
+
+func (r *mutationResolver) AdminLogout(ctx context.Context) (*model.Response, error) {
+ return resolvers.AdminLogout(ctx)
+}
+
+func (r *mutationResolver) UpdateConfig(ctx context.Context, params model.UpdateConfigInput) (*model.Response, error) {
+ return resolvers.UpdateConfigResolver(ctx, params)
+}
+
func (r *queryResolver) Meta(ctx context.Context) (*model.Meta, error) {
return resolvers.Meta(ctx)
}
@@ -75,13 +91,19 @@ func (r *queryResolver) VerificationRequests(ctx context.Context) ([]*model.Veri
return resolvers.VerificationRequests(ctx)
}
+func (r *queryResolver) AdminSession(ctx context.Context) (*model.Response, error) {
+ return resolvers.AdminSession(ctx)
+}
+
+func (r *queryResolver) Config(ctx context.Context) (*model.Config, error) {
+ return resolvers.ConfigResolver(ctx)
+}
+
// Mutation returns generated.MutationResolver implementation.
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }
// Query returns generated.QueryResolver implementation.
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
-type (
- mutationResolver struct{ *Resolver }
- queryResolver struct{ *Resolver }
-)
+type mutationResolver struct{ *Resolver }
+type queryResolver struct{ *Resolver }
diff --git a/server/handlers/app.go b/server/handlers/app.go
index 4fb7070..e2569e4 100644
--- a/server/handlers/app.go
+++ b/server/handlers/app.go
@@ -1,7 +1,6 @@
package handlers
import (
- "encoding/base64"
"encoding/json"
"log"
"net/http"
@@ -30,17 +29,17 @@ func AppHandler() gin.HandlerFunc {
// return
// }
- stateObj.AuthorizerURL = constants.AUTHORIZER_URL
- stateObj.RedirectURL = constants.AUTHORIZER_URL + "/app"
+ stateObj.AuthorizerURL = constants.EnvData.AUTHORIZER_URL
+ stateObj.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/app"
} else {
- decodedState, err := base64.StdEncoding.DecodeString(state)
+ decodedState, err := utils.DecryptB64(state)
if err != nil {
c.JSON(400, gin.H{"error": "[unable to decode state] invalid state"})
return
}
- err = json.Unmarshal(decodedState, &stateObj)
+ err = json.Unmarshal([]byte(decodedState), &stateObj)
if err != nil {
c.JSON(400, gin.H{"error": "[unable to parse state] invalid state"})
return
@@ -60,7 +59,7 @@ func AppHandler() gin.HandlerFunc {
}
// validate host and domain of authorizer url
- if strings.TrimSuffix(stateObj.AuthorizerURL, "/") != constants.AUTHORIZER_URL {
+ if strings.TrimSuffix(stateObj.AuthorizerURL, "/") != constants.EnvData.AUTHORIZER_URL {
c.JSON(400, gin.H{"error": "invalid host url"})
return
}
@@ -77,8 +76,8 @@ func AppHandler() gin.HandlerFunc {
"data": map[string]string{
"authorizerURL": stateObj.AuthorizerURL,
"redirectURL": stateObj.RedirectURL,
- "organizationName": constants.ORGANIZATION_NAME,
- "organizationLogo": constants.ORGANIZATION_LOGO,
+ "organizationName": constants.EnvData.ORGANIZATION_NAME,
+ "organizationLogo": constants.EnvData.ORGANIZATION_LOGO,
},
})
}
diff --git a/server/handlers/dashboard.go b/server/handlers/dashboard.go
new file mode 100644
index 0000000..f16e442
--- /dev/null
+++ b/server/handlers/dashboard.go
@@ -0,0 +1,24 @@
+package handlers
+
+import (
+ "net/http"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/gin-gonic/gin"
+)
+
+func DashboardHandler() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ isOnboardingCompleted := false
+
+ if constants.EnvData.ADMIN_SECRET != "" {
+ isOnboardingCompleted = true
+ }
+
+ c.HTML(http.StatusOK, "dashboard.tmpl", gin.H{
+ "data": map[string]interface{}{
+ "isOnboardingCompleted": isOnboardingCompleted,
+ },
+ })
+ }
+}
diff --git a/server/handlers/oauth_callback.go b/server/handlers/oauth_callback.go
index 4fd0364..a6c922a 100644
--- a/server/handlers/oauth_callback.go
+++ b/server/handlers/oauth_callback.go
@@ -195,7 +195,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
// make sure inputRoles don't include protected roles
hasProtectedRole := false
for _, ir := range inputRoles {
- if utils.StringSliceContains(constants.PROTECTED_ROLES, ir) {
+ if utils.StringSliceContains(constants.EnvData.PROTECTED_ROLES, ir) {
hasProtectedRole = true
}
}
@@ -238,7 +238,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
// check if it contains protected unassigned role
hasProtectedRole := false
for _, ur := range unasignedRoles {
- if utils.StringSliceContains(constants.PROTECTED_ROLES, ur) {
+ if utils.StringSliceContains(constants.EnvData.PROTECTED_ROLES, ur) {
hasProtectedRole = true
}
}
diff --git a/server/handlers/oauth_login.go b/server/handlers/oauth_login.go
index 1f3cd4e..0363f70 100644
--- a/server/handlers/oauth_login.go
+++ b/server/handlers/oauth_login.go
@@ -34,14 +34,14 @@ func OAuthLoginHandler() gin.HandlerFunc {
// use protected roles verification for admin login only.
// though if not associated with user, it will be rejected from oauth_callback
- if !utils.IsValidRoles(append([]string{}, append(constants.ROLES, constants.PROTECTED_ROLES...)...), rolesSplit) {
+ if !utils.IsValidRoles(append([]string{}, append(constants.EnvData.ROLES, constants.EnvData.PROTECTED_ROLES...)...), rolesSplit) {
c.JSON(400, gin.H{
"error": "invalid role",
})
return
}
} else {
- roles = strings.Join(constants.DEFAULT_ROLES, ",")
+ roles = strings.Join(constants.EnvData.DEFAULT_ROLES, ",")
}
uuid := uuid.New()
@@ -57,7 +57,7 @@ func OAuthLoginHandler() gin.HandlerFunc {
}
session.SetSocailLoginState(oauthStateString, enum.Google.String())
// during the init of OAuthProvider authorizer url might be empty
- oauth.OAuthProviders.GoogleConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/google"
+ oauth.OAuthProviders.GoogleConfig.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/oauth_callback/google"
url := oauth.OAuthProviders.GoogleConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url)
case enum.Github.String():
@@ -66,7 +66,7 @@ func OAuthLoginHandler() gin.HandlerFunc {
break
}
session.SetSocailLoginState(oauthStateString, enum.Github.String())
- oauth.OAuthProviders.GithubConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/github"
+ oauth.OAuthProviders.GithubConfig.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/oauth_callback/github"
url := oauth.OAuthProviders.GithubConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url)
case enum.Facebook.String():
@@ -75,7 +75,7 @@ func OAuthLoginHandler() gin.HandlerFunc {
break
}
session.SetSocailLoginState(oauthStateString, enum.Facebook.String())
- oauth.OAuthProviders.FacebookConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/facebook"
+ oauth.OAuthProviders.FacebookConfig.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/oauth_callback/facebook"
url := oauth.OAuthProviders.FacebookConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url)
default:
diff --git a/server/main.go b/server/main.go
index c709788..7e7c88e 100644
--- a/server/main.go
+++ b/server/main.go
@@ -22,20 +22,22 @@ func main() {
env.ARG_ENV_FILE = flag.String("env_file", "", "Env file path")
flag.Parse()
- constants.VERSION = VERSION
+ constants.EnvData.VERSION = VERSION
env.InitEnv()
db.InitDB()
+ env.PersistEnv()
+
session.InitSession()
oauth.InitOAuth()
utils.InitServer()
router := router.InitRouter()
+ router.LoadHTMLGlob("templates/*")
// login page app related routes.
// if we put them in router file then tests would fail as templates or build path will be different
- if !constants.DISABLE_LOGIN_PAGE {
- router.LoadHTMLGlob("templates/*")
+ if !constants.EnvData.DISABLE_LOGIN_PAGE {
app := router.Group("/app")
{
app.Static("/build", "app/build")
@@ -44,5 +46,11 @@ func main() {
}
}
- router.Run(":" + constants.PORT)
+ app := router.Group("/dashboard")
+ {
+ app.Static("/build", "dashboard/build")
+ app.GET("/", handlers.DashboardHandler())
+ }
+
+ router.Run(":" + constants.EnvData.PORT)
}
diff --git a/server/middlewares/context.go b/server/middlewares/context.go
index 32e824b..fd205ac 100644
--- a/server/middlewares/context.go
+++ b/server/middlewares/context.go
@@ -11,10 +11,10 @@ import (
func GinContextToContextMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
- if constants.AUTHORIZER_URL == "" {
+ if constants.EnvData.AUTHORIZER_URL == "" {
url := location.Get(c)
- constants.AUTHORIZER_URL = url.Scheme + "://" + c.Request.Host
- log.Println("authorizer url:", constants.AUTHORIZER_URL)
+ constants.EnvData.AUTHORIZER_URL = url.Scheme + "://" + c.Request.Host
+ log.Println("authorizer url:", constants.EnvData.AUTHORIZER_URL)
}
ctx := context.WithValue(c.Request.Context(), "GinContextKey", c)
c.Request = c.Request.WithContext(ctx)
diff --git a/server/middlewares/cors.go b/server/middlewares/cors.go
index e0bb4a9..f093e8a 100644
--- a/server/middlewares/cors.go
+++ b/server/middlewares/cors.go
@@ -1,7 +1,6 @@
package middlewares
import (
- "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/gin-gonic/gin"
)
@@ -9,7 +8,6 @@ import (
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
origin := c.Request.Header.Get("Origin")
- constants.APP_URL = origin
if utils.IsValidOrigin(origin) {
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
diff --git a/server/oauth/oauth.go b/server/oauth/oauth.go
index 64b6927..5c6d943 100644
--- a/server/oauth/oauth.go
+++ b/server/oauth/oauth.go
@@ -28,33 +28,33 @@ var (
func InitOAuth() {
ctx := context.Background()
- if constants.GOOGLE_CLIENT_ID != "" && constants.GOOGLE_CLIENT_SECRET != "" {
+ if constants.EnvData.GOOGLE_CLIENT_ID != "" && constants.EnvData.GOOGLE_CLIENT_SECRET != "" {
p, err := oidc.NewProvider(ctx, "https://accounts.google.com")
if err != nil {
log.Fatalln("error creating oidc provider for google:", err)
}
OIDCProviders.GoogleOIDC = p
OAuthProviders.GoogleConfig = &oauth2.Config{
- ClientID: constants.GOOGLE_CLIENT_ID,
- ClientSecret: constants.GOOGLE_CLIENT_SECRET,
- RedirectURL: constants.AUTHORIZER_URL + "/oauth_callback/google",
+ ClientID: constants.EnvData.GOOGLE_CLIENT_ID,
+ ClientSecret: constants.EnvData.GOOGLE_CLIENT_SECRET,
+ RedirectURL: constants.EnvData.AUTHORIZER_URL + "/oauth_callback/google",
Endpoint: OIDCProviders.GoogleOIDC.Endpoint(),
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
}
}
- if constants.GITHUB_CLIENT_ID != "" && constants.GITHUB_CLIENT_SECRET != "" {
+ if constants.EnvData.GITHUB_CLIENT_ID != "" && constants.EnvData.GITHUB_CLIENT_SECRET != "" {
OAuthProviders.GithubConfig = &oauth2.Config{
- ClientID: constants.GITHUB_CLIENT_ID,
- ClientSecret: constants.GITHUB_CLIENT_SECRET,
- RedirectURL: constants.AUTHORIZER_URL + "/oauth_callback/github",
+ ClientID: constants.EnvData.GITHUB_CLIENT_ID,
+ ClientSecret: constants.EnvData.GITHUB_CLIENT_SECRET,
+ RedirectURL: constants.EnvData.AUTHORIZER_URL + "/oauth_callback/github",
Endpoint: githubOAuth2.Endpoint,
}
}
- if constants.FACEBOOK_CLIENT_ID != "" && constants.FACEBOOK_CLIENT_SECRET != "" {
+ if constants.EnvData.FACEBOOK_CLIENT_ID != "" && constants.EnvData.FACEBOOK_CLIENT_SECRET != "" {
OAuthProviders.FacebookConfig = &oauth2.Config{
- ClientID: constants.FACEBOOK_CLIENT_ID,
- ClientSecret: constants.FACEBOOK_CLIENT_SECRET,
- RedirectURL: constants.AUTHORIZER_URL + "/oauth_callback/facebook",
+ ClientID: constants.EnvData.FACEBOOK_CLIENT_ID,
+ ClientSecret: constants.EnvData.FACEBOOK_CLIENT_SECRET,
+ RedirectURL: constants.EnvData.AUTHORIZER_URL + "/oauth_callback/facebook",
Endpoint: facebookOAuth2.Endpoint,
Scopes: []string{"public_profile", "email"},
}
diff --git a/server/resolvers/admin_login.go b/server/resolvers/admin_login.go
new file mode 100644
index 0000000..e829454
--- /dev/null
+++ b/server/resolvers/admin_login.go
@@ -0,0 +1,34 @@
+package resolvers
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/graph/model"
+ "github.com/authorizerdev/authorizer/server/utils"
+)
+
+func AdminLoginResolver(ctx context.Context, params model.AdminLoginInput) (*model.Response, error) {
+ gc, err := utils.GinContextFromContext(ctx)
+ var res *model.Response
+
+ if err != nil {
+ return res, err
+ }
+
+ if params.AdminSecret != constants.EnvData.ADMIN_SECRET {
+ return res, fmt.Errorf(`invalid admin secret`)
+ }
+
+ hashedKey, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
+ if err != nil {
+ return res, err
+ }
+ utils.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
new file mode 100644
index 0000000..d6bb2f8
--- /dev/null
+++ b/server/resolvers/admin_logout.go
@@ -0,0 +1,29 @@
+package resolvers
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/authorizerdev/authorizer/server/graph/model"
+ "github.com/authorizerdev/authorizer/server/utils"
+)
+
+func AdminLogout(ctx context.Context) (*model.Response, error) {
+ gc, err := utils.GinContextFromContext(ctx)
+ var res *model.Response
+
+ if err != nil {
+ return res, err
+ }
+
+ if !utils.IsSuperAdmin(gc) {
+ return res, fmt.Errorf("unauthorized")
+ }
+
+ utils.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
new file mode 100644
index 0000000..50a5ab6
--- /dev/null
+++ b/server/resolvers/admin_session.go
@@ -0,0 +1,34 @@
+package resolvers
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/graph/model"
+ "github.com/authorizerdev/authorizer/server/utils"
+)
+
+func AdminSession(ctx context.Context) (*model.Response, error) {
+ gc, err := utils.GinContextFromContext(ctx)
+ var res *model.Response
+
+ if err != nil {
+ return res, err
+ }
+
+ if !utils.IsSuperAdmin(gc) {
+ return res, fmt.Errorf("unauthorized")
+ }
+
+ hashedKey, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
+ if err != nil {
+ return res, err
+ }
+ utils.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
new file mode 100644
index 0000000..2a943de
--- /dev/null
+++ b/server/resolvers/admin_signup.go
@@ -0,0 +1,77 @@
+package resolvers
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "strings"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/db"
+ "github.com/authorizerdev/authorizer/server/graph/model"
+ "github.com/authorizerdev/authorizer/server/utils"
+)
+
+func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) {
+ gc, err := utils.GinContextFromContext(ctx)
+ var res *model.Response
+
+ if err != nil {
+ return res, err
+ }
+
+ if strings.TrimSpace(params.AdminSecret) == "" {
+ err = fmt.Errorf("please select secure admin secret")
+ return res, err
+ }
+
+ if len(params.AdminSecret) < 6 {
+ err = fmt.Errorf("admin secret must be at least 6 characters")
+ return res, err
+ }
+
+ if constants.EnvData.ADMIN_SECRET != "" {
+ err = fmt.Errorf("admin sign up already completed")
+ return res, err
+ }
+
+ constants.EnvData.ADMIN_SECRET = params.AdminSecret
+
+ // consvert EnvData to JSON
+ var jsonData map[string]interface{}
+
+ jsonBytes, err := json.Marshal(constants.EnvData)
+ if err != nil {
+ return res, err
+ }
+
+ if err := json.Unmarshal(jsonBytes, &jsonData); err != nil {
+ return res, err
+ }
+
+ config, err := db.Mgr.GetConfig()
+ if err != nil {
+ return res, err
+ }
+
+ configData, err := utils.EncryptConfig(jsonData)
+ if err != nil {
+ return res, err
+ }
+
+ config.Config = configData
+ if _, err := db.Mgr.UpdateConfig(config); err != nil {
+ return res, err
+ }
+
+ hashedKey, err := utils.HashPassword(params.AdminSecret)
+ if err != nil {
+ return res, err
+ }
+ utils.SetAdminCookie(gc, hashedKey)
+
+ res = &model.Response{
+ Message: "admin signed up successfully",
+ }
+ return res, nil
+}
diff --git a/server/resolvers/config.go b/server/resolvers/config.go
new file mode 100644
index 0000000..10bdd64
--- /dev/null
+++ b/server/resolvers/config.go
@@ -0,0 +1,60 @@
+package resolvers
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/graph/model"
+ "github.com/authorizerdev/authorizer/server/utils"
+)
+
+func ConfigResolver(ctx context.Context) (*model.Config, error) {
+ gc, err := utils.GinContextFromContext(ctx)
+ var res *model.Config
+
+ if err != nil {
+ return res, err
+ }
+
+ if !utils.IsSuperAdmin(gc) {
+ return res, fmt.Errorf("unauthorized")
+ }
+
+ res = &model.Config{
+ AdminSecret: &constants.EnvData.ADMIN_SECRET,
+ DatabaseType: &constants.EnvData.DATABASE_TYPE,
+ DatabaseURL: &constants.EnvData.DATABASE_URL,
+ DatabaseName: &constants.EnvData.DATABASE_NAME,
+ SMTPHost: &constants.EnvData.SMTP_HOST,
+ SMTPPort: &constants.EnvData.SMTP_PORT,
+ SMTPPassword: &constants.EnvData.SMTP_PASSWORD,
+ SMTPUsername: &constants.EnvData.SMTP_USERNAME,
+ SenderEmail: &constants.EnvData.SENDER_EMAIL,
+ JwtType: &constants.EnvData.JWT_TYPE,
+ JwtSecret: &constants.EnvData.JWT_SECRET,
+ AllowedOrigins: constants.EnvData.ALLOWED_ORIGINS,
+ AuthorizerURL: &constants.EnvData.AUTHORIZER_URL,
+ AppURL: &constants.EnvData.APP_URL,
+ RedisURL: &constants.EnvData.REDIS_URL,
+ CookieName: &constants.EnvData.COOKIE_NAME,
+ ResetPasswordURL: &constants.EnvData.RESET_PASSWORD_URL,
+ DisableEmailVerification: &constants.EnvData.DISABLE_EMAIL_VERIFICATION,
+ DisableBasicAuthentication: &constants.EnvData.DISABLE_BASIC_AUTHENTICATION,
+ DisableMagicLinkLogin: &constants.EnvData.DISABLE_MAGIC_LINK_LOGIN,
+ DisableLoginPage: &constants.EnvData.DISABLE_LOGIN_PAGE,
+ Roles: constants.EnvData.ROLES,
+ ProtectedRoles: constants.EnvData.PROTECTED_ROLES,
+ DefaultRoles: constants.EnvData.DEFAULT_ROLES,
+ JwtRoleClaim: &constants.EnvData.JWT_ROLE_CLAIM,
+ GoogleClientID: &constants.EnvData.GOOGLE_CLIENT_ID,
+ GoogleClientSecret: &constants.EnvData.GOOGLE_CLIENT_SECRET,
+ GithubClientID: &constants.EnvData.GITHUB_CLIENT_ID,
+ GithubClientSecret: &constants.EnvData.GITHUB_CLIENT_SECRET,
+ FacebookClientID: &constants.EnvData.FACEBOOK_CLIENT_ID,
+ FacebookClientSecret: &constants.EnvData.FACEBOOK_CLIENT_SECRET,
+ OrganizationName: &constants.EnvData.ORGANIZATION_NAME,
+ OrganizationLogo: &constants.EnvData.ORGANIZATION_LOGO,
+ }
+ return res, nil
+}
diff --git a/server/resolvers/forgot_password.go b/server/resolvers/forgot_password.go
index fc5ba16..8c5c583 100644
--- a/server/resolvers/forgot_password.go
+++ b/server/resolvers/forgot_password.go
@@ -20,7 +20,7 @@ func ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*mod
if err != nil {
return res, err
}
- if constants.DISABLE_BASIC_AUTHENTICATION {
+ if constants.EnvData.DISABLE_BASIC_AUTHENTICATION {
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
}
host := gc.Request.Host
diff --git a/server/resolvers/login.go b/server/resolvers/login.go
index 00b444e..482cf4b 100644
--- a/server/resolvers/login.go
+++ b/server/resolvers/login.go
@@ -22,7 +22,7 @@ func Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, e
return res, err
}
- if constants.DISABLE_BASIC_AUTHENTICATION {
+ if constants.EnvData.DISABLE_BASIC_AUTHENTICATION {
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
}
@@ -46,7 +46,7 @@ func Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, e
log.Println("compare password error:", err)
return res, fmt.Errorf(`invalid password`)
}
- roles := constants.DEFAULT_ROLES
+ roles := constants.EnvData.DEFAULT_ROLES
currentRoles := strings.Split(user.Roles, ",")
if len(params.Roles) > 0 {
if !utils.IsValidRoles(currentRoles, params.Roles) {
diff --git a/server/resolvers/magic_link_login.go b/server/resolvers/magic_link_login.go
index 2bb3d9d..8ba726a 100644
--- a/server/resolvers/magic_link_login.go
+++ b/server/resolvers/magic_link_login.go
@@ -17,7 +17,7 @@ import (
func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
var res *model.Response
- if constants.DISABLE_MAGIC_LINK_LOGIN {
+ if constants.EnvData.DISABLE_MAGIC_LINK_LOGIN {
return res, fmt.Errorf(`magic link login is disabled for this instance`)
}
@@ -41,13 +41,13 @@ func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*mod
// define roles for new user
if len(params.Roles) > 0 {
// check if roles exists
- if !utils.IsValidRoles(constants.ROLES, params.Roles) {
+ if !utils.IsValidRoles(constants.EnvData.ROLES, params.Roles) {
return res, fmt.Errorf(`invalid roles`)
} else {
inputRoles = params.Roles
}
} else {
- inputRoles = constants.DEFAULT_ROLES
+ inputRoles = constants.EnvData.DEFAULT_ROLES
}
user.Roles = strings.Join(inputRoles, ",")
@@ -72,7 +72,7 @@ func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*mod
// check if it contains protected unassigned role
hasProtectedRole := false
for _, ur := range unasignedRoles {
- if utils.StringSliceContains(constants.PROTECTED_ROLES, ur) {
+ if utils.StringSliceContains(constants.EnvData.PROTECTED_ROLES, ur) {
hasProtectedRole = true
}
}
@@ -98,7 +98,7 @@ func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*mod
}
}
- if !constants.DISABLE_EMAIL_VERIFICATION {
+ if !constants.EnvData.DISABLE_EMAIL_VERIFICATION {
// insert verification request
verificationType := enum.MagicLinkLogin.String()
token, err := utils.CreateVerificationToken(params.Email, verificationType)
diff --git a/server/resolvers/reset_password.go b/server/resolvers/reset_password.go
index 3ad2a03..a83cf52 100644
--- a/server/resolvers/reset_password.go
+++ b/server/resolvers/reset_password.go
@@ -15,7 +15,7 @@ import (
func ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) {
var res *model.Response
- if constants.DISABLE_BASIC_AUTHENTICATION {
+ if constants.EnvData.DISABLE_BASIC_AUTHENTICATION {
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
}
diff --git a/server/resolvers/session.go b/server/resolvers/session.go
index cecc0fe..a587deb 100644
--- a/server/resolvers/session.go
+++ b/server/resolvers/session.go
@@ -45,7 +45,7 @@ func Session(ctx context.Context, roles []string) (*model.AuthResponse, error) {
expiresTimeObj := time.Unix(expiresAt, 0)
currentTimeObj := time.Now()
- claimRoleInterface := claim[constants.JWT_ROLE_CLAIM].([]interface{})
+ claimRoleInterface := claim[constants.EnvData.JWT_ROLE_CLAIM].([]interface{})
claimRoles := make([]string, len(claimRoleInterface))
for i, v := range claimRoleInterface {
claimRoles[i] = v.(string)
diff --git a/server/resolvers/signup.go b/server/resolvers/signup.go
index aa9a241..ba19b45 100644
--- a/server/resolvers/signup.go
+++ b/server/resolvers/signup.go
@@ -22,7 +22,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
return res, err
}
- if constants.DISABLE_BASIC_AUTHENTICATION {
+ if constants.EnvData.DISABLE_BASIC_AUTHENTICATION {
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
}
if params.ConfirmPassword != params.Password {
@@ -52,13 +52,13 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
if len(params.Roles) > 0 {
// check if roles exists
- if !utils.IsValidRoles(constants.ROLES, params.Roles) {
+ if !utils.IsValidRoles(constants.EnvData.ROLES, params.Roles) {
return res, fmt.Errorf(`invalid roles`)
} else {
inputRoles = params.Roles
}
} else {
- inputRoles = constants.DEFAULT_ROLES
+ inputRoles = constants.EnvData.DEFAULT_ROLES
}
user := db.User{
@@ -103,7 +103,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
}
user.SignupMethods = enum.BasicAuth.String()
- if constants.DISABLE_EMAIL_VERIFICATION {
+ if constants.EnvData.DISABLE_EMAIL_VERIFICATION {
now := time.Now().Unix()
user.EmailVerifiedAt = &now
}
@@ -115,7 +115,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
roles := strings.Split(user.Roles, ",")
userToReturn := utils.GetResponseUserData(user)
- if !constants.DISABLE_EMAIL_VERIFICATION {
+ if !constants.EnvData.DISABLE_EMAIL_VERIFICATION {
// insert verification request
verificationType := enum.BasicAuthSignup.String()
token, err := utils.CreateVerificationToken(params.Email, verificationType)
diff --git a/server/resolvers/update_config.go b/server/resolvers/update_config.go
new file mode 100644
index 0000000..b1a407c
--- /dev/null
+++ b/server/resolvers/update_config.go
@@ -0,0 +1,105 @@
+package resolvers
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "log"
+ "reflect"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+ "github.com/authorizerdev/authorizer/server/db"
+ "github.com/authorizerdev/authorizer/server/graph/model"
+ "github.com/authorizerdev/authorizer/server/utils"
+)
+
+func UpdateConfigResolver(ctx context.Context, params model.UpdateConfigInput) (*model.Response, error) {
+ gc, err := utils.GinContextFromContext(ctx)
+ var res *model.Response
+
+ if err != nil {
+ return res, err
+ }
+
+ if !utils.IsSuperAdmin(gc) {
+ return res, fmt.Errorf("unauthorized")
+ }
+
+ var data map[string]interface{}
+ byteData, err := json.Marshal(params)
+ if err != nil {
+ return res, fmt.Errorf("error marshalling params: %t", err)
+ }
+
+ err = json.Unmarshal(byteData, &data)
+ if err != nil {
+ return res, fmt.Errorf("error un-marshalling params: %t", err)
+ }
+
+ updatedData := make(map[string]interface{})
+ for key, value := range data {
+ if value != nil {
+ fieldType := reflect.TypeOf(value).String()
+
+ if fieldType == "string" || fieldType == "bool" {
+ updatedData[key] = value
+ }
+
+ if fieldType == "[]interface {}" {
+ stringArr := []string{}
+ for _, v := range value.([]interface{}) {
+ stringArr = append(stringArr, v.(string))
+ }
+ updatedData[key] = stringArr
+ }
+ }
+ }
+
+ // handle derivative cases like disabling email verification & magic login
+ // in case SMTP is off but env is set to true
+ if updatedData["SMTP_HOST"] == "" || updatedData["SENDER_EMAIL"] == "" || updatedData["SENDER_PASSWORD"] == "" {
+ if !updatedData["DISABLE_EMAIL_VERIFICATION"].(bool) {
+ updatedData["DISABLE_EMAIL_VERIFICATION"] = true
+ }
+
+ if !updatedData["DISABLE_MAGIC_LINK_LOGIN"].(bool) {
+ updatedData["DISABLE_MAGIC_LINK_LOGIN"] = true
+ }
+ }
+
+ config, err := db.Mgr.GetConfig()
+ if err != nil {
+ return res, err
+ }
+
+ encryptedConfig, err := utils.EncryptConfig(updatedData)
+ if err != nil {
+ return res, err
+ }
+
+ // in case of db change re-initialize db
+ if params.DatabaseType != nil || params.DatabaseURL != nil || params.DatabaseName != nil {
+ db.InitDB()
+ }
+
+ // in case of admin secret change update the cookie with new hash
+ if params.AdminSecret != nil {
+ hashedKey, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
+ if err != nil {
+ return res, err
+ }
+ utils.SetAdminCookie(gc, hashedKey)
+ }
+
+ config.Config = encryptedConfig
+ _, err = db.Mgr.UpdateConfig(config)
+ if err != nil {
+ log.Println("error updating config:", err)
+ return res, err
+ }
+
+ res = &model.Response{
+ Message: "configurations updated successfully",
+ }
+ return res, nil
+}
diff --git a/server/resolvers/update_user.go b/server/resolvers/update_user.go
index 93222de..c67021b 100644
--- a/server/resolvers/update_user.go
+++ b/server/resolvers/update_user.go
@@ -112,7 +112,7 @@ func UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User,
inputRoles = append(inputRoles, *item)
}
- if !utils.IsValidRoles(append([]string{}, append(constants.ROLES, constants.PROTECTED_ROLES...)...), inputRoles) {
+ if !utils.IsValidRoles(append([]string{}, append(constants.EnvData.ROLES, constants.EnvData.PROTECTED_ROLES...)...), inputRoles) {
return res, fmt.Errorf("invalid list of roles")
}
diff --git a/server/session/session.go b/server/session/session.go
index 08138b0..39727b3 100644
--- a/server/session/session.go
+++ b/server/session/session.go
@@ -95,9 +95,9 @@ func RemoveSocialLoginState(key string) {
}
func InitSession() {
- if constants.REDIS_URL != "" {
+ if constants.EnvData.REDIS_URL != "" {
log.Println("using redis store to save sessions")
- opt, err := redis.ParseURL(constants.REDIS_URL)
+ opt, err := redis.ParseURL(constants.EnvData.REDIS_URL)
if err != nil {
log.Fatalln("Error parsing redis url:", err)
}
diff --git a/server/utils/auth_token.go b/server/utils/auth_token.go
index 23995de..6003291 100644
--- a/server/utils/auth_token.go
+++ b/server/utils/auth_token.go
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"log"
+ "net/url"
"os"
"strings"
"time"
@@ -14,10 +15,11 @@ import (
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
"github.com/robertkrimen/otto"
+ "golang.org/x/crypto/bcrypt"
)
func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (string, int64, error) {
- t := jwt.New(jwt.GetSigningMethod(constants.JWT_TYPE))
+ t := jwt.New(jwt.GetSigningMethod(constants.EnvData.JWT_TYPE))
expiryBound := time.Hour
if tokenType == enum.RefreshToken {
// expires in 1 year
@@ -32,11 +34,11 @@ func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (st
json.Unmarshal(userBytes, &userMap)
customClaims := jwt.MapClaims{
- "exp": expiresAt,
- "iat": time.Now().Unix(),
- "token_type": tokenType.String(),
- "allowed_roles": strings.Split(user.Roles, ","),
- constants.JWT_ROLE_CLAIM: roles,
+ "exp": expiresAt,
+ "iat": time.Now().Unix(),
+ "token_type": tokenType.String(),
+ "allowed_roles": strings.Split(user.Roles, ","),
+ constants.EnvData.JWT_ROLE_CLAIM: roles,
}
for k, v := range userMap {
@@ -77,7 +79,7 @@ func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (st
t.Claims = customClaims
- token, err := t.SignedString([]byte(constants.JWT_SECRET))
+ token, err := t.SignedString([]byte(constants.EnvData.JWT_SECRET))
if err != nil {
return "", 0, err
}
@@ -89,7 +91,6 @@ func GetAuthToken(gc *gin.Context) (string, error) {
token, err := GetCookie(gc)
if err != nil || token == "" {
// try to check in auth header for cookie
- log.Println("cookie not found checking headers")
auth := gc.Request.Header.Get("Authorization")
if auth == "" {
return "", fmt.Errorf(`unauthorized`)
@@ -105,7 +106,7 @@ func VerifyAuthToken(token string) (map[string]interface{}, error) {
claims := jwt.MapClaims{}
_, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) {
- return []byte(constants.JWT_SECRET), nil
+ return []byte(constants.EnvData.JWT_SECRET), nil
})
if err != nil {
return res, err
@@ -124,3 +125,29 @@ func VerifyAuthToken(token string) (map[string]interface{}, error) {
return res, nil
}
+
+func CreateAdminAuthToken(tokenType enum.TokenType, c *gin.Context) (string, error) {
+ return HashPassword(constants.EnvData.ADMIN_SECRET)
+}
+
+func GetAdminAuthToken(gc *gin.Context) (string, error) {
+ token, err := GetAdminCookie(gc)
+ if err != nil || token == "" {
+ return "", fmt.Errorf("unauthorized")
+ }
+
+ // cookie escapes special characters like $
+ // hence we need to unescape before comparing
+ decodedValue, err := url.QueryUnescape(token)
+ if err != nil {
+ return "", err
+ }
+
+ err = bcrypt.CompareHashAndPassword([]byte(decodedValue), []byte(constants.EnvData.ADMIN_SECRET))
+ log.Println("error comparing hash:", err)
+ if err != nil {
+ return "", fmt.Errorf(`unauthorized`)
+ }
+
+ return token, nil
+}
diff --git a/server/utils/cookie.go b/server/utils/cookie.go
index 38cf327..7319a21 100644
--- a/server/utils/cookie.go
+++ b/server/utils/cookie.go
@@ -10,21 +10,21 @@ import (
func SetCookie(gc *gin.Context, token string) {
secure := true
httpOnly := true
- host, _ := GetHostParts(constants.AUTHORIZER_URL)
- domain := GetDomainName(constants.AUTHORIZER_URL)
+ host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
+ domain := GetDomainName(constants.EnvData.AUTHORIZER_URL)
if domain != "localhost" {
domain = "." + domain
}
gc.SetSameSite(http.SameSiteNoneMode)
- gc.SetCookie(constants.COOKIE_NAME, token, 3600, "/", host, secure, httpOnly)
- gc.SetCookie(constants.COOKIE_NAME+"-client", token, 3600, "/", domain, secure, httpOnly)
+ gc.SetCookie(constants.EnvData.COOKIE_NAME, token, 3600, "/", host, secure, httpOnly)
+ gc.SetCookie(constants.EnvData.COOKIE_NAME+"-client", token, 3600, "/", domain, secure, httpOnly)
}
func GetCookie(gc *gin.Context) (string, error) {
- cookie, err := gc.Request.Cookie(constants.COOKIE_NAME)
+ cookie, err := gc.Request.Cookie(constants.EnvData.COOKIE_NAME)
if err != nil {
- cookie, err = gc.Request.Cookie(constants.COOKIE_NAME + "-client")
+ cookie, err = gc.Request.Cookie(constants.EnvData.COOKIE_NAME + "-client")
if err != nil {
return "", err
}
@@ -37,13 +37,37 @@ func DeleteCookie(gc *gin.Context) {
secure := true
httpOnly := true
- host, _ := GetHostParts(constants.AUTHORIZER_URL)
- domain := GetDomainName(constants.AUTHORIZER_URL)
+ host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
+ domain := GetDomainName(constants.EnvData.AUTHORIZER_URL)
if domain != "localhost" {
domain = "." + domain
}
gc.SetSameSite(http.SameSiteNoneMode)
- gc.SetCookie(constants.COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
- gc.SetCookie(constants.COOKIE_NAME+"-client", "", -1, "/", domain, secure, httpOnly)
+ gc.SetCookie(constants.EnvData.COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
+ gc.SetCookie(constants.EnvData.COOKIE_NAME+"-client", "", -1, "/", domain, secure, httpOnly)
+}
+
+func SetAdminCookie(gc *gin.Context, token string) {
+ secure := true
+ httpOnly := true
+ host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
+
+ gc.SetCookie(constants.EnvData.ADMIN_COOKIE_NAME, token, 3600, "/", host, secure, httpOnly)
+}
+
+func GetAdminCookie(gc *gin.Context) (string, error) {
+ cookie, err := gc.Request.Cookie(constants.EnvData.ADMIN_COOKIE_NAME)
+ if err != nil {
+ return "", err
+ }
+ return cookie.Value, nil
+}
+
+func DeleteAdminCookie(gc *gin.Context) {
+ secure := true
+ httpOnly := true
+ host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
+
+ gc.SetCookie(constants.EnvData.ADMIN_COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
}
diff --git a/server/utils/crypto.go b/server/utils/crypto.go
new file mode 100644
index 0000000..de7ce39
--- /dev/null
+++ b/server/utils/crypto.go
@@ -0,0 +1,83 @@
+package utils
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rand"
+ "encoding/base64"
+ "io"
+
+ "github.com/authorizerdev/authorizer/server/constants"
+)
+
+func EncryptB64(text string) string {
+ return base64.StdEncoding.EncodeToString([]byte(text))
+}
+
+func DecryptB64(s string) (string, error) {
+ data, err := base64.StdEncoding.DecodeString(s)
+ if err != nil {
+ return "", err
+ }
+ return string(data), nil
+}
+
+func EncryptAES(text []byte) ([]byte, error) {
+ key := []byte(constants.EnvData.ENCRYPTION_KEY)
+ c, err := aes.NewCipher(key)
+ var res []byte
+ 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
+}
+
+func DecryptAES(ciphertext []byte) ([]byte, error) {
+ key := []byte(constants.EnvData.ENCRYPTION_KEY)
+ c, err := aes.NewCipher(key)
+ var res []byte
+ 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/utils/email.go b/server/utils/email.go
index 1a4028a..fbb8edf 100644
--- a/server/utils/email.go
+++ b/server/utils/email.go
@@ -101,9 +101,9 @@ func SendVerificationMail(toEmail, token string) error {