Compare commits

..

1 Commits

Author SHA1 Message Date
Lakhan Samani
c128f7e267 fix: add code to query params + fix openid config 2022-10-20 14:29:47 +05:30
107 changed files with 1910 additions and 4167 deletions

View File

@@ -6,5 +6,4 @@ SMTP_HOST=smtp.mailtrap.io
SMTP_PORT=2525 SMTP_PORT=2525
SMTP_USERNAME=test SMTP_USERNAME=test
SMTP_PASSWORD=test SMTP_PASSWORD=test
SENDER_EMAIL="info@authorizer.dev" SENDER_EMAIL="info@authorizer.dev"
AWS_REGION=ap-south-1

View File

@@ -2,44 +2,36 @@ on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
logLevel: logLevel:
description: 'Log level' description: 'Log level'
required: true required: true
default: 'warning' default: 'warning'
type: choice type: choice
options: options:
- info - info
- warning - warning
- debug - debug
tags: tags:
description: 'Tags' description: 'Tags'
required: false required: false
type: boolean type: boolean
release: release:
types: [created] types: [created]
jobs: jobs:
releases: releases:
name: Release Authorizer name: Release Authorizer Binary
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: '16' node-version: '16'
- # Add support for more platforms with QEMU (optional)
# https://github.com/docker/setup-qemu-action
name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
platforms: linux/amd64,linux/arm64
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: '^1.19.1' go-version: '^1.17.3'
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get install build-essential wget zip libc6-dev-arm64-cross && \ sudo apt-get install build-essential wget zip gcc-mingw-w64 && \
echo "/usr/bin/x86_64-w64-mingw32-gcc" >> GITHUB_PATH && \ echo "/usr/bin/x86_64-w64-mingw32-gcc" >> GITHUB_PATH && \
wget --no-check-certificate --progress=dot:mega https://github.com/wangyoucao577/assets-uploader/releases/download/v0.3.0/github-assets-uploader-v0.3.0-linux-amd64.tar.gz -O github-assets-uploader.tar.gz && \ wget --no-check-certificate --progress=dot:mega https://github.com/wangyoucao577/assets-uploader/releases/download/v0.3.0/github-assets-uploader-v0.3.0-linux-amd64.tar.gz -O github-assets-uploader.tar.gz && \
tar -zxf github-assets-uploader.tar.gz && \ tar -zxf github-assets-uploader.tar.gz && \
@@ -52,26 +44,25 @@ jobs:
run: whereis go run: whereis go
- name: Print Go Version - name: Print Go Version
run: go version run: go version
- name: Install gox
run: go install github.com/mitchellh/gox@latest
- name: Set VERSION env - name: Set VERSION env
run: echo VERSION=$(basename ${GITHUB_REF}) >> ${GITHUB_ENV} run: echo VERSION=$(basename ${GITHUB_REF}) >> ${GITHUB_ENV}
- name: Copy .env file - name: Copy .env file
run: mv .env.sample .env run: mv .env.sample .env
- name: Build package - name: Package files for windows
run: | run: |
make clean && \ make clean && \
make build && \ CGO_ENABLED=1 GOOS=windows CC=/usr/bin/x86_64-w64-mingw32-gcc make && \
mkdir -p authorizer-${VERSION}-darwin-amd64/build authorizer-${VERSION}-darwin-amd64/app authorizer-${VERSION}-darwin-amd64/dashboard && cp build/darwin/amd64/server authorizer-${VERSION}-darwin-amd64/build/ && cp .env authorizer-${VERSION}-darwin-amd64/.env && cp -rf app/build authorizer-${VERSION}-darwin-amd64/app/build && cp -rf templates authorizer-${VERSION}-darwin-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-darwin-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-amd64.tar.gz authorizer-${VERSION}-darwin-amd64 && \ mv build/server build/server.exe && \
mkdir -p authorizer-${VERSION}-linux-amd64/build authorizer-${VERSION}-linux-amd64/app authorizer-${VERSION}-linux-amd64/dashboard && cp build/linux/amd64/server authorizer-${VERSION}-linux-amd64/build/ && cp .env authorizer-${VERSION}-linux-amd64/.env && cp -rf app/build authorizer-${VERSION}-linux-amd64/app/build && cp -rf templates authorizer-${VERSION}-linux-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz authorizer-${VERSION}-linux-amd64 && \ zip -vr authorizer-${VERSION}-windows-amd64.zip .env app/build build templates dashboard/build
mkdir -p authorizer-${VERSION}-linux-arm64/build authorizer-${VERSION}-linux-arm64/app authorizer-${VERSION}-linux-arm64/dashboard && cp build/linux/arm64/server authorizer-${VERSION}-linux-arm64/build/ && cp .env authorizer-${VERSION}-linux-arm64/.env && cp -rf app/build authorizer-${VERSION}-linux-arm64/app/build && cp -rf templates authorizer-${VERSION}-linux-arm64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-arm64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-arm64.tar.gz authorizer-${VERSION}-linux-arm64 && \ - name: Package files for linux
mkdir -p authorizer-${VERSION}-windows-amd64/build authorizer-${VERSION}-windows-amd64/app authorizer-${VERSION}-windows-amd64/dashboard && cp build/windows/amd64/server.exe authorizer-${VERSION}-windows-amd64/build/ && cp .env authorizer-${VERSION}-windows-amd64/.env && cp -rf app/build authorizer-${VERSION}-windows-amd64/app/build && cp -rf templates authorizer-${VERSION}-windows-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-windows-amd64/dashboard/build && zip -vr authorizer-${VERSION}-windows-amd64.zip authorizer-${VERSION}-windows-amd64 run: |
make clean && \
CGO_ENABLED=1 make && \
tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz .env app/build build templates dashboard/build
- name: Upload assets - name: Upload assets
run: | run: |
github-assets-uploader -f authorizer-${VERSION}-darwin-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} github-assets-uploader -f authorizer-${VERSION}-windows-amd64.zip -mediatype application/zip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} && \
github-assets-uploader -f authorizer-${VERSION}-linux-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} github-assets-uploader -f authorizer-${VERSION}-linux-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
github-assets-uploader -f authorizer-${VERSION}-linux-arm64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
github-assets-uploader -f authorizer-${VERSION}-windows-amd64.zip -mediatype application/zip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
- name: Log in to Docker Hub - name: Log in to Docker Hub
uses: docker/login-action@v1 uses: docker/login-action@v1
with: with:
@@ -83,11 +74,6 @@ jobs:
uses: docker/metadata-action@v3 uses: docker/metadata-action@v3
with: with:
images: lakhansamani/authorizer images: lakhansamani/authorizer
tags: |
type=schedule
type=ref,event=branch
type=ref,event=tag
type=ref,event=pr
- name: Build and push Docker image - name: Build and push Docker image
uses: docker/build-push-action@v2 uses: docker/build-push-action@v2
@@ -96,6 +82,5 @@ jobs:
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64
build-args: | build-args: |
VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}

4
.gitignore vendored
View File

@@ -15,6 +15,4 @@ test.db
.vscode/ .vscode/
.yalc .yalc
yalc.lock yalc.lock
certs/ certs/
*-shm
*-wal

View File

@@ -3,12 +3,6 @@ VERSION := $(or $(VERSION),$(DEFAULT_VERSION))
cmd: cmd:
cd server && go build -ldflags "-w -X main.VERSION=$(VERSION)" -o '../build/server' cd server && go build -ldflags "-w -X main.VERSION=$(VERSION)" -o '../build/server'
build:
cd server && gox \
-osarch="linux/amd64 linux/arm64 darwin/amd64 windows/amd64" \
-ldflags "-w -X main.VERSION=$(VERSION)" \
-output="../build/{{.OS}}/{{.Arch}}/server" \
./...
build-app: build-app:
cd app && npm i && npm run build cd app && npm i && npm run build
build-dashboard: build-dashboard:
@@ -16,7 +10,7 @@ build-dashboard:
clean: clean:
rm -rf build rm -rf build
test: test:
rm -rf server/test/test.db server/test/test.db-shm server/test/test.db-wal && rm -rf test.db test.db-shm test.db-wal && cd server && go clean --testcache && TEST_DBS="sqlite" go test -p 1 -v ./test rm -rf server/test/test.db && rm -rf test.db && cd server && go clean --testcache && TEST_DBS="sqlite" go test -p 1 -v ./test
test-mongodb: test-mongodb:
docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15 docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15
cd server && go clean --testcache && TEST_DBS="mongodb" go test -p 1 -v ./test cd server && go clean --testcache && TEST_DBS="mongodb" go test -p 1 -v ./test
@@ -29,20 +23,14 @@ test-arangodb:
docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.8.4 docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.8.4
cd server && go clean --testcache && TEST_DBS="arangodb" go test -p 1 -v ./test cd server && go clean --testcache && TEST_DBS="arangodb" go test -p 1 -v ./test
docker rm -vf authorizer_arangodb docker rm -vf authorizer_arangodb
test-dynamodb:
docker run -d --name dynamodb-local-test -p 8000:8000 amazon/dynamodb-local:latest
cd server && go clean --testcache && TEST_DBS="dynamodb" go test -p 1 -v ./test
docker rm -vf dynamodb-local-test
test-all-db: test-all-db:
rm -rf server/test/test.db server/test/test.db-shm server/test/test.db-wal && rm -rf test.db test.db-shm test.db-wal rm -rf server/test/test.db && rm -rf test.db
docker run -d --name authorizer_scylla_db -p 9042:9042 scylladb/scylla docker run -d --name authorizer_scylla_db -p 9042:9042 scylladb/scylla
docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15 docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15
docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.8.4 docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.8.4
docker run -d --name dynamodb-local-test -p 8000:8000 amazon/dynamodb-local:latest cd server && go clean --testcache && TEST_DBS="sqlite,mongodb,arangodb,scylladb" go test -p 1 -v ./test
cd server && go clean --testcache && TEST_DBS="sqlite,mongodb,arangodb,scylladb,dynamodb" go test -p 1 -v ./test
docker rm -vf authorizer_scylla_db docker rm -vf authorizer_scylla_db
docker rm -vf authorizer_mongodb_db docker rm -vf authorizer_mongodb_db
docker rm -vf authorizer_arangodb docker rm -vf authorizer_arangodb
docker rm -vf dynamodb-local-test
generate: generate:
cd server && go run github.com/99designs/gqlgen generate && go mod tidy cd server && go run github.com/99designs/gqlgen generate && go mod tidy

View File

@@ -2,5 +2,5 @@
"tabWidth": 2, "tabWidth": 2,
"singleQuote": true, "singleQuote": true,
"trailingComma": "all", "trailingComma": "all",
"useTabs": true "useTabs": false
} }

101
app/package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@authorizerdev/authorizer-react": "^1.1.4", "@authorizerdev/authorizer-react": "^1.1.2",
"@types/react": "^17.0.15", "@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9", "@types/react-dom": "^17.0.9",
"esbuild": "^0.12.17", "esbuild": "^0.12.17",
@@ -27,9 +27,9 @@
} }
}, },
"node_modules/@authorizerdev/authorizer-js": { "node_modules/@authorizerdev/authorizer-js": {
"version": "1.1.2", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.1.2.tgz", "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.1.0.tgz",
"integrity": "sha512-22qoqBaCNMn3QRWdJXmwAZeb5X9lwhZF3y23loY0eO3xUUzBaJiltENjHynbLGCg8LGgn7UaJEKDqGfL6Rzwvg==", "integrity": "sha512-MdEw1SjhIm7pXq20AscHSbnAta2PC3w7GNBY52/OzmlBXUGH3ooUQX/aszbYOse3FlhapcrGrRvg4sNM7faGAg==",
"dependencies": { "dependencies": {
"cross-fetch": "^3.1.5" "cross-fetch": "^3.1.5"
}, },
@@ -38,11 +38,14 @@
} }
}, },
"node_modules/@authorizerdev/authorizer-react": { "node_modules/@authorizerdev/authorizer-react": {
"version": "1.1.4", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.4.tgz", "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.2.tgz",
"integrity": "sha512-FBH2igXFM8+TdA2hl1S/HMzt1+OL5wWUow3+Zyiq+IkG9nIjWFlM7ebo4D0zJd875IJiabYFnXqstRABo0ysIQ==", "integrity": "sha512-uBmuKnOVX8gp8CEUuGJuz04ep+8qMEzJXWd5leEGKYMIgolHpu/lOinnMUXhjh8YL3pA4+EhvB+hQXxUX+rRHQ==",
"dependencies": { "dependencies": {
"@authorizerdev/authorizer-js": "^1.1.2" "@authorizerdev/authorizer-js": "^1.1.0",
"final-form": "^4.20.2",
"react-final-form": "^6.5.3",
"styled-components": "^5.3.0"
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=10"
@@ -466,6 +469,18 @@
"node": ">=0.8.0" "node": ">=0.8.0"
} }
}, },
"node_modules/final-form": {
"version": "4.20.4",
"resolved": "https://registry.npmjs.org/final-form/-/final-form-4.20.4.tgz",
"integrity": "sha512-hyoOVVilPLpkTvgi+FSJkFZrh0Yhy4BhE6lk/NiBwrF4aRV8/ykKEyXYvQH/pfUbRkOosvpESYouFb+FscsLrw==",
"dependencies": {
"@babel/runtime": "^7.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/final-form"
}
},
"node_modules/globals": { "node_modules/globals": {
"version": "11.12.0", "version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@@ -658,6 +673,33 @@
"react": "17.0.2" "react": "17.0.2"
} }
}, },
"node_modules/react-final-form": {
"version": "6.5.7",
"resolved": "https://registry.npmjs.org/react-final-form/-/react-final-form-6.5.7.tgz",
"integrity": "sha512-o7tvJXB+McGiXOILqIC8lnOcX4aLhIBiF/Xi9Qet35b7XOS8R7KL8HLRKTfnZWQJm6MCE15v1U0SFive0NcxyA==",
"dependencies": {
"@babel/runtime": "^7.15.4"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/final-form"
},
"peerDependencies": {
"final-form": "4.20.4",
"react": "^16.8.0 || ^17.0.0"
}
},
"node_modules/react-final-form/node_modules/@babel/runtime": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
"dependencies": {
"regenerator-runtime": "^0.13.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -834,19 +876,22 @@
}, },
"dependencies": { "dependencies": {
"@authorizerdev/authorizer-js": { "@authorizerdev/authorizer-js": {
"version": "1.1.2", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.1.2.tgz", "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.1.0.tgz",
"integrity": "sha512-22qoqBaCNMn3QRWdJXmwAZeb5X9lwhZF3y23loY0eO3xUUzBaJiltENjHynbLGCg8LGgn7UaJEKDqGfL6Rzwvg==", "integrity": "sha512-MdEw1SjhIm7pXq20AscHSbnAta2PC3w7GNBY52/OzmlBXUGH3ooUQX/aszbYOse3FlhapcrGrRvg4sNM7faGAg==",
"requires": { "requires": {
"cross-fetch": "^3.1.5" "cross-fetch": "^3.1.5"
} }
}, },
"@authorizerdev/authorizer-react": { "@authorizerdev/authorizer-react": {
"version": "1.1.4", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.4.tgz", "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.2.tgz",
"integrity": "sha512-FBH2igXFM8+TdA2hl1S/HMzt1+OL5wWUow3+Zyiq+IkG9nIjWFlM7ebo4D0zJd875IJiabYFnXqstRABo0ysIQ==", "integrity": "sha512-uBmuKnOVX8gp8CEUuGJuz04ep+8qMEzJXWd5leEGKYMIgolHpu/lOinnMUXhjh8YL3pA4+EhvB+hQXxUX+rRHQ==",
"requires": { "requires": {
"@authorizerdev/authorizer-js": "^1.1.2" "@authorizerdev/authorizer-js": "^1.1.0",
"final-form": "^4.20.2",
"react-final-form": "^6.5.3",
"styled-components": "^5.3.0"
} }
}, },
"@babel/code-frame": { "@babel/code-frame": {
@@ -1186,6 +1231,14 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
}, },
"final-form": {
"version": "4.20.4",
"resolved": "https://registry.npmjs.org/final-form/-/final-form-4.20.4.tgz",
"integrity": "sha512-hyoOVVilPLpkTvgi+FSJkFZrh0Yhy4BhE6lk/NiBwrF4aRV8/ykKEyXYvQH/pfUbRkOosvpESYouFb+FscsLrw==",
"requires": {
"@babel/runtime": "^7.10.0"
}
},
"globals": { "globals": {
"version": "11.12.0", "version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@@ -1334,6 +1387,24 @@
"scheduler": "^0.20.2" "scheduler": "^0.20.2"
} }
}, },
"react-final-form": {
"version": "6.5.7",
"resolved": "https://registry.npmjs.org/react-final-form/-/react-final-form-6.5.7.tgz",
"integrity": "sha512-o7tvJXB+McGiXOILqIC8lnOcX4aLhIBiF/Xi9Qet35b7XOS8R7KL8HLRKTfnZWQJm6MCE15v1U0SFive0NcxyA==",
"requires": {
"@babel/runtime": "^7.15.4"
},
"dependencies": {
"@babel/runtime": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
}
}
},
"react-is": { "react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",

View File

@@ -6,13 +6,13 @@
"scripts": { "scripts": {
"build": "rm -rf build && NODE_ENV=production node ./esbuild.config.js", "build": "rm -rf build && NODE_ENV=production node ./esbuild.config.js",
"start": "NODE_ENV=development node ./esbuild.config.js", "start": "NODE_ENV=development node ./esbuild.config.js",
"format": "prettier --write 'src/**/*.(ts|tsx|js|jsx)'" "format": "prettier --write --use-tabs 'src/**/*.(ts|tsx|js|jsx)'"
}, },
"keywords": [], "keywords": [],
"author": "Lakhan Samani", "author": "Lakhan Samani",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@authorizerdev/authorizer-react": "^1.1.4", "@authorizerdev/authorizer-react": "^1.1.2",
"@types/react": "^17.0.15", "@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9", "@types/react-dom": "^17.0.9",
"esbuild": "^0.12.17", "esbuild": "^0.12.17",

View File

@@ -38,8 +38,7 @@ export default function Root({
const scope = searchParams.get('scope') const scope = searchParams.get('scope')
? searchParams.get('scope')?.toString().split(' ') ? searchParams.get('scope')?.toString().split(' ')
: ['openid', 'profile', 'email']; : ['openid', 'profile', 'email'];
const code = searchParams.get('code') || ''; const code = searchParams.get('code')
const nonce = searchParams.get('nonce') || '';
const urlProps: Record<string, any> = { const urlProps: Record<string, any> = {
state, state,
@@ -61,18 +60,12 @@ export default function Root({
let redirectURL = config.redirectURL || '/app'; let redirectURL = config.redirectURL || '/app';
let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}`; let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}`;
if (code !== '') { if (code) {
params += `&code=${code}`; params += `&code=${code}`
} }
if (nonce !== '') {
params += `&nonce=${nonce}`;
}
if (token.refresh_token) { if (token.refresh_token) {
params += `&refresh_token=${token.refresh_token}`; params += `&refresh_token=${token.refresh_token}`;
} }
const url = new URL(redirectURL); const url = new URL(redirectURL);
if (redirectURL.includes('?')) { if (redirectURL.includes('?')) {
redirectURL = `${redirectURL}&${params}`; redirectURL = `${redirectURL}&${params}`;
@@ -86,7 +79,7 @@ export default function Root({
} }
} }
return () => {}; return () => {};
}, [token, config]); }, [token]);
if (loading) { if (loading) {
return <h1>Loading...</h1>; return <h1>Loading...</h1>;
@@ -112,7 +105,7 @@ export default function Root({
<Route path="/app" exact> <Route path="/app" exact>
<Login urlProps={urlProps} /> <Login urlProps={urlProps} />
</Route> </Route>
<Route path="/app/signup"> <Route path="/app/signup" exact>
<SignUp urlProps={urlProps} /> <SignUp urlProps={urlProps} />
</Route> </Route>
<Route path="/app/reset-password"> <Route path="/app/reset-password">

View File

@@ -60,12 +60,7 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
{view === VIEW_TYPES.FORGOT_PASSWORD && ( {view === VIEW_TYPES.FORGOT_PASSWORD && (
<Fragment> <Fragment>
<h1 style={{ textAlign: 'center' }}>Forgot Password</h1> <h1 style={{ textAlign: 'center' }}>Forgot Password</h1>
<AuthorizerForgotPassword <AuthorizerForgotPassword urlProps={urlProps} />
urlProps={{
...urlProps,
redirect_uri: `${window.location.origin}/app/reset-password`,
}}
/>
<Footer> <Footer>
<Link <Link
to="#" to="#"

View File

@@ -2,5 +2,5 @@
"tabWidth": 2, "tabWidth": 2,
"singleQuote": true, "singleQuote": true,
"trailingComma": "all", "trailingComma": "all",
"useTabs": true "useTabs": false
} }

File diff suppressed because it is too large Load Diff

View File

@@ -44,7 +44,7 @@ const DeleteEmailTemplateModal = ({
title: capitalizeFirstLetter(res.error.message), title: capitalizeFirstLetter(res.error.message),
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
return; return;
@@ -53,7 +53,7 @@ const DeleteEmailTemplateModal = ({
title: capitalizeFirstLetter(res.data?._delete_email_template.message), title: capitalizeFirstLetter(res.data?._delete_email_template.message),
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
} }
onClose(); onClose();

View File

@@ -51,7 +51,7 @@ const DeleteUserModal = ({
title: capitalizeFirstLetter(res.error.message), title: capitalizeFirstLetter(res.error.message),
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
return; return;
@@ -60,7 +60,7 @@ const DeleteUserModal = ({
title: capitalizeFirstLetter(res.data?._delete_user.message), title: capitalizeFirstLetter(res.data?._delete_user.message),
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
} }
onClose(); onClose();

View File

@@ -44,7 +44,7 @@ const DeleteWebhookModal = ({
title: capitalizeFirstLetter(res.error.message), title: capitalizeFirstLetter(res.error.message),
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
return; return;
@@ -53,7 +53,7 @@ const DeleteWebhookModal = ({
title: capitalizeFirstLetter(res.data?._delete_webhook.message), title: capitalizeFirstLetter(res.data?._delete_webhook.message),
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
} }
onClose(); onClose();

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React from 'react';
import { import {
Button, Button,
Center, Center,
@@ -20,14 +20,13 @@ import { useClient } from 'urql';
import { FaSave } from 'react-icons/fa'; import { FaSave } from 'react-icons/fa';
import InputField from './InputField'; import InputField from './InputField';
import { import {
ArrayInputType,
DateInputType, DateInputType,
MultiSelectInputType,
SelectInputType, SelectInputType,
TextInputType, TextInputType,
} from '../constants'; } from '../constants';
import { getObjectDiff } from '../utils'; import { getObjectDiff } from '../utils';
import { UpdateUser } from '../graphql/mutation'; import { UpdateUser } from '../graphql/mutation';
import { GetAvailableRolesQuery } from '../graphql/queries';
const GenderTypes = { const GenderTypes = {
Undisclosed: null, Undisclosed: null,
@@ -58,9 +57,8 @@ const EditUserModal = ({
}) => { }) => {
const client = useClient(); const client = useClient();
const toast = useToast(); const toast = useToast();
const [availableRoles, setAvailableRoles] = useState<string[]>([]);
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const [userData, setUserData] = useState<userDataTypes>({ const [userData, setUserData] = React.useState<userDataTypes>({
id: '', id: '',
email: '', email: '',
given_name: '', given_name: '',
@@ -75,17 +73,7 @@ const EditUserModal = ({
}); });
React.useEffect(() => { React.useEffect(() => {
setUserData(user); setUserData(user);
fetchAvailableRoles();
}, []); }, []);
const fetchAvailableRoles = async () => {
const res = await client.query(GetAvailableRolesQuery).toPromise();
if (res.data?._env?.ROLES && res.data?._env?.PROTECTED_ROLES) {
setAvailableRoles([
...res.data._env.ROLES,
...res.data._env.PROTECTED_ROLES,
]);
}
};
const saveHandler = async () => { const saveHandler = async () => {
const diff = getObjectDiff(user, userData); const diff = getObjectDiff(user, userData);
const updatedUserData = diff.reduce( const updatedUserData = diff.reduce(
@@ -104,14 +92,14 @@ const EditUserModal = ({
title: 'User data update failed', title: 'User data update failed',
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
} else if (res.data?._update_user?.id) { } else if (res.data?._update_user?.id) {
toast({ toast({
title: 'User data update successful', title: 'User data update successful',
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
} }
onClose(); onClose();
@@ -233,8 +221,7 @@ const EditUserModal = ({
<InputField <InputField
variables={userData} variables={userData}
setVariables={setUserData} setVariables={setUserData}
availableRoles={availableRoles} inputType={ArrayInputType.USER_ROLES}
inputType={MultiSelectInputType.USER_ROLES}
/> />
</Center> </Center>
</Flex> </Flex>

View File

@@ -48,26 +48,6 @@ const EmailConfigurations = ({
/> />
</Center> </Center>
</Flex> </Flex>
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
<Flex
w={isNotSmallerScreen ? '30%' : '40%'}
justifyContent="start"
alignItems="center"
>
<Text fontSize="sm">SMTP Local Name:</Text>
</Flex>
<Center
w={isNotSmallerScreen ? '70%' : '100%'}
mt={isNotSmallerScreen ? '0' : '3'}
>
<InputField
borderRadius={5}
variables={variables}
setVariables={setVariables}
inputType={TextInputType.SMTP_LOCAL_NAME}
/>
</Center>
</Flex>
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}> <Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
<Flex <Flex
w={isNotSmallerScreen ? '30%' : '40%'} w={isNotSmallerScreen ? '30%' : '40%'}

View File

@@ -43,7 +43,7 @@ const JSTConfigurations = ({
title: `JWT config copied successfully`, title: `JWT config copied successfully`,
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
} catch (err) { } catch (err) {
console.error({ console.error({
@@ -54,7 +54,7 @@ const JSTConfigurations = ({
title: `Failed to copy JWT config`, title: `Failed to copy JWT config`,
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
} }
}; };

View File

@@ -73,7 +73,7 @@ const GenerateKeysModal = ({ jwtType, getData }: propTypes) => {
title: 'Error occurred generating jwt keys', title: 'Error occurred generating jwt keys',
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
closeHandler(); closeHandler();
} else { } else {
@@ -107,7 +107,7 @@ const GenerateKeysModal = ({ jwtType, getData }: propTypes) => {
title: 'Error occurred setting jwt keys', title: 'Error occurred setting jwt keys',
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
return; return;
@@ -116,7 +116,7 @@ const GenerateKeysModal = ({ jwtType, getData }: propTypes) => {
title: 'JWT keys updated successfully', title: 'JWT keys updated successfully',
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
closeHandler(); closeHandler();
}; };

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React from 'react';
import { import {
Box, Box,
Flex, Flex,
@@ -13,12 +13,6 @@ import {
Textarea, Textarea,
Switch, Switch,
Text, Text,
MenuButton,
MenuList,
MenuItemOption,
MenuOptionGroup,
Button,
Menu,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
FaRegClone, FaRegClone,
@@ -26,7 +20,6 @@ import {
FaRegEyeSlash, FaRegEyeSlash,
FaPlus, FaPlus,
FaTimes, FaTimes,
FaAngleDown,
} from 'react-icons/fa'; } from 'react-icons/fa';
import { import {
ArrayInputOperations, ArrayInputOperations,
@@ -37,7 +30,6 @@ import {
TextAreaInputType, TextAreaInputType,
SwitchInputType, SwitchInputType,
DateInputType, DateInputType,
MultiSelectInputType,
} from '../constants'; } from '../constants';
import { copyTextToClipboard } from '../utils'; import { copyTextToClipboard } from '../utils';
@@ -47,16 +39,13 @@ const InputField = ({
setVariables, setVariables,
fieldVisibility, fieldVisibility,
setFieldVisibility, setFieldVisibility,
availableRoles,
...downshiftProps ...downshiftProps
}: any) => { }: any) => {
const props = { const props = {
size: 'sm', size: 'sm',
...downshiftProps, ...downshiftProps,
}; };
const [availableUserRoles, setAvailableUserRoles] = const [inputFieldVisibility, setInputFieldVisibility] = React.useState<
useState<string[]>(availableRoles);
const [inputFieldVisibility, setInputFieldVisibility] = useState<
Record<string, boolean> Record<string, boolean>
>({ >({
ROLES: false, ROLES: false,
@@ -65,7 +54,7 @@ const InputField = ({
ALLOWED_ORIGINS: false, ALLOWED_ORIGINS: false,
roles: false, roles: false,
}); });
const [inputData, setInputData] = useState<Record<string, string>>({ const [inputData, setInputData] = React.useState<Record<string, string>>({
ROLES: '', ROLES: '',
DEFAULT_ROLES: '', DEFAULT_ROLES: '',
PROTECTED_ROLES: '', PROTECTED_ROLES: '',
@@ -127,7 +116,7 @@ const InputField = ({
<InputGroup size="sm"> <InputGroup size="sm">
<Input <Input
{...props} {...props}
value={variables[inputType] || ''} value={variables[inputType] ?? ''}
onChange={( onChange={(
event: Event & { event: Event & {
target: HTMLInputElement; target: HTMLInputElement;
@@ -232,7 +221,7 @@ const InputField = ({
size="xs" size="xs"
minW="150px" minW="150px"
placeholder="add a new value" placeholder="add a new value"
value={inputData[inputType] || ''} value={inputData[inputType] ?? ''}
onChange={(e: any) => { onChange={(e: any) => {
setInputData({ ...inputData, [inputType]: e.target.value }); setInputData({ ...inputData, [inputType]: e.target.value });
}} }}
@@ -289,87 +278,6 @@ const InputField = ({
</Select> </Select>
); );
} }
if (Object.values(MultiSelectInputType).includes(inputType)) {
return (
<Flex w="100%" style={{ position: 'relative' }}>
<Flex
border="1px solid #e2e8f0"
w="100%"
borderRadius="var(--chakra-radii-sm)"
p="1% 0 0 2.5%"
overflowX={variables[inputType].length > 3 ? 'scroll' : 'hidden'}
overflowY="hidden"
justifyContent="space-between"
alignItems="center"
>
<Flex justifyContent="start" alignItems="center" w="100%" wrap="wrap">
{variables[inputType].map((role: string, index: number) => (
<Box key={index} margin="0.5%" role="group">
<Tag
size="sm"
variant="outline"
colorScheme="gray"
minW="fit-content"
>
<TagLabel cursor="default">{role}</TagLabel>
<TagRightIcon
boxSize="12px"
as={FaTimes}
display="none"
cursor="pointer"
_groupHover={{ display: 'block' }}
onClick={() =>
updateInputHandler(
inputType,
ArrayInputOperations.REMOVE,
role,
)
}
/>
</Tag>
</Box>
))}
</Flex>
<Menu matchWidth={true}>
<MenuButton px="10px" py="7.5px">
<FaAngleDown />
</MenuButton>
<MenuList
position="absolute"
top="0"
right="0"
zIndex="10"
maxH="150"
overflowX="scroll"
>
<MenuOptionGroup
title={undefined}
value={variables[inputType]}
type="checkbox"
onChange={(values: string[] | string) => {
setVariables({
...variables,
[inputType]: values,
});
}}
>
{availableUserRoles.map((role) => {
return (
<MenuItemOption
key={`multiselect-menu-${role}`}
value={role}
>
{role}
</MenuItemOption>
);
})}
</MenuOptionGroup>
</MenuList>
</Menu>
</Flex>
</Flex>
);
}
if (Object.values(TextAreaInputType).includes(inputType)) { if (Object.values(TextAreaInputType).includes(inputType)) {
return ( return (
<Textarea <Textarea

View File

@@ -105,7 +105,7 @@ const InviteMembersModal = ({
title: 'Invites sent successfully!', title: 'Invites sent successfully!',
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
setLoading(false); setLoading(false);
updateUserList(); updateUserList();
@@ -117,7 +117,7 @@ const InviteMembersModal = ({
title: error?.message || 'Error occurred, try again!', title: error?.message || 'Error occurred, try again!',
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
setLoading(false); setLoading(false);
} }

View File

@@ -29,10 +29,6 @@ import {
Tbody, Tbody,
Td, Td,
Code, Code,
Radio,
RadioGroup,
Stack,
Textarea,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { FaPlus, FaAngleDown, FaAngleUp } from 'react-icons/fa'; import { FaPlus, FaAngleDown, FaAngleUp } from 'react-icons/fa';
import { useClient } from 'urql'; import { useClient } from 'urql';
@@ -42,7 +38,6 @@ import {
EmailTemplateInputDataFields, EmailTemplateInputDataFields,
emailTemplateEventNames, emailTemplateEventNames,
emailTemplateVariables, emailTemplateVariables,
EmailTemplateEditors,
} from '../constants'; } from '../constants';
import { capitalizeFirstLetter } from '../utils'; import { capitalizeFirstLetter } from '../utils';
import { AddEmailTemplate, EditEmailTemplate } from '../graphql/mutation'; import { AddEmailTemplate, EditEmailTemplate } from '../graphql/mutation';
@@ -71,8 +66,6 @@ interface templateVariableDataTypes {
interface emailTemplateDataType { interface emailTemplateDataType {
[EmailTemplateInputDataFields.EVENT_NAME]: string; [EmailTemplateInputDataFields.EVENT_NAME]: string;
[EmailTemplateInputDataFields.SUBJECT]: string; [EmailTemplateInputDataFields.SUBJECT]: string;
[EmailTemplateInputDataFields.TEMPLATE]: string;
[EmailTemplateInputDataFields.DESIGN]: string;
} }
interface validatorDataType { interface validatorDataType {
@@ -82,8 +75,6 @@ interface validatorDataType {
const initTemplateData: emailTemplateDataType = { const initTemplateData: emailTemplateDataType = {
[EmailTemplateInputDataFields.EVENT_NAME]: emailTemplateEventNames.Signup, [EmailTemplateInputDataFields.EVENT_NAME]: emailTemplateEventNames.Signup,
[EmailTemplateInputDataFields.SUBJECT]: '', [EmailTemplateInputDataFields.SUBJECT]: '',
[EmailTemplateInputDataFields.TEMPLATE]: '',
[EmailTemplateInputDataFields.DESIGN]: '',
}; };
const initTemplateValidatorData: validatorDataType = { const initTemplateValidatorData: validatorDataType = {
@@ -100,9 +91,6 @@ const UpdateEmailTemplate = ({
const emailEditorRef = useRef(null); const emailEditorRef = useRef(null);
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const [editor, setEditor] = useState<string>(
EmailTemplateEditors.PLAIN_HTML_EDITOR,
);
const [templateVariables, setTemplateVariables] = useState< const [templateVariables, setTemplateVariables] = useState<
templateVariableDataTypes[] templateVariableDataTypes[]
>([]); >([]);
@@ -119,11 +107,9 @@ const UpdateEmailTemplate = ({
if (selectedTemplate) { if (selectedTemplate) {
const { design } = selectedTemplate; const { design } = selectedTemplate;
try { try {
if (design) { const designData = JSON.parse(design);
const designData = JSON.parse(design); // @ts-ignore
// @ts-ignore emailEditorRef.current.editor.loadDesign(designData);
emailEditorRef.current.editor.loadDesign(designData);
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);
onClose(); onClose();
@@ -150,85 +136,70 @@ const UpdateEmailTemplate = ({
); );
}; };
const updateTemplate = async (params: emailTemplateDataType) => {
let res: any = {};
if (
view === UpdateModalViews.Edit &&
selectedTemplate?.[EmailTemplateInputDataFields.ID]
) {
res = await client
.mutation(EditEmailTemplate, {
params: {
...params,
id: selectedTemplate[EmailTemplateInputDataFields.ID],
},
})
.toPromise();
} else {
res = await client.mutation(AddEmailTemplate, { params }).toPromise();
}
setLoading(false);
if (res.error) {
toast({
title: capitalizeFirstLetter(res.error.message),
isClosable: true,
status: 'error',
position: 'top-right',
});
} else if (
res.data?._add_email_template ||
res.data?._update_email_template
) {
toast({
title: capitalizeFirstLetter(
res.data?._add_email_template?.message ||
res.data?._update_email_template?.message,
),
isClosable: true,
status: 'success',
position: 'top-right',
});
setTemplateData({
...initTemplateData,
});
setValidator({ ...initTemplateValidatorData });
fetchEmailTemplatesData();
}
};
const saveData = async () => { const saveData = async () => {
if (!validateData()) return; if (!validateData()) return;
setLoading(true); setLoading(true);
let params: emailTemplateDataType = { // @ts-ignore
[EmailTemplateInputDataFields.EVENT_NAME]: return await emailEditorRef.current.editor.exportHtml(async (data) => {
templateData[EmailTemplateInputDataFields.EVENT_NAME], const { design, html } = data;
[EmailTemplateInputDataFields.SUBJECT]: if (!html || !design) {
templateData[EmailTemplateInputDataFields.SUBJECT], setLoading(false);
[EmailTemplateInputDataFields.TEMPLATE]: return;
templateData[EmailTemplateInputDataFields.TEMPLATE], }
[EmailTemplateInputDataFields.DESIGN]: '', const params = {
}; [EmailTemplateInputDataFields.EVENT_NAME]:
if (editor === EmailTemplateEditors.UNLAYER_EDITOR) { templateData[EmailTemplateInputDataFields.EVENT_NAME],
// @ts-ignore [EmailTemplateInputDataFields.SUBJECT]:
await emailEditorRef.current.editor.exportHtml(async (data) => { templateData[EmailTemplateInputDataFields.SUBJECT],
const { design, html } = data; [EmailTemplateInputDataFields.TEMPLATE]: html.trim(),
if (!html || !design) { [EmailTemplateInputDataFields.DESIGN]: JSON.stringify(design),
setLoading(false); };
return; let res: any = {};
} if (
params = { view === UpdateModalViews.Edit &&
...params, selectedTemplate?.[EmailTemplateInputDataFields.ID]
[EmailTemplateInputDataFields.TEMPLATE]: html.trim(), ) {
[EmailTemplateInputDataFields.DESIGN]: JSON.stringify(design), res = await client
}; .mutation(EditEmailTemplate, {
await updateTemplate(params); params: {
}); ...params,
} else { id: selectedTemplate[EmailTemplateInputDataFields.ID],
await updateTemplate(params); },
} })
view === UpdateModalViews.ADD && onClose(); .toPromise();
} else {
res = await client.mutation(AddEmailTemplate, { params }).toPromise();
}
setLoading(false);
if (res.error) {
toast({
title: capitalizeFirstLetter(res.error.message),
isClosable: true,
status: 'error',
position: 'bottom-right',
});
} else if (
res.data?._add_email_template ||
res.data?._update_email_template
) {
toast({
title: capitalizeFirstLetter(
res.data?._add_email_template?.message ||
res.data?._update_email_template?.message,
),
isClosable: true,
status: 'success',
position: 'bottom-right',
});
setTemplateData({
...initTemplateData,
});
setValidator({ ...initTemplateValidatorData });
fetchEmailTemplatesData();
}
view === UpdateModalViews.ADD && onClose();
});
}; };
const resetData = () => { const resetData = () => {
if (selectedTemplate) { if (selectedTemplate) {
setTemplateData(selectedTemplate); setTemplateData(selectedTemplate);
@@ -236,8 +207,6 @@ const UpdateEmailTemplate = ({
setTemplateData({ ...initTemplateData }); setTemplateData({ ...initTemplateData });
} }
}; };
// set template data if edit modal is open
useEffect(() => { useEffect(() => {
if ( if (
isOpen && isOpen &&
@@ -245,12 +214,10 @@ const UpdateEmailTemplate = ({
selectedTemplate && selectedTemplate &&
Object.keys(selectedTemplate || {}).length Object.keys(selectedTemplate || {}).length
) { ) {
const { id, created_at, ...rest } = selectedTemplate; const { id, created_at, template, design, ...rest } = selectedTemplate;
setTemplateData(rest); setTemplateData(rest);
} }
}, [isOpen]); }, [isOpen]);
// set template variables
useEffect(() => { useEffect(() => {
const updatedTemplateVariables = Object.entries( const updatedTemplateVariables = Object.entries(
emailTemplateVariables, emailTemplateVariables,
@@ -277,51 +244,6 @@ const UpdateEmailTemplate = ({
setTemplateVariables(updatedTemplateVariables); setTemplateVariables(updatedTemplateVariables);
}, [templateData[EmailTemplateInputDataFields.EVENT_NAME]]); }, [templateData[EmailTemplateInputDataFields.EVENT_NAME]]);
// change editor
useEffect(() => {
if (isOpen && selectedTemplate) {
const { design } = selectedTemplate;
if (design) {
setEditor(EmailTemplateEditors.UNLAYER_EDITOR);
} else {
setEditor(EmailTemplateEditors.PLAIN_HTML_EDITOR);
}
}
}, [isOpen, selectedTemplate]);
// reset fields when editor is changed
useEffect(() => {
if (selectedTemplate?.design) {
if (editor === EmailTemplateEditors.UNLAYER_EDITOR) {
setTemplateData({
...templateData,
[EmailTemplateInputDataFields.TEMPLATE]: selectedTemplate.template,
[EmailTemplateInputDataFields.DESIGN]: selectedTemplate.design,
});
} else {
setTemplateData({
...templateData,
[EmailTemplateInputDataFields.TEMPLATE]: '',
[EmailTemplateInputDataFields.DESIGN]: '',
});
}
} else if (selectedTemplate?.template) {
if (editor === EmailTemplateEditors.UNLAYER_EDITOR) {
setTemplateData({
...templateData,
[EmailTemplateInputDataFields.TEMPLATE]: '',
[EmailTemplateInputDataFields.DESIGN]: '',
});
} else {
setTemplateData({
...templateData,
[EmailTemplateInputDataFields.TEMPLATE]: selectedTemplate?.template,
[EmailTemplateInputDataFields.DESIGN]: '',
});
}
}
}, [editor]);
return ( return (
<> <>
{view === UpdateModalViews.ADD ? ( {view === UpdateModalViews.ADD ? (
@@ -492,22 +414,7 @@ const UpdateEmailTemplate = ({
alignItems="center" alignItems="center"
marginBottom="2%" marginBottom="2%"
> >
<Flex flex="1">Template Body</Flex> Template Body
<Flex flex="3">
<RadioGroup
onChange={(value) => setEditor(value)}
value={editor}
>
<Stack direction="row" spacing="50px">
<Radio value={EmailTemplateEditors.PLAIN_HTML_EDITOR}>
Plain HTML
</Radio>
<Radio value={EmailTemplateEditors.UNLAYER_EDITOR}>
Unlayer Editor
</Radio>
</Stack>
</RadioGroup>
</Flex>
</Flex> </Flex>
<Flex <Flex
width="100%" width="100%"
@@ -516,22 +423,7 @@ const UpdateEmailTemplate = ({
border="1px solid" border="1px solid"
borderColor="gray.200" borderColor="gray.200"
> >
{editor === EmailTemplateEditors.UNLAYER_EDITOR ? ( <EmailEditor ref={emailEditorRef} onReady={onReady} />
<EmailEditor ref={emailEditorRef} onReady={onReady} />
) : (
<Textarea
value={templateData.template}
onChange={(e) => {
setTemplateData({
...templateData,
[EmailTemplateInputDataFields.TEMPLATE]: e.target.value,
});
}}
placeholder="Template HTML"
border="0"
height="500px"
/>
)}
</Flex> </Flex>
</Flex> </Flex>
</ModalBody> </ModalBody>

View File

@@ -290,7 +290,7 @@ const UpdateWebhookModal = ({
title: capitalizeFirstLetter(res.error.message), title: capitalizeFirstLetter(res.error.message),
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
} else if (res.data?._add_webhook || res.data?._update_webhook) { } else if (res.data?._add_webhook || res.data?._update_webhook) {
toast({ toast({
@@ -299,7 +299,7 @@ const UpdateWebhookModal = ({
), ),
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
setWebhook({ setWebhook({
...initWebhookData, ...initWebhookData,

View File

@@ -15,7 +15,6 @@ export const TextInputType = {
SMTP_HOST: 'SMTP_HOST', SMTP_HOST: 'SMTP_HOST',
SMTP_PORT: 'SMTP_PORT', SMTP_PORT: 'SMTP_PORT',
SMTP_USERNAME: 'SMTP_USERNAME', SMTP_USERNAME: 'SMTP_USERNAME',
SMTP_LOCAL_NAME: 'SMTP_LOCAL_NAME',
SENDER_EMAIL: 'SENDER_EMAIL', SENDER_EMAIL: 'SENDER_EMAIL',
ORGANIZATION_NAME: 'ORGANIZATION_NAME', ORGANIZATION_NAME: 'ORGANIZATION_NAME',
ORGANIZATION_LOGO: 'ORGANIZATION_LOGO', ORGANIZATION_LOGO: 'ORGANIZATION_LOGO',
@@ -49,6 +48,7 @@ export const ArrayInputType = {
DEFAULT_ROLES: 'DEFAULT_ROLES', DEFAULT_ROLES: 'DEFAULT_ROLES',
PROTECTED_ROLES: 'PROTECTED_ROLES', PROTECTED_ROLES: 'PROTECTED_ROLES',
ALLOWED_ORIGINS: 'ALLOWED_ORIGINS', ALLOWED_ORIGINS: 'ALLOWED_ORIGINS',
USER_ROLES: 'roles',
}; };
export const SelectInputType = { export const SelectInputType = {
@@ -56,10 +56,6 @@ export const SelectInputType = {
GENDER: 'gender', GENDER: 'gender',
}; };
export const MultiSelectInputType = {
USER_ROLES: 'roles',
};
export const TextAreaInputType = { export const TextAreaInputType = {
CUSTOM_ACCESS_TOKEN_SCRIPT: 'CUSTOM_ACCESS_TOKEN_SCRIPT', CUSTOM_ACCESS_TOKEN_SCRIPT: 'CUSTOM_ACCESS_TOKEN_SCRIPT',
JWT_PRIVATE_KEY: 'JWT_PRIVATE_KEY', JWT_PRIVATE_KEY: 'JWT_PRIVATE_KEY',
@@ -133,7 +129,6 @@ export interface envVarTypes {
SMTP_PORT: string; SMTP_PORT: string;
SMTP_USERNAME: string; SMTP_USERNAME: string;
SMTP_PASSWORD: string; SMTP_PASSWORD: string;
SMTP_LOCAL_NAME: string;
SENDER_EMAIL: string; SENDER_EMAIL: string;
ALLOWED_ORIGINS: [string] | []; ALLOWED_ORIGINS: [string] | [];
ORGANIZATION_NAME: string; ORGANIZATION_NAME: string;
@@ -337,8 +332,3 @@ export const webhookPayloadExample: string = `{
}, },
"auth_recipe":"google" "auth_recipe":"google"
}`; }`;
export enum EmailTemplateEditors {
UNLAYER_EDITOR = 'unlayer_editor',
PLAIN_HTML_EDITOR = 'plain_html_editor',
}

View File

@@ -45,7 +45,6 @@ export const EnvVariablesQuery = `
SMTP_PORT SMTP_PORT
SMTP_USERNAME SMTP_USERNAME
SMTP_PASSWORD SMTP_PASSWORD
SMTP_LOCAL_NAME
SENDER_EMAIL SENDER_EMAIL
ALLOWED_ORIGINS ALLOWED_ORIGINS
ORGANIZATION_NAME ORGANIZATION_NAME
@@ -170,12 +169,3 @@ export const WebhookLogsQuery = `
} }
} }
`; `;
export const GetAvailableRolesQuery = `
query {
_env {
ROLES
PROTECTED_ROLES
}
}
`;

View File

@@ -57,7 +57,7 @@ export default function Auth() {
title: capitalizeFirstLetter(error.message), title: capitalizeFirstLetter(error.message),
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
}); });
} }

View File

@@ -65,7 +65,6 @@ const Environment = () => {
SMTP_PORT: '', SMTP_PORT: '',
SMTP_USERNAME: '', SMTP_USERNAME: '',
SMTP_PASSWORD: '', SMTP_PASSWORD: '',
SMTP_LOCAL_NAME: '',
SENDER_EMAIL: '', SENDER_EMAIL: '',
ALLOWED_ORIGINS: [], ALLOWED_ORIGINS: [],
ORGANIZATION_NAME: '', ORGANIZATION_NAME: '',
@@ -203,7 +202,7 @@ const Environment = () => {
} variables`, } variables`,
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
}; };

View File

@@ -180,14 +180,14 @@ export default function Users() {
title: 'User verification failed', title: 'User verification failed',
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
} else if (res.data?._update_user?.id) { } else if (res.data?._update_user?.id) {
toast({ toast({
title: 'User verification successful', title: 'User verification successful',
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
} }
updateUserList(); updateUserList();
@@ -211,14 +211,14 @@ export default function Users() {
title: 'User access enable failed', title: 'User access enable failed',
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
} else { } else {
toast({ toast({
title: 'User access enabled successfully', title: 'User access enabled successfully',
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
} }
updateUserList(); updateUserList();
@@ -236,14 +236,14 @@ export default function Users() {
title: 'User access revoke failed', title: 'User access revoke failed',
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
} else { } else {
toast({ toast({
title: 'User access revoked successfully', title: 'User access revoked successfully',
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
} }
updateUserList(); updateUserList();
@@ -268,7 +268,7 @@ export default function Users() {
} for user`, } for user`,
isClosable: true, isClosable: true,
status: 'success', status: 'success',
position: 'top-right', position: 'bottom-right',
}); });
updateUserList(); updateUserList();
return; return;
@@ -277,7 +277,7 @@ export default function Users() {
title: 'Multi factor authentication update failed for user', title: 'Multi factor authentication update failed for user',
isClosable: true, isClosable: true,
status: 'error', status: 'error',
position: 'top-right', position: 'bottom-right',
}); });
}; };

View File

@@ -3,8 +3,6 @@ package constants
const ( const (
// AuthRecipeMethodBasicAuth is the basic_auth auth method // AuthRecipeMethodBasicAuth is the basic_auth auth method
AuthRecipeMethodBasicAuth = "basic_auth" AuthRecipeMethodBasicAuth = "basic_auth"
// AuthRecipeMethodMobileBasicAuth is the mobile basic_auth method, where user can signup using mobile number and password
AuthRecipeMethodMobileBasicAuth = "mobile_basic_auth"
// AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method // AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method
AuthRecipeMethodMagicLinkLogin = "magic_link_login" AuthRecipeMethodMagicLinkLogin = "magic_link_login"
// AuthRecipeMethodGoogle is the google auth method // AuthRecipeMethodGoogle is the google auth method

View File

@@ -25,6 +25,4 @@ const (
DbTypeCockroachDB = "cockroachdb" DbTypeCockroachDB = "cockroachdb"
// DbTypePlanetScaleDB is the planetscale database type // DbTypePlanetScaleDB is the planetscale database type
DbTypePlanetScaleDB = "planetscale" DbTypePlanetScaleDB = "planetscale"
// DbTypeDynamoDB is the Dynamo database type
DbTypeDynamoDB = "dynamodb"
) )

View File

@@ -21,12 +21,6 @@ const (
EnvKeyDatabaseType = "DATABASE_TYPE" EnvKeyDatabaseType = "DATABASE_TYPE"
// EnvKeyDatabaseURL key for env variable DATABASE_URL // EnvKeyDatabaseURL key for env variable DATABASE_URL
EnvKeyDatabaseURL = "DATABASE_URL" EnvKeyDatabaseURL = "DATABASE_URL"
// EnvAwsRegion key for env variable AWS REGION
EnvAwsRegion = "AWS_REGION"
// EnvAwsAccessKeyID key for env variable AWS_ACCESS_KEY_ID
EnvAwsAccessKeyID = "AWS_ACCESS_KEY_ID"
// EnvAwsAccessKey key for env variable AWS_SECRET_ACCESS_KEY
EnvAwsSecretAccessKey = "AWS_SECRET_ACCESS_KEY"
// EnvKeyDatabaseName key for env variable DATABASE_NAME // EnvKeyDatabaseName key for env variable DATABASE_NAME
EnvKeyDatabaseName = "DATABASE_NAME" EnvKeyDatabaseName = "DATABASE_NAME"
// EnvKeyDatabaseUsername key for env variable DATABASE_USERNAME // EnvKeyDatabaseUsername key for env variable DATABASE_USERNAME
@@ -51,8 +45,6 @@ const (
EnvKeySmtpUsername = "SMTP_USERNAME" EnvKeySmtpUsername = "SMTP_USERNAME"
// EnvKeySmtpPassword key for env variable SMTP_PASSWORD // EnvKeySmtpPassword key for env variable SMTP_PASSWORD
EnvKeySmtpPassword = "SMTP_PASSWORD" EnvKeySmtpPassword = "SMTP_PASSWORD"
// EnvKeySmtpLocalName key for env variable SMTP_LOCAL_NAME
EnvKeySmtpLocalName = "SMTP_LOCAL_NAME"
// EnvKeySenderEmail key for env variable SENDER_EMAIL // EnvKeySenderEmail key for env variable SENDER_EMAIL
EnvKeySenderEmail = "SENDER_EMAIL" EnvKeySenderEmail = "SENDER_EMAIL"
// EnvKeyIsEmailServiceEnabled key for env variable IS_EMAIL_SERVICE_ENABLED // EnvKeyIsEmailServiceEnabled key for env variable IS_EMAIL_SERVICE_ENABLED
@@ -125,8 +117,6 @@ const (
EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION" EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION"
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH // EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION" EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION"
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_MOBILE_BASIC_AUTH
EnvKeyDisableMobileBasicAuthentication = "DISABLE_MOBILE_BASIC_AUTHENTICATION"
// EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN // EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN
EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN" EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN"
// EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE // EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE

View File

@@ -1,19 +0,0 @@
package constants
const (
// - query: for Authorization Code grant. 302 Found triggers redirect.
ResponseModeQuery = "query"
// - fragment: for Implicit grant. 302 Found triggers redirect.
ResponseModeFragment = "fragment"
// - form_post: 200 OK with response parameters embedded in an HTML form as hidden parameters.
ResponseModeFormPost = "form_post"
// - web_message: For Silent Authentication. Uses HTML5 web messaging.
ResponseModeWebMessage = "web_message"
// For the Authorization Code grant, use response_type=code to include the authorization code.
ResponseTypeCode = "code"
// For the Implicit grant, use response_type=token to include an access token.
ResponseTypeToken = "token"
// For the Implicit grant of id_token, use response_type=id_token to include an identifier token.
ResponseTypeIDToken = "id_token"
)

View File

@@ -7,7 +7,6 @@ import (
"github.com/authorizerdev/authorizer/server/db/providers" "github.com/authorizerdev/authorizer/server/db/providers"
"github.com/authorizerdev/authorizer/server/db/providers/arangodb" "github.com/authorizerdev/authorizer/server/db/providers/arangodb"
"github.com/authorizerdev/authorizer/server/db/providers/cassandradb" "github.com/authorizerdev/authorizer/server/db/providers/cassandradb"
"github.com/authorizerdev/authorizer/server/db/providers/dynamodb"
"github.com/authorizerdev/authorizer/server/db/providers/mongodb" "github.com/authorizerdev/authorizer/server/db/providers/mongodb"
"github.com/authorizerdev/authorizer/server/db/providers/sql" "github.com/authorizerdev/authorizer/server/db/providers/sql"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
@@ -21,11 +20,10 @@ func InitDB() error {
envs := memorystore.RequiredEnvStoreObj.GetRequiredEnv() envs := memorystore.RequiredEnvStoreObj.GetRequiredEnv()
isSQL := envs.DatabaseType != constants.DbTypeArangodb && envs.DatabaseType != constants.DbTypeMongodb && envs.DatabaseType != constants.DbTypeCassandraDB && envs.DatabaseType != constants.DbTypeScyllaDB && envs.DatabaseType != constants.DbTypeDynamoDB isSQL := envs.DatabaseType != constants.DbTypeArangodb && envs.DatabaseType != constants.DbTypeMongodb && envs.DatabaseType != constants.DbTypeCassandraDB && envs.DatabaseType != constants.DbTypeScyllaDB
isArangoDB := envs.DatabaseType == constants.DbTypeArangodb isArangoDB := envs.DatabaseType == constants.DbTypeArangodb
isMongoDB := envs.DatabaseType == constants.DbTypeMongodb isMongoDB := envs.DatabaseType == constants.DbTypeMongodb
isCassandra := envs.DatabaseType == constants.DbTypeCassandraDB || envs.DatabaseType == constants.DbTypeScyllaDB isCassandra := envs.DatabaseType == constants.DbTypeCassandraDB || envs.DatabaseType == constants.DbTypeScyllaDB
isDynamoDB := envs.DatabaseType == constants.DbTypeDynamoDB
if isSQL { if isSQL {
log.Info("Initializing SQL Driver for: ", envs.DatabaseType) log.Info("Initializing SQL Driver for: ", envs.DatabaseType)
@@ -63,14 +61,5 @@ func InitDB() error {
} }
} }
if isDynamoDB {
log.Info("Initializing DynamoDB Driver for: ", envs.DatabaseType)
Provider, err = dynamodb.NewProvider()
if err != nil {
log.Fatal("Failed to initialize DynamoDB driver: ", err)
return err
}
}
return nil return nil
} }

View File

@@ -9,14 +9,14 @@ import (
// EmailTemplate model for database // EmailTemplate model for database
type EmailTemplate struct { type EmailTemplate struct {
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name" dynamo:"event_name" index:"event_name,hash"` EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name"`
Subject string `json:"subject" bson:"subject" cql:"subject" dynamo:"subject"` Subject string `json:"subject" bson:"subject" cql:"subject"`
Template string `json:"template" bson:"template" cql:"template" dynamo:"template"` Template string `json:"template" bson:"template" cql:"template"`
Design string `json:"design" bson:"design" cql:"design" dynamo:"design"` Design string `json:"design" bson:"design" cql:"design"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
} }
// AsAPIEmailTemplate to return email template as graphql response object // AsAPIEmailTemplate to return email template as graphql response object

View File

@@ -4,10 +4,10 @@ package models
// Env model for db // Env model for db
type Env struct { type Env struct {
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
EnvData string `json:"env" bson:"env" cql:"env" dynamo:"env"` EnvData string `json:"env" bson:"env" cql:"env"`
Hash string `json:"hash" bson:"hash" cql:"hash" dynamo:"hash"` Hash string `json:"hash" bson:"hash" cql:"hash"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
} }

View File

@@ -2,15 +2,11 @@ package models
// OTP model for database // OTP model for database
type OTP struct { type OTP struct {
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"` Email string `gorm:"unique" json:"email" bson:"email" cql:"email"`
Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"` Otp string `json:"otp" bson:"otp" cql:"otp"`
ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"` ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
}
type Paging struct {
ID string `json:"id,omitempty" dynamo:"id,hash"`
} }

View File

@@ -4,11 +4,11 @@ package models
// Session model for db // Session model for db
type Session struct { type Session struct {
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
UserID string `gorm:"type:char(36)" json:"user_id" bson:"user_id" cql:"user_id" dynamo:"user_id" index:"user_id,hash"` UserID string `gorm:"type:char(36)" json:"user_id" bson:"user_id" cql:"user_id"`
UserAgent string `json:"user_agent" bson:"user_agent" cql:"user_agent" dynamo:"user_agent"` UserAgent string `json:"user_agent" bson:"user_agent" cql:"user_agent"`
IP string `json:"ip" bson:"ip" cql:"ip" dynamo:"ip"` IP string `json:"ip" bson:"ip" cql:"ip"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
} }

View File

@@ -12,27 +12,27 @@ import (
// User model for db // User model for db
type User struct { type User struct {
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"` Email string `gorm:"unique" json:"email" bson:"email" cql:"email"`
EmailVerifiedAt *int64 `json:"email_verified_at" bson:"email_verified_at" cql:"email_verified_at" dynamo:"email_verified_at"` EmailVerifiedAt *int64 `json:"email_verified_at" bson:"email_verified_at" cql:"email_verified_at"`
Password *string `json:"password" bson:"password" cql:"password" dynamo:"password"` Password *string `json:"password" bson:"password" cql:"password"`
SignupMethods string `json:"signup_methods" bson:"signup_methods" cql:"signup_methods" dynamo:"signup_methods"` SignupMethods string `json:"signup_methods" bson:"signup_methods" cql:"signup_methods"`
GivenName *string `json:"given_name" bson:"given_name" cql:"given_name" dynamo:"given_name"` GivenName *string `json:"given_name" bson:"given_name" cql:"given_name"`
FamilyName *string `json:"family_name" bson:"family_name" cql:"family_name" dynamo:"family_name"` FamilyName *string `json:"family_name" bson:"family_name" cql:"family_name"`
MiddleName *string `json:"middle_name" bson:"middle_name" cql:"middle_name" dynamo:"middle_name"` MiddleName *string `json:"middle_name" bson:"middle_name" cql:"middle_name"`
Nickname *string `json:"nickname" bson:"nickname" cql:"nickname" dynamo:"nickname"` Nickname *string `json:"nickname" bson:"nickname" cql:"nickname"`
Gender *string `json:"gender" bson:"gender" cql:"gender" dynamo:"gender"` Gender *string `json:"gender" bson:"gender" cql:"gender"`
Birthdate *string `json:"birthdate" bson:"birthdate" cql:"birthdate" dynamo:"birthdate"` Birthdate *string `json:"birthdate" bson:"birthdate" cql:"birthdate"`
PhoneNumber *string `gorm:"index" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number"` PhoneNumber *string `gorm:"unique" json:"phone_number" bson:"phone_number" cql:"phone_number"`
PhoneNumberVerifiedAt *int64 `json:"phone_number_verified_at" bson:"phone_number_verified_at" cql:"phone_number_verified_at" dynamo:"phone_number_verified_at"` PhoneNumberVerifiedAt *int64 `json:"phone_number_verified_at" bson:"phone_number_verified_at" cql:"phone_number_verified_at"`
Picture *string `json:"picture" bson:"picture" cql:"picture" dynamo:"picture"` Picture *string `json:"picture" bson:"picture" cql:"picture"`
Roles string `json:"roles" bson:"roles" cql:"roles" dynamo:"roles"` Roles string `json:"roles" bson:"roles" cql:"roles"`
RevokedTimestamp *int64 `json:"revoked_timestamp" bson:"revoked_timestamp" cql:"revoked_timestamp" dynamo:"revoked_timestamp"` RevokedTimestamp *int64 `json:"revoked_timestamp" bson:"revoked_timestamp" cql:"revoked_timestamp"`
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled" bson:"is_multi_factor_auth_enabled" cql:"is_multi_factor_auth_enabled" dynamo:"is_multi_factor_auth_enabled"` IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled" bson:"is_multi_factor_auth_enabled" cql:"is_multi_factor_auth_enabled"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
} }
func (user *User) AsAPIUser() *model.User { func (user *User) AsAPIUser() *model.User {

View File

@@ -11,16 +11,16 @@ import (
// VerificationRequest model for db // VerificationRequest model for db
type VerificationRequest struct { type VerificationRequest struct {
Key string `json:"_key,omitempty" bson:"_key" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb Key string `json:"_key,omitempty" bson:"_key" cql:"_key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
Token string `json:"token" bson:"token" cql:"jwt_token" dynamo:"token" index:"token,hash"` Token string `json:"token" bson:"token" cql:"jwt_token"` // token is reserved keyword in cassandra
Identifier string `gorm:"uniqueIndex:idx_email_identifier;type:varchar(64)" json:"identifier" bson:"identifier" cql:"identifier" dynamo:"identifier"` Identifier string `gorm:"uniqueIndex:idx_email_identifier;type:varchar(64)" json:"identifier" bson:"identifier" cql:"identifier"`
ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"` ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at"`
Email string `gorm:"uniqueIndex:idx_email_identifier;type:varchar(256)" json:"email" bson:"email" cql:"email" dynamo:"email"` Email string `gorm:"uniqueIndex:idx_email_identifier;type:varchar(256)" json:"email" bson:"email" cql:"email"`
Nonce string `json:"nonce" bson:"nonce" cql:"nonce" dynamo:"nonce"` Nonce string `json:"nonce" bson:"nonce" cql:"nonce"`
RedirectURI string `json:"redirect_uri" bson:"redirect_uri" cql:"redirect_uri" dynamo:"redirect_uri"` RedirectURI string `json:"redirect_uri" bson:"redirect_uri" cql:"redirect_uri"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
} }
func (v *VerificationRequest) AsAPIVerificationRequest() *model.VerificationRequest { func (v *VerificationRequest) AsAPIVerificationRequest() *model.VerificationRequest {

View File

@@ -12,14 +12,14 @@ import (
// Webhook model for db // Webhook model for db
type Webhook struct { type Webhook struct {
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name" dynamo:"event_name" index:"event_name,hash"` EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name"`
EndPoint string `json:"endpoint" bson:"endpoint" cql:"endpoint" dynamo:"endpoint"` EndPoint string `json:"endpoint" bson:"endpoint" cql:"endpoint"`
Headers string `json:"headers" bson:"headers" cql:"headers" dynamo:"headers"` Headers string `json:"headers" bson:"headers" cql:"headers"`
Enabled bool `json:"enabled" bson:"enabled" cql:"enabled" dynamo:"enabled"` Enabled bool `json:"enabled" bson:"enabled" cql:"enabled"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
} }
// AsAPIWebhook to return webhook as graphql response object // AsAPIWebhook to return webhook as graphql response object

View File

@@ -11,14 +11,14 @@ import (
// WebhookLog model for db // WebhookLog model for db
type WebhookLog struct { type WebhookLog struct {
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
HttpStatus int64 `json:"http_status" bson:"http_status" cql:"http_status" dynamo:"http_status"` HttpStatus int64 `json:"http_status" bson:"http_status" cql:"http_status"`
Response string `json:"response" bson:"response" cql:"response" dynamo:"response"` Response string `json:"response" bson:"response" cql:"response"`
Request string `json:"request" bson:"request" cql:"request" dynamo:"request"` Request string `json:"request" bson:"request" cql:"request"`
WebhookID string `gorm:"type:char(36)" json:"webhook_id" bson:"webhook_id" cql:"webhook_id" dynamo:"webhook_id" index:"webhook_id,hash"` WebhookID string `gorm:"type:char(36)" json:"webhook_id" bson:"webhook_id" cql:"webhook_id"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
} }
// AsAPIWebhookLog to return webhook log as graphql response object // AsAPIWebhookLog to return webhook log as graphql response object

View File

@@ -15,7 +15,6 @@ import (
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/refs"
) )
// AddUser to save user information in database // AddUser to save user information in database
@@ -33,12 +32,6 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
user.Roles = defaultRoles user.Roles = defaultRoles
} }
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
return user, fmt.Errorf("user with given phone number already exists")
}
}
user.CreatedAt = time.Now().Unix() user.CreatedAt = time.Now().Unix()
user.UpdatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix()
userCollection, _ := p.db.Collection(ctx, models.Collections.User) userCollection, _ := p.db.Collection(ctx, models.Collections.User)
@@ -55,7 +48,6 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
// UpdateUser to update user information in database // UpdateUser to update user information in database
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) { func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
user.UpdatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix()
collection, _ := p.db.Collection(ctx, models.Collections.User) collection, _ := p.db.Collection(ctx, models.Collections.User)
meta, err := collection.UpdateDocument(ctx, user.Key, user) meta, err := collection.UpdateDocument(ctx, user.Key, user)
if err != nil { if err != nil {
@@ -219,34 +211,3 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
return nil return nil
} }
// GetUserByPhoneNumber to get user information from database using phone number
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
var user models.User
query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.User)
bindVars := map[string]interface{}{
"phone_number": phoneNumber,
}
cursor, err := p.db.Query(ctx, query, bindVars)
if err != nil {
return nil, err
}
defer cursor.Close()
for {
if !cursor.HasMore() {
if user.Key == "" {
return nil, fmt.Errorf("user not found")
}
break
}
_, err := cursor.ReadDocument(ctx, &user)
if err != nil {
return nil, err
}
}
return &user, nil
}

View File

@@ -161,12 +161,6 @@ func NewProvider() (*provider, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
userPhoneNumberIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_user_phone_number ON %s.%s (phone_number)", KeySpace, models.Collections.User)
err = session.Query(userPhoneNumberIndexQuery).Exec()
if err != nil {
return nil, err
}
// add is_multi_factor_auth_enabled on users table // add is_multi_factor_auth_enabled on users table
userTableAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD is_multi_factor_auth_enabled boolean`, KeySpace, models.Collections.User) userTableAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD is_multi_factor_auth_enabled boolean`, KeySpace, models.Collections.User)
err = session.Query(userTableAlterQuery).Exec() err = session.Query(userTableAlterQuery).Exec()

View File

@@ -12,7 +12,6 @@ import (
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/gocql/gocql" "github.com/gocql/gocql"
"github.com/google/uuid" "github.com/google/uuid"
) )
@@ -31,12 +30,6 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
user.Roles = defaultRoles user.Roles = defaultRoles
} }
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
return user, fmt.Errorf("user with given phone number already exists")
}
}
user.CreatedAt = time.Now().Unix() user.CreatedAt = time.Now().Unix()
user.UpdatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix()
@@ -306,14 +299,3 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
return nil return nil
} }
// GetUserByPhoneNumber to get user information from database using phone number
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
var user models.User
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, phoneNumber)
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.CreatedAt, &user.UpdatedAt)
if err != nil {
return nil, err
}
return &user, nil
}

View File

@@ -1,121 +0,0 @@
package dynamodb
import (
"context"
"errors"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
"github.com/guregu/dynamo"
)
// AddEmailTemplate to add EmailTemplate
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
collection := p.db.Table(models.Collections.EmailTemplate)
if emailTemplate.ID == "" {
emailTemplate.ID = uuid.New().String()
}
emailTemplate.Key = emailTemplate.ID
emailTemplate.CreatedAt = time.Now().Unix()
emailTemplate.UpdatedAt = time.Now().Unix()
err := collection.Put(emailTemplate).RunWithContext(ctx)
if err != nil {
return emailTemplate.AsAPIEmailTemplate(), err
}
return emailTemplate.AsAPIEmailTemplate(), nil
}
// UpdateEmailTemplate to update EmailTemplate
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
collection := p.db.Table(models.Collections.EmailTemplate)
emailTemplate.UpdatedAt = time.Now().Unix()
err := UpdateByHashKey(collection, "id", emailTemplate.ID, emailTemplate)
if err != nil {
return emailTemplate.AsAPIEmailTemplate(), err
}
return emailTemplate.AsAPIEmailTemplate(), nil
}
// ListEmailTemplates to list EmailTemplate
func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) {
var emailTemplate models.EmailTemplate
var iter dynamo.PagingIter
var lastEval dynamo.PagingKey
var iteration int64 = 0
collection := p.db.Table(models.Collections.EmailTemplate)
emailTemplates := []*model.EmailTemplate{}
paginationClone := pagination
scanner := collection.Scan()
count, err := scanner.Count()
if err != nil {
return nil, err
}
for (paginationClone.Offset + paginationClone.Limit) > iteration {
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
for iter.NextWithContext(ctx, &emailTemplate) {
if paginationClone.Offset == iteration {
emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate())
}
}
lastEval = iter.LastEvaluatedKey()
iteration += paginationClone.Limit
}
paginationClone.Total = count
return &model.EmailTemplates{
Pagination: &paginationClone,
EmailTemplates: emailTemplates,
}, nil
}
// GetEmailTemplateByID to get EmailTemplate by id
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
collection := p.db.Table(models.Collections.EmailTemplate)
var emailTemplate models.EmailTemplate
err := collection.Get("id", emailTemplateID).OneWithContext(ctx, &emailTemplate)
if err != nil {
return nil, err
}
return emailTemplate.AsAPIEmailTemplate(), nil
}
// GetEmailTemplateByEventName to get EmailTemplate by event_name
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
collection := p.db.Table(models.Collections.EmailTemplate)
var emailTemplates []models.EmailTemplate
var emailTemplate models.EmailTemplate
err := collection.Scan().Index("event_name").Filter("'event_name' = ?", eventName).Limit(1).AllWithContext(ctx, &emailTemplates)
if err != nil {
return nil, err
}
if len(emailTemplates) > 0 {
emailTemplate = emailTemplates[0]
return emailTemplate.AsAPIEmailTemplate(), nil
} else {
return nil, errors.New("no record found")
}
}
// DeleteEmailTemplate to delete EmailTemplate
func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error {
collection := p.db.Table(models.Collections.EmailTemplate)
err := collection.Delete("id", emailTemplate.ID).RunWithContext(ctx)
if err != nil {
return err
}
return nil
}

View File

@@ -1,71 +0,0 @@
package dynamodb
import (
"context"
"errors"
"fmt"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/google/uuid"
)
// AddEnv to save environment information in database
func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
collection := p.db.Table(models.Collections.Env)
if env.ID == "" {
env.ID = uuid.New().String()
}
env.Key = env.ID
env.CreatedAt = time.Now().Unix()
env.UpdatedAt = time.Now().Unix()
err := collection.Put(env).RunWithContext(ctx)
if err != nil {
return env, err
}
return env, nil
}
// UpdateEnv to update environment information in database
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
collection := p.db.Table(models.Collections.Env)
env.UpdatedAt = time.Now().Unix()
err := UpdateByHashKey(collection, "id", env.ID, env)
if err != nil {
return env, err
}
return env, nil
}
// GetEnv to get environment information from database
func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
var env models.Env
collection := p.db.Table(models.Collections.Env)
// As there is no Findone supported.
iter := collection.Scan().Limit(1).Iter()
for iter.NextWithContext(ctx, &env) {
if env.ID == "" {
return env, errors.New("no documets found")
} else {
return env, nil
}
}
err := iter.Err()
if err != nil {
return env, fmt.Errorf("config not found")
}
return env, nil
}

View File

@@ -1,80 +0,0 @@
package dynamodb
import (
"context"
"errors"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/google/uuid"
)
// UpsertOTP to add or update otp
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
shouldCreate := false
if otp == nil {
id := uuid.NewString()
otp = &models.OTP{
ID: id,
Key: id,
Otp: otpParam.Otp,
Email: otpParam.Email,
ExpiresAt: otpParam.ExpiresAt,
CreatedAt: time.Now().Unix(),
}
shouldCreate = true
} else {
otp.Otp = otpParam.Otp
otp.ExpiresAt = otpParam.ExpiresAt
}
collection := p.db.Table(models.Collections.OTP)
otp.UpdatedAt = time.Now().Unix()
var err error
if shouldCreate {
err = collection.Put(otp).RunWithContext(ctx)
} else {
err = UpdateByHashKey(collection, "id", otp.ID, otp)
}
if err != nil {
return nil, err
}
return otp, nil
}
// GetOTPByEmail to get otp for a given email address
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
var otps []models.OTP
var otp models.OTP
collection := p.db.Table(models.Collections.OTP)
err := collection.Scan().Index("email").Filter("'email' = ?", emailAddress).Limit(1).AllWithContext(ctx, &otps)
if err != nil {
return nil, err
}
if len(otps) > 0 {
otp = otps[0]
return &otp, nil
} else {
return nil, errors.New("no docuemnt found")
}
}
// DeleteOTP to delete otp
func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error {
collection := p.db.Table(models.Collections.OTP)
if otp.ID != "" {
err := collection.Delete("id", otp.ID).RunWithContext(ctx)
if err != nil {
return err
}
}
return nil
}

View File

@@ -1,61 +0,0 @@
package dynamodb
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/guregu/dynamo"
log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/memorystore"
)
type provider struct {
db *dynamo.DB
}
// NewProvider returns a new Dynamo provider
func NewProvider() (*provider, error) {
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
awsRegion := memorystore.RequiredEnvStoreObj.GetRequiredEnv().AwsRegion
awsAccessKeyID := memorystore.RequiredEnvStoreObj.GetRequiredEnv().AwsAccessKeyID
awsSecretAccessKey := memorystore.RequiredEnvStoreObj.GetRequiredEnv().AwsSecretAccessKey
config := aws.Config{
MaxRetries: aws.Int(3),
CredentialsChainVerboseErrors: aws.Bool(true), // for full error logs
}
if awsRegion != "" {
config.Region = aws.String(awsRegion)
}
// custom awsAccessKeyID, awsSecretAccessKey took first priority, if not then fetch config from aws credentials
if awsAccessKeyID != "" && awsSecretAccessKey != "" {
config.Credentials = credentials.NewStaticCredentials(awsAccessKeyID, awsSecretAccessKey, "")
} else if dbURL != "" {
// static config in case of testing or local-setup
config.Credentials = credentials.NewStaticCredentials("key", "key", "")
config.Endpoint = aws.String(dbURL)
} else {
log.Debugf("%s or %s or %s not found. Trying to load default credentials from aws config", constants.EnvAwsRegion, constants.EnvAwsAccessKeyID, constants.EnvAwsSecretAccessKey)
}
session := session.Must(session.NewSession(&config))
db := dynamo.New(session)
db.CreateTable(models.Collections.User, models.User{}).Wait()
db.CreateTable(models.Collections.Session, models.Session{}).Wait()
db.CreateTable(models.Collections.EmailTemplate, models.EmailTemplate{}).Wait()
db.CreateTable(models.Collections.Env, models.Env{}).Wait()
db.CreateTable(models.Collections.OTP, models.OTP{}).Wait()
db.CreateTable(models.Collections.VerificationRequest, models.VerificationRequest{}).Wait()
db.CreateTable(models.Collections.Webhook, models.Webhook{}).Wait()
db.CreateTable(models.Collections.WebhookLog, models.WebhookLog{}).Wait()
return &provider{
db: db,
}, nil
}

View File

@@ -1,28 +0,0 @@
package dynamodb
import (
"context"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/google/uuid"
)
// AddSession to save session information in database
func (p *provider) AddSession(ctx context.Context, session models.Session) error {
collection := p.db.Table(models.Collections.Session)
if session.ID == "" {
session.ID = uuid.New().String()
}
session.CreatedAt = time.Now().Unix()
session.UpdatedAt = time.Now().Unix()
err := collection.Put(session).RunWithContext(ctx)
return err
}
// DeleteSession to delete session information from database
func (p *provider) DeleteSession(ctx context.Context, userId string) error {
return nil
}

View File

@@ -1,46 +0,0 @@
package dynamodb
import (
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"github.com/guregu/dynamo"
)
// As updpate all item not supported so set manually via Set and SetNullable for empty field
func UpdateByHashKey(table dynamo.Table, hashKey string, hashValue string, item interface{}) error {
existingValue, err := dynamo.MarshalItem(item)
var i interface{}
if err != nil {
return err
}
nullableValue, err := dynamodbattribute.MarshalMap(item)
if err != nil {
return err
}
u := table.Update(hashKey, hashValue)
for k, v := range existingValue {
if k == hashKey {
continue
}
u = u.Set(k, v)
}
for k, v := range nullableValue {
if k == hashKey {
continue
}
dynamodbattribute.Unmarshal(v, &i)
if i == nil {
u = u.SetNullable(k, v)
}
}
err = u.Run()
if err != nil {
return err
}
return nil
}

View File

@@ -1,224 +0,0 @@
package dynamodb
import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/google/uuid"
"github.com/guregu/dynamo"
log "github.com/sirupsen/logrus"
)
// AddUser to save user information in database
func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
collection := p.db.Table(models.Collections.User)
if user.ID == "" {
user.ID = uuid.New().String()
}
if user.Roles == "" {
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
if err != nil {
return user, err
}
user.Roles = defaultRoles
}
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
return user, fmt.Errorf("user with given phone number already exists")
}
}
user.CreatedAt = time.Now().Unix()
user.UpdatedAt = time.Now().Unix()
err := collection.Put(user).RunWithContext(ctx)
if err != nil {
return user, err
}
return user, nil
}
// UpdateUser to update user information in database
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
collection := p.db.Table(models.Collections.User)
if user.ID != "" {
user.UpdatedAt = time.Now().Unix()
err := UpdateByHashKey(collection, "id", user.ID, user)
if err != nil {
return user, err
}
if err != nil {
return user, err
}
}
return user, nil
}
// DeleteUser to delete user information from database
func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
collection := p.db.Table(models.Collections.User)
sessionCollection := p.db.Table(models.Collections.Session)
if user.ID != "" {
err := collection.Delete("id", user.ID).Run()
if err != nil {
return err
}
_, err = sessionCollection.Batch("id").Write().Delete(dynamo.Keys{"user_id", user.ID}).RunWithContext(ctx)
if err != nil {
return err
}
}
return nil
}
// ListUsers to get list of users from database
func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
var user models.User
var lastEval dynamo.PagingKey
var iter dynamo.PagingIter
var iteration int64 = 0
collection := p.db.Table(models.Collections.User)
users := []*model.User{}
paginationClone := pagination
scanner := collection.Scan()
count, err := scanner.Count()
if err != nil {
return nil, err
}
for (paginationClone.Offset + paginationClone.Limit) > iteration {
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
for iter.NextWithContext(ctx, &user) {
if paginationClone.Offset == iteration {
users = append(users, user.AsAPIUser())
}
}
lastEval = iter.LastEvaluatedKey()
iteration += paginationClone.Limit
}
err = iter.Err()
if err != nil {
return nil, err
}
paginationClone.Total = count
return &model.Users{
Pagination: &paginationClone,
Users: users,
}, nil
}
// GetUserByEmail to get user information from database using email address
func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
var users []models.User
var user models.User
collection := p.db.Table(models.Collections.User)
err := collection.Scan().Index("email").Filter("'email' = ?", email).AllWithContext(ctx, &users)
if err != nil {
return user, nil
}
if len(users) > 0 {
user = users[0]
return user, nil
} else {
return user, errors.New("no record found")
}
}
// GetUserByID to get user information from database using user ID
func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
collection := p.db.Table(models.Collections.User)
var user models.User
err := collection.Get("id", id).OneWithContext(ctx, &user)
if err != nil {
if user.Email == "" {
return user, errors.New("no documets found")
} else {
return user, nil
}
}
return user, nil
}
// UpdateUsers to update multiple users, with parameters of user IDs slice
// If ids set to nil / empty all the users will be updated
func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error {
// set updated_at time for all users
userCollection := p.db.Table(models.Collections.User)
var allUsers []models.User
var res int64 = 0
var err error
if len(ids) > 0 {
for _, v := range ids {
err = UpdateByHashKey(userCollection, "id", v, data)
}
} else {
// as there is no facility to update all doc - https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SQLtoNoSQL.UpdateData.html
userCollection.Scan().All(&allUsers)
for _, user := range allUsers {
err = UpdateByHashKey(userCollection, "id", user.ID, data)
if err == nil {
res = res + 1
}
}
}
if err != nil {
return err
} else {
log.Info("Updated users: ", res)
}
return nil
}
// GetUserByPhoneNumber to get user information from database using phone number
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
var users []models.User
var user models.User
collection := p.db.Table(models.Collections.User)
err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).AllWithContext(ctx, &users)
if err != nil {
return nil, err
}
if len(users) > 0 {
user = users[0]
return &user, nil
} else {
return nil, errors.New("no record found")
}
}

View File

@@ -1,116 +0,0 @@
package dynamodb
import (
"context"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
"github.com/guregu/dynamo"
)
// AddVerification to save verification request in database
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
collection := p.db.Table(models.Collections.VerificationRequest)
if verificationRequest.ID == "" {
verificationRequest.ID = uuid.New().String()
verificationRequest.CreatedAt = time.Now().Unix()
verificationRequest.UpdatedAt = time.Now().Unix()
err := collection.Put(verificationRequest).RunWithContext(ctx)
if err != nil {
return verificationRequest, err
}
}
return verificationRequest, nil
}
// GetVerificationRequestByToken to get verification request from database using token
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
collection := p.db.Table(models.Collections.VerificationRequest)
var verificationRequest models.VerificationRequest
iter := collection.Scan().Filter("'token' = ?", token).Iter()
for iter.NextWithContext(ctx, &verificationRequest) {
return verificationRequest, nil
}
err := iter.Err()
if err != nil {
return verificationRequest, err
}
return verificationRequest, nil
}
// GetVerificationRequestByEmail to get verification request by email from database
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
var verificationRequest models.VerificationRequest
collection := p.db.Table(models.Collections.VerificationRequest)
iter := collection.Scan().Filter("'email' = ?", email).Filter("'identifier' = ?", identifier).Iter()
for iter.NextWithContext(ctx, &verificationRequest) {
return verificationRequest, nil
}
err := iter.Err()
if err != nil {
return verificationRequest, err
}
return verificationRequest, nil
}
// ListVerificationRequests to get list of verification requests from database
func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
verificationRequests := []*model.VerificationRequest{}
var verificationRequest models.VerificationRequest
var lastEval dynamo.PagingKey
var iter dynamo.PagingIter
var iteration int64 = 0
collection := p.db.Table(models.Collections.VerificationRequest)
paginationClone := pagination
scanner := collection.Scan()
count, err := scanner.Count()
if err != nil {
return nil, err
}
for (paginationClone.Offset + paginationClone.Limit) > iteration {
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
for iter.NextWithContext(ctx, &verificationRequest) {
if paginationClone.Offset == iteration {
verificationRequests = append(verificationRequests, verificationRequest.AsAPIVerificationRequest())
}
}
err = iter.Err()
if err != nil {
return nil, err
}
lastEval = iter.LastEvaluatedKey()
iteration += paginationClone.Limit
}
paginationClone.Total = count
return &model.VerificationRequests{
VerificationRequests: verificationRequests,
Pagination: &paginationClone,
}, nil
}
// DeleteVerificationRequest to delete verification request from database
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
collection := p.db.Table(models.Collections.VerificationRequest)
if verificationRequest.ID != "" {
err := collection.Delete("id", verificationRequest.ID).RunWithContext(ctx)
if err != nil {
return err
}
}
return nil
}

View File

@@ -1,148 +0,0 @@
package dynamodb
import (
"context"
"errors"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
"github.com/guregu/dynamo"
)
// AddWebhook to add webhook
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
collection := p.db.Table(models.Collections.Webhook)
if webhook.ID == "" {
webhook.ID = uuid.New().String()
}
webhook.Key = webhook.ID
webhook.CreatedAt = time.Now().Unix()
webhook.UpdatedAt = time.Now().Unix()
err := collection.Put(webhook).RunWithContext(ctx)
if err != nil {
return nil, err
}
return webhook.AsAPIWebhook(), nil
}
// UpdateWebhook to update webhook
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
collection := p.db.Table(models.Collections.Webhook)
webhook.UpdatedAt = time.Now().Unix()
err := UpdateByHashKey(collection, "id", webhook.ID, webhook)
if err != nil {
return nil, err
}
return webhook.AsAPIWebhook(), nil
}
// ListWebhooks to list webhook
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
webhooks := []*model.Webhook{}
var webhook models.Webhook
var lastEval dynamo.PagingKey
var iter dynamo.PagingIter
var iteration int64 = 0
collection := p.db.Table(models.Collections.Webhook)
paginationClone := pagination
scanner := collection.Scan()
count, err := scanner.Count()
if err != nil {
return nil, err
}
for (paginationClone.Offset + paginationClone.Limit) > iteration {
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
for iter.NextWithContext(ctx, &webhook) {
if paginationClone.Offset == iteration {
webhooks = append(webhooks, webhook.AsAPIWebhook())
}
}
err = iter.Err()
if err != nil {
return nil, err
}
lastEval = iter.LastEvaluatedKey()
iteration += paginationClone.Limit
}
paginationClone.Total = count
return &model.Webhooks{
Pagination: &paginationClone,
Webhooks: webhooks,
}, nil
}
// GetWebhookByID to get webhook by id
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
collection := p.db.Table(models.Collections.Webhook)
var webhook models.Webhook
err := collection.Get("id", webhookID).OneWithContext(ctx, &webhook)
if err != nil {
return nil, err
}
if webhook.ID == "" {
return webhook.AsAPIWebhook(), errors.New("no documets found")
}
return webhook.AsAPIWebhook(), nil
}
// GetWebhookByEventName to get webhook by event_name
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
var webhook models.Webhook
collection := p.db.Table(models.Collections.Webhook)
iter := collection.Scan().Index("event_name").Filter("'event_name' = ?", eventName).Iter()
for iter.NextWithContext(ctx, &webhook) {
return webhook.AsAPIWebhook(), nil
}
err := iter.Err()
if err != nil {
return webhook.AsAPIWebhook(), err
}
return webhook.AsAPIWebhook(), nil
}
// DeleteWebhook to delete webhook
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
// Also delete webhook logs for given webhook id
if webhook.ID != "" {
webhookCollection := p.db.Table(models.Collections.Webhook)
pagination := model.Pagination{}
webhookLogCollection := p.db.Table(models.Collections.WebhookLog)
err := webhookCollection.Delete("id", webhook.ID).RunWithContext(ctx)
if err != nil {
return err
}
webhookLogs, errIs := p.ListWebhookLogs(ctx, pagination, webhook.ID)
for _, webhookLog := range webhookLogs.WebhookLogs {
err = webhookLogCollection.Delete("id", webhookLog.ID).RunWithContext(ctx)
if err != nil {
return err
}
}
if errIs != nil {
return errIs
}
}
return nil
}

View File

@@ -1,78 +0,0 @@
package dynamodb
import (
"context"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
"github.com/guregu/dynamo"
)
// AddWebhookLog to add webhook log
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
collection := p.db.Table(models.Collections.WebhookLog)
if webhookLog.ID == "" {
webhookLog.ID = uuid.New().String()
}
webhookLog.Key = webhookLog.ID
webhookLog.CreatedAt = time.Now().Unix()
webhookLog.UpdatedAt = time.Now().Unix()
err := collection.Put(webhookLog).RunWithContext(ctx)
if err != nil {
return nil, err
}
return webhookLog.AsAPIWebhookLog(), nil
}
// ListWebhookLogs to list webhook logs
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
webhookLogs := []*model.WebhookLog{}
var webhookLog models.WebhookLog
var lastEval dynamo.PagingKey
var iter dynamo.PagingIter
var iteration int64 = 0
var err error
var count int64
collection := p.db.Table(models.Collections.WebhookLog)
paginationClone := pagination
scanner := collection.Scan()
if webhookID != "" {
iter = scanner.Index("webhook_id").Filter("'webhook_id' = ?", webhookID).Iter()
for iter.NextWithContext(ctx, &webhookLog) {
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
}
err = iter.Err()
if err != nil {
return nil, err
}
} else {
for (paginationClone.Offset + paginationClone.Limit) > iteration {
iter = scanner.StartFrom(lastEval).Limit(paginationClone.Limit).Iter()
for iter.NextWithContext(ctx, &webhookLog) {
if paginationClone.Offset == iteration {
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
}
}
err = iter.Err()
if err != nil {
return nil, err
}
lastEval = iter.LastEvaluatedKey()
iteration += paginationClone.Limit
}
}
paginationClone.Total = count
// paginationClone.Cursor = iter.LastEvaluatedKey()
return &model.WebhookLogs{
Pagination: &paginationClone,
WebhookLogs: webhookLogs,
}, nil
}

View File

@@ -155,16 +155,3 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
} }
return nil return nil
} }
// GetUserByPhoneNumber to get user information from database using phone number
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
var user models.User
userCollection := p.db.Collection(models.Collections.User, options.Collection())
err := userCollection.FindOne(ctx, bson.M{"phone_number": phoneNumber}).Decode(&user)
if err != nil {
return nil, err
}
return &user, nil
}

View File

@@ -69,10 +69,3 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
return nil return nil
} }
// GetUserByPhoneNumber to get user information from database using phone number
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
var user *models.User
return user, nil
}

View File

@@ -18,8 +18,6 @@ type Provider interface {
ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error)
// GetUserByEmail to get user information from database using email address // GetUserByEmail to get user information from database using email address
GetUserByEmail(ctx context.Context, email string) (models.User, error) GetUserByEmail(ctx context.Context, email string) (models.User, error)
// GetUserByPhoneNumber to get user information from database using phone number
GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error)
// GetUserByID to get user information from database using user ID // GetUserByID to get user information from database using user ID
GetUserByID(ctx context.Context, id string) (models.User, error) GetUserByID(ctx context.Context, id string) (models.User, error)
// UpdateUsers to update multiple users, with parameters of user IDs slice // UpdateUsers to update multiple users, with parameters of user IDs slice

View File

@@ -1,15 +1,16 @@
package sql package sql
import ( import (
"log"
"os"
"time" "time"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
"github.com/glebarez/sqlite"
"github.com/sirupsen/logrus"
"gorm.io/driver/mysql" "gorm.io/driver/mysql"
"gorm.io/driver/postgres" "gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/driver/sqlserver" "gorm.io/driver/sqlserver"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/logger" "gorm.io/gorm/logger"
@@ -20,27 +21,17 @@ type provider struct {
db *gorm.DB db *gorm.DB
} }
const (
phoneNumberIndexName = "UQ_phone_number"
phoneNumberColumnName = "phone_number"
)
type indexInfo struct {
IndexName string `json:"index_name"`
ColumnName string `json:"column_name"`
}
// NewProvider returns a new SQL provider // NewProvider returns a new SQL provider
func NewProvider() (*provider, error) { func NewProvider() (*provider, error) {
var sqlDB *gorm.DB var sqlDB *gorm.DB
var err error var err error
customLogger := logger.New( customLogger := logger.New(
logrus.StandardLogger(), log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
logger.Config{ logger.Config{
SlowThreshold: time.Second, // Slow SQL threshold SlowThreshold: time.Second, // Slow SQL threshold
LogLevel: logger.Error, // Log level LogLevel: logger.Silent, // Log level
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
Colorful: false, // Disable color Colorful: false, // Disable color
}, },
) )
@@ -59,7 +50,7 @@ func NewProvider() (*provider, error) {
case constants.DbTypePostgres, constants.DbTypeYugabyte, constants.DbTypeCockroachDB: case constants.DbTypePostgres, constants.DbTypeYugabyte, constants.DbTypeCockroachDB:
sqlDB, err = gorm.Open(postgres.Open(dbURL), ormConfig) sqlDB, err = gorm.Open(postgres.Open(dbURL), ormConfig)
case constants.DbTypeSqlite: case constants.DbTypeSqlite:
sqlDB, err = gorm.Open(sqlite.Open(dbURL+"?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)"), ormConfig) sqlDB, err = gorm.Open(sqlite.Open(dbURL), ormConfig)
case constants.DbTypeMysql, constants.DbTypeMariaDB, constants.DbTypePlanetScaleDB: case constants.DbTypeMysql, constants.DbTypeMariaDB, constants.DbTypePlanetScaleDB:
sqlDB, err = gorm.Open(mysql.Open(dbURL), ormConfig) sqlDB, err = gorm.Open(mysql.Open(dbURL), ormConfig)
case constants.DbTypeSqlserver: case constants.DbTypeSqlserver:
@@ -70,44 +61,10 @@ func NewProvider() (*provider, error) {
return nil, err return nil, err
} }
// For sqlserver, handle uniqueness of phone_number manually via extra db call
// during create and update mutation.
if sqlDB.Migrator().HasConstraint(&models.User{}, "authorizer_users_phone_number_key") {
err = sqlDB.Migrator().DropConstraint(&models.User{}, "authorizer_users_phone_number_key")
logrus.Debug("Failed to drop phone number constraint:", err)
}
err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}, &models.Webhook{}, models.WebhookLog{}, models.EmailTemplate{}, &models.OTP{}) err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}, &models.Webhook{}, models.WebhookLog{}, models.EmailTemplate{}, &models.OTP{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
// IMPACT: Request user to manually delete: UQ_phone_number constraint
// unique constraint on phone number does not work with multiple null values for sqlserver
// for more information check https://stackoverflow.com/a/767702
// if dbType == constants.DbTypeSqlserver {
// var indexInfos []indexInfo
// // remove index on phone number if present with different name
// res := sqlDB.Raw("SELECT i.name AS index_name, i.type_desc AS index_algorithm, CASE i.is_unique WHEN 1 THEN 'TRUE' ELSE 'FALSE' END AS is_unique, ac.Name AS column_name FROM sys.tables AS t INNER JOIN sys.indexes AS i ON t.object_id = i.object_id INNER JOIN sys.index_columns AS ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id INNER JOIN sys.all_columns AS ac ON ic.object_id = ac.object_id AND ic.column_id = ac.column_id WHERE t.name = 'authorizer_users' AND SCHEMA_NAME(t.schema_id) = 'dbo';").Scan(&indexInfos)
// if res.Error != nil {
// return nil, res.Error
// }
// for _, val := range indexInfos {
// if val.ColumnName == phoneNumberColumnName && val.IndexName != phoneNumberIndexName {
// // drop index & create new
// if res := sqlDB.Exec(fmt.Sprintf(`ALTER TABLE authorizer_users DROP CONSTRAINT "%s";`, val.IndexName)); res.Error != nil {
// return nil, res.Error
// }
// // create index
// if res := sqlDB.Exec(fmt.Sprintf("CREATE UNIQUE NONCLUSTERED INDEX %s ON authorizer_users(phone_number) WHERE phone_number IS NOT NULL;", phoneNumberIndexName)); res.Error != nil {
// return nil, res.Error
// }
// }
// }
// }
return &provider{ return &provider{
db: sqlDB, db: sqlDB,
}, nil }, nil

View File

@@ -2,15 +2,12 @@ package sql
import ( import (
"context" "context"
"fmt"
"strings"
"time" "time"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/google/uuid" "github.com/google/uuid"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
@@ -30,12 +27,6 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
user.Roles = defaultRoles user.Roles = defaultRoles
} }
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
return user, fmt.Errorf("user with given phone number already exists")
}
}
user.CreatedAt = time.Now().Unix() user.CreatedAt = time.Now().Unix()
user.UpdatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix()
user.Key = user.ID user.Key = user.ID
@@ -67,12 +58,13 @@ func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.Use
// DeleteUser to delete user information from database // DeleteUser to delete user information from database
func (p *provider) DeleteUser(ctx context.Context, user models.User) error { func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
result := p.db.Where("user_id = ?", user.ID).Delete(&models.Session{}) result := p.db.Delete(&user)
if result.Error != nil { if result.Error != nil {
return result.Error return result.Error
} }
result = p.db.Delete(&user) result = p.db.Where("user_id = ?", user.ID).Delete(&models.Session{})
if result.Error != nil { if result.Error != nil {
return result.Error return result.Error
} }
@@ -149,15 +141,3 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
} }
return nil return nil
} }
// GetUserByPhoneNumber to get user information from database using phone number
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
var user *models.User
result := p.db.Where("phone_number = ?", phoneNumber).First(&user)
if result.Error != nil {
return nil, result.Error
}
return user, nil
}

View File

@@ -5,7 +5,6 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"strconv" "strconv"
"strings"
"text/template" "text/template"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@@ -127,12 +126,6 @@ func SendEmail(to []string, event string, data map[string]interface{}) error {
return err return err
} }
smtpLocalName, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySmtpLocalName)
if err != nil {
log.Debugf("Error while getting smtp localname from env variable: %v", err)
smtpLocalName = ""
}
isProd, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsProd) isProd, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsProd)
if err != nil { if err != nil {
log.Errorf("Error while getting env variable: %v", err) log.Errorf("Error while getting env variable: %v", err)
@@ -148,11 +141,6 @@ func SendEmail(to []string, event string, data map[string]interface{}) error {
if !isProd { if !isProd {
d.TLSConfig = &tls.Config{InsecureSkipVerify: true} d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
} }
if strings.TrimSpace(smtpLocalName) != "" {
d.LocalName = smtpLocalName
}
if err := d.DialAndSend(m); err != nil { if err := d.DialAndSend(m); err != nil {
log.Debug("SMTP Failed: ", err) log.Debug("SMTP Failed: ", err)
return err return err

48
server/env/env.go vendored
View File

@@ -55,7 +55,6 @@ func InitAllEnv() error {
osSmtpPort := os.Getenv(constants.EnvKeySmtpPort) osSmtpPort := os.Getenv(constants.EnvKeySmtpPort)
osSmtpUsername := os.Getenv(constants.EnvKeySmtpUsername) osSmtpUsername := os.Getenv(constants.EnvKeySmtpUsername)
osSmtpPassword := os.Getenv(constants.EnvKeySmtpPassword) osSmtpPassword := os.Getenv(constants.EnvKeySmtpPassword)
osSmtpLocalName := os.Getenv(constants.EnvKeySmtpLocalName)
osSenderEmail := os.Getenv(constants.EnvKeySenderEmail) osSenderEmail := os.Getenv(constants.EnvKeySenderEmail)
osJwtType := os.Getenv(constants.EnvKeyJwtType) osJwtType := os.Getenv(constants.EnvKeyJwtType)
osJwtSecret := os.Getenv(constants.EnvKeyJwtSecret) osJwtSecret := os.Getenv(constants.EnvKeyJwtSecret)
@@ -78,15 +77,11 @@ func InitAllEnv() error {
osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL) osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL)
osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName) osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName)
osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo) osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo)
osAwsRegion := os.Getenv(constants.EnvAwsRegion)
osAwsAccessKey := os.Getenv(constants.EnvAwsAccessKeyID)
osAwsSecretKey := os.Getenv(constants.EnvAwsSecretAccessKey)
// os bool vars // os bool vars
osAppCookieSecure := os.Getenv(constants.EnvKeyAppCookieSecure) osAppCookieSecure := os.Getenv(constants.EnvKeyAppCookieSecure)
osAdminCookieSecure := os.Getenv(constants.EnvKeyAdminCookieSecure) osAdminCookieSecure := os.Getenv(constants.EnvKeyAdminCookieSecure)
osDisableBasicAuthentication := os.Getenv(constants.EnvKeyDisableBasicAuthentication) osDisableBasicAuthentication := os.Getenv(constants.EnvKeyDisableBasicAuthentication)
osDisableMobileBasicAuthentication := os.Getenv(constants.AuthRecipeMethodMobileBasicAuth)
osDisableEmailVerification := os.Getenv(constants.EnvKeyDisableEmailVerification) osDisableEmailVerification := os.Getenv(constants.EnvKeyDisableEmailVerification)
osDisableMagicLinkLogin := os.Getenv(constants.EnvKeyDisableMagicLinkLogin) osDisableMagicLinkLogin := os.Getenv(constants.EnvKeyDisableMagicLinkLogin)
osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage) osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage)
@@ -124,27 +119,6 @@ func InitAllEnv() error {
} }
} }
if val, ok := envData[constants.EnvAwsRegion]; !ok || val == "" {
envData[constants.EnvAwsRegion] = osAwsRegion
}
if osAwsRegion != "" && envData[constants.EnvAwsRegion] != osAwsRegion {
envData[constants.EnvAwsRegion] = osAwsRegion
}
if val, ok := envData[constants.EnvAwsAccessKeyID]; !ok || val == "" {
envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey
}
if osAwsAccessKey != "" && envData[constants.EnvAwsAccessKeyID] != osAwsRegion {
envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey
}
if val, ok := envData[constants.EnvAwsSecretAccessKey]; !ok || val == "" {
envData[constants.EnvAwsSecretAccessKey] = osAwsSecretKey
}
if osAwsSecretKey != "" && envData[constants.EnvAwsSecretAccessKey] != osAwsRegion {
envData[constants.EnvAwsSecretAccessKey] = osAwsSecretKey
}
if val, ok := envData[constants.EnvKeyAppURL]; !ok || val == "" { if val, ok := envData[constants.EnvKeyAppURL]; !ok || val == "" {
envData[constants.EnvKeyAppURL] = osAppURL envData[constants.EnvKeyAppURL] = osAppURL
} }
@@ -207,13 +181,6 @@ func InitAllEnv() error {
envData[constants.EnvKeySmtpUsername] = osSmtpUsername envData[constants.EnvKeySmtpUsername] = osSmtpUsername
} }
if val, ok := envData[constants.EnvKeySmtpLocalName]; !ok || val == "" {
envData[constants.EnvKeySmtpLocalName] = osSmtpLocalName
}
if osSmtpLocalName != "" && envData[constants.EnvKeySmtpLocalName] != osSmtpLocalName {
envData[constants.EnvKeySmtpLocalName] = osSmtpLocalName
}
if val, ok := envData[constants.EnvKeySmtpPassword]; !ok || val == "" { if val, ok := envData[constants.EnvKeySmtpPassword]; !ok || val == "" {
envData[constants.EnvKeySmtpPassword] = osSmtpPassword envData[constants.EnvKeySmtpPassword] = osSmtpPassword
} }
@@ -333,7 +300,7 @@ func InitAllEnv() error {
envData[constants.EnvKeyJwtRoleClaim] = osJwtRoleClaim envData[constants.EnvKeyJwtRoleClaim] = osJwtRoleClaim
if envData[constants.EnvKeyJwtRoleClaim] == "" { if envData[constants.EnvKeyJwtRoleClaim] == "" {
envData[constants.EnvKeyJwtRoleClaim] = "roles" envData[constants.EnvKeyJwtRoleClaim] = "role"
} }
} }
if osJwtRoleClaim != "" && envData[constants.EnvKeyJwtRoleClaim] != osJwtRoleClaim { if osJwtRoleClaim != "" && envData[constants.EnvKeyJwtRoleClaim] != osJwtRoleClaim {
@@ -499,19 +466,6 @@ func InitAllEnv() error {
} }
} }
if _, ok := envData[constants.EnvKeyDisableMobileBasicAuthentication]; !ok {
envData[constants.EnvKeyDisableMobileBasicAuthentication] = osDisableBasicAuthentication == "true"
}
if osDisableMobileBasicAuthentication != "" {
boolValue, err := strconv.ParseBool(osDisableMobileBasicAuthentication)
if err != nil {
return err
}
if boolValue != envData[constants.EnvKeyDisableMobileBasicAuthentication].(bool) {
envData[constants.EnvKeyDisableMobileBasicAuthentication] = boolValue
}
}
if _, ok := envData[constants.EnvKeyDisableEmailVerification]; !ok { if _, ok := envData[constants.EnvKeyDisableEmailVerification]; !ok {
envData[constants.EnvKeyDisableEmailVerification] = osDisableEmailVerification == "true" envData[constants.EnvKeyDisableEmailVerification] = osDisableEmailVerification == "true"
} }

View File

@@ -75,6 +75,7 @@ func GetEnvData() (map[string]interface{}, error) {
} }
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey) memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData) b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
if err != nil { if err != nil {
log.Debug("Error while decrypting env data from B64: ", err) log.Debug("Error while decrypting env data from B64: ", err)
@@ -200,7 +201,7 @@ func PersistEnv() error {
envValue := strings.TrimSpace(os.Getenv(key)) envValue := strings.TrimSpace(os.Getenv(key))
if envValue != "" { if envValue != "" {
switch key { switch key {
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure: case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure:
if envValueBool, err := strconv.ParseBool(envValue); err == nil { if envValueBool, err := strconv.ParseBool(envValue); err == nil {
if value.(bool) != envValueBool { if value.(bool) != envValueBool {
storeData[key] = envValueBool storeData[key] = envValueBool

View File

@@ -5,10 +5,8 @@ go 1.16
require ( require (
github.com/99designs/gqlgen v0.17.20 github.com/99designs/gqlgen v0.17.20
github.com/arangodb/go-driver v1.2.1 github.com/arangodb/go-driver v1.2.1
github.com/aws/aws-sdk-go v1.44.109
github.com/coreos/go-oidc/v3 v3.1.0 github.com/coreos/go-oidc/v3 v3.1.0
github.com/gin-gonic/gin v1.8.1 github.com/gin-gonic/gin v1.8.1
github.com/glebarez/sqlite v1.5.0
github.com/go-playground/validator/v10 v10.11.1 // indirect github.com/go-playground/validator/v10 v10.11.1 // indirect
github.com/go-redis/redis/v8 v8.11.0 github.com/go-redis/redis/v8 v8.11.0
github.com/goccy/go-json v0.9.11 // indirect github.com/goccy/go-json v0.9.11 // indirect
@@ -16,7 +14,6 @@ require (
github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/guregu/dynamo v1.16.0
github.com/joho/godotenv v1.3.0 github.com/joho/godotenv v1.3.0
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect
@@ -25,15 +22,18 @@ require (
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
github.com/vektah/gqlparser/v2 v2.5.1 github.com/vektah/gqlparser/v2 v2.5.1
go.mongodb.org/mongo-driver v1.8.1 go.mongodb.org/mongo-driver v1.8.1
golang.org/x/crypto v0.3.0 golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b // indirect
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/mail.v2 v2.3.1 gopkg.in/mail.v2 v2.3.1
gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/square/go-jose.v2 v2.6.0
gorm.io/driver/mysql v1.4.3 gorm.io/driver/mysql v1.2.1
gorm.io/driver/postgres v1.4.5 gorm.io/driver/postgres v1.2.3
gorm.io/driver/sqlserver v1.4.1 gorm.io/driver/sqlite v1.2.6
gorm.io/gorm v1.24.1 gorm.io/driver/sqlserver v1.2.1
gorm.io/gorm v1.22.4
) )

View File

@@ -33,10 +33,6 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/99designs/gqlgen v0.17.20 h1:O7WzccIhKB1dm+7g6dhQcULINftfiLSBg2l/mwbpJMw= github.com/99designs/gqlgen v0.17.20 h1:O7WzccIhKB1dm+7g6dhQcULINftfiLSBg2l/mwbpJMw=
github.com/99designs/gqlgen v0.17.20/go.mod h1:Mja2HI23kWT1VRH09hvWshFgOzKswpO20o4ScpJIES4= github.com/99designs/gqlgen v0.17.20/go.mod h1:Mja2HI23kWT1VRH09hvWshFgOzKswpO20o4ScpJIES4=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
@@ -53,15 +49,10 @@ github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e h1:Xg+hGrY2
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e/go.mod h1:mq7Shfa/CaixoDxiyAAc5jZ6CVBAyPaNQCGS7mkj4Ho= github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e/go.mod h1:mq7Shfa/CaixoDxiyAAc5jZ6CVBAyPaNQCGS7mkj4Ho=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/aws/aws-sdk-go v1.42.47/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc=
github.com/aws/aws-sdk-go v1.44.109 h1:+Na5JPeS0kiEHoBp5Umcuuf+IDqXqD0lXnM920E31YI=
github.com/aws/aws-sdk-go v1.44.109/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY=
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -85,13 +76,12 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4= github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI=
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -103,10 +93,6 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/glebarez/go-sqlite v1.19.1 h1:o2XhjyR8CQ2m84+bVz10G0cabmG0tY4sIMiCbrcUTrY=
github.com/glebarez/go-sqlite v1.19.1/go.mod h1:9AykawGIyIcxoSfpYWiX1SgTNHTNsa/FVc75cDkbp4M=
github.com/glebarez/sqlite v1.5.0 h1:+8LAEpmywqresSoGlqjjT+I9m4PseIM3NcerIJ/V7mk=
github.com/glebarez/sqlite v1.5.0/go.mod h1:0wzXzTvfVJIN2GqRhCdMbnYd+m+aH5/QV7B30rM6NgY=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -132,18 +118,12 @@ github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gocql/gocql v1.2.0 h1:TZhsCd7fRuye4VyHr3WCvWwIQaZUmjsqnSIXK9FcVCE= github.com/gocql/gocql v1.2.0 h1:TZhsCd7fRuye4VyHr3WCvWwIQaZUmjsqnSIXK9FcVCE=
github.com/gocql/gocql v1.2.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= github.com/gocql/gocql v1.2.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -184,7 +164,6 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -206,8 +185,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/guregu/dynamo v1.16.0 h1:gmI8oi1VHwYQtq7+RPBeOiSssVLgxH/Az2t+NtDtL2c=
github.com/guregu/dynamo v1.16.0/go.mod h1:W2Gqcf3MtkrS+Q6fHPGAmRtT0Dyq+TGrqfqrUC9+R/c=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -227,8 +204,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8=
github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
@@ -245,42 +222,37 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns=
github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= github.com/jackc/pgtype v1.9.0 h1:/SH1RxEtltvJgsDqp3TbiTFApD3mey3iygpuEGeuBXk=
github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= github.com/jackc/pgx/v4 v4.14.0 h1:TgdrmgnM7VY72EuSQzBbBd4JA1RLqJolrw9nQVZABVc=
github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
@@ -296,7 +268,6 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -315,9 +286,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA= github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA=
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -325,9 +295,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -341,8 +309,6 @@ github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -350,8 +316,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f h1:a7clxaGmmqtdNTXyvrp/lVO/Gnkzlhc/+dLs5v965GM= github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f h1:a7clxaGmmqtdNTXyvrp/lVO/Gnkzlhc/+dLs5v965GM=
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f/go.mod h1:/mK7FZ3mFYEn9zvNPhpngTyatyehSwte5bJZ4ehL5Xw= github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f/go.mod h1:/mK7FZ3mFYEn9zvNPhpngTyatyehSwte5bJZ4ehL5Xw=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -433,6 +397,7 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -445,11 +410,8 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -513,18 +475,14 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b h1:uKO3Js8lXGjpjdc4J3rqs0/Ex5yDKUGfk43tTYWVLas=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -583,25 +541,20 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -610,9 +563,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -663,7 +615,6 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
@@ -777,7 +728,6 @@ gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -788,17 +738,18 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.4.3 h1:/JhWJhO2v17d8hjApTltKNADm7K7YI2ogkR7avJUL3k= gorm.io/driver/mysql v1.2.1 h1:h+3f1l9Ng2C072Y2tIiLgPpWN78r1KXL7bHJ0nTjlhU=
gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= gorm.io/driver/mysql v1.2.1/go.mod h1:qsiz+XcAyMrS6QY+X3M9R6b/lKM1imKmcuK9kac5LTo=
gorm.io/driver/postgres v1.4.5 h1:mTeXTTtHAgnS9PgmhN2YeUbazYpLhUI1doLnw42XUZc= gorm.io/driver/postgres v1.2.3 h1:f4t0TmNMy9gh3TU2PX+EppoA6YsgFnyq8Ojtddb42To=
gorm.io/driver/postgres v1.4.5/go.mod h1:GKNQYSJ14qvWkvPwXljMGehpKrhlDNsqYRr5HnYGncg= gorm.io/driver/postgres v1.2.3/go.mod h1:pJV6RgYQPG47aM1f0QeOzFH9HxQc8JcmAgjRCgS0wjs=
gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0= gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4=
gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig= gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/driver/sqlserver v1.2.1 h1:KhGOjvPX7JZ5hPyQICTJfMuTz88zgJ2lk9bWiHVNHd8=
gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= gorm.io/driver/sqlserver v1.2.1/go.mod h1:nixq0OB3iLXZDiPv6JSOjWuPgpyaRpOIIevYtA4Ulb4=
gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.24.1 h1:CgvzRniUdG67hBAzsxDGOAuq4Te1osVMYsa1eQbd4fs= gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.24.1/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= gorm.io/gorm v1.22.4 h1:8aPcyEJhY0MAt8aY6Dc524Pn+pO29K+ydu+e/cXSpQM=
gorm.io/gorm v1.22.4/go.mod h1:1aeVC+pe9ZmvKZban/gW4QPra7PRoTEssyc922qCAkk=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -806,38 +757,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
modernc.org/cc/v3 v3.38.1/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI=
modernc.org/ccgo/v3 v3.0.0-20220910160915-348f15de615a/go.mod h1:8p47QxPkdugex9J4n9P2tLZ9bK01yngIVp00g4nomW0=
modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0=
modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA=
modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0=
modernc.org/libc v1.19.0 h1:bXyVhGQg6KIClTr8FMVIDPl7jtbcs7aS5WP7vLDaxPs=
modernc.org/libc v1.19.0/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.19.1 h1:8xmS5oLnZtAK//vnd4aTVj8VOeTAccEFOtUnIzfSw+4=
modernc.org/sqlite v1.19.1/go.mod h1:UfQ83woKMaPW/ZBruK0T7YaFCrI+IE0LeWVY6pmnVms=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.14.0/go.mod h1:gQ7c1YPMvryCHCcmf8acB6VPabE59QBeuRQLL7cTUlM=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.6.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@@ -118,7 +118,6 @@ type ComplexityRoot struct {
ResetPasswordURL func(childComplexity int) int ResetPasswordURL func(childComplexity int) int
Roles func(childComplexity int) int Roles func(childComplexity int) int
SMTPHost func(childComplexity int) int SMTPHost func(childComplexity int) int
SMTPLocalName func(childComplexity int) int
SMTPPassword func(childComplexity int) int SMTPPassword func(childComplexity int) int
SMTPPort func(childComplexity int) int SMTPPort func(childComplexity int) int
SMTPUsername func(childComplexity int) int SMTPUsername func(childComplexity int) int
@@ -171,8 +170,6 @@ type ComplexityRoot struct {
Login func(childComplexity int, params model.LoginInput) int Login func(childComplexity int, params model.LoginInput) int
Logout func(childComplexity int) int Logout func(childComplexity int) int
MagicLinkLogin func(childComplexity int, params model.MagicLinkLoginInput) int MagicLinkLogin func(childComplexity int, params model.MagicLinkLoginInput) int
MobileLogin func(childComplexity int, params model.MobileLoginInput) int
MobileSignup func(childComplexity int, params *model.MobileSignUpInput) int
ResendOtp func(childComplexity int, params model.ResendOTPRequest) int ResendOtp func(childComplexity int, params model.ResendOTPRequest) int
ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int
ResetPassword func(childComplexity int, params model.ResetPasswordInput) int ResetPassword func(childComplexity int, params model.ResetPasswordInput) int
@@ -248,7 +245,6 @@ type ComplexityRoot struct {
} }
ValidateJWTTokenResponse struct { ValidateJWTTokenResponse struct {
Claims func(childComplexity int) int
IsValid func(childComplexity int) int IsValid func(childComplexity int) int
} }
@@ -302,9 +298,7 @@ type ComplexityRoot struct {
type MutationResolver interface { type MutationResolver interface {
Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error)
MobileSignup(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error)
Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error)
MobileLogin(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error)
MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error)
Logout(ctx context.Context) (*model.Response, error) Logout(ctx context.Context) (*model.Response, error)
UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error) UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error)
@@ -811,13 +805,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Env.SMTPHost(childComplexity), true return e.complexity.Env.SMTPHost(childComplexity), true
case "Env.SMTP_LOCAL_NAME":
if e.complexity.Env.SMTPLocalName == nil {
break
}
return e.complexity.Env.SMTPLocalName(childComplexity), true
case "Env.SMTP_PASSWORD": case "Env.SMTP_PASSWORD":
if e.complexity.Env.SMTPPassword == nil { if e.complexity.Env.SMTPPassword == nil {
break break
@@ -1163,30 +1150,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.MagicLinkLogin(childComplexity, args["params"].(model.MagicLinkLoginInput)), true return e.complexity.Mutation.MagicLinkLogin(childComplexity, args["params"].(model.MagicLinkLoginInput)), true
case "Mutation.mobile_login":
if e.complexity.Mutation.MobileLogin == nil {
break
}
args, err := ec.field_Mutation_mobile_login_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.MobileLogin(childComplexity, args["params"].(model.MobileLoginInput)), true
case "Mutation.mobile_signup":
if e.complexity.Mutation.MobileSignup == nil {
break
}
args, err := ec.field_Mutation_mobile_signup_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.MobileSignup(childComplexity, args["params"].(*model.MobileSignUpInput)), true
case "Mutation.resend_otp": case "Mutation.resend_otp":
if e.complexity.Mutation.ResendOtp == nil { if e.complexity.Mutation.ResendOtp == nil {
break break
@@ -1675,13 +1638,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Users.Users(childComplexity), true return e.complexity.Users.Users(childComplexity), true
case "ValidateJWTTokenResponse.claims":
if e.complexity.ValidateJWTTokenResponse.Claims == nil {
break
}
return e.complexity.ValidateJWTTokenResponse.Claims(childComplexity), true
case "ValidateJWTTokenResponse.is_valid": case "ValidateJWTTokenResponse.is_valid":
if e.complexity.ValidateJWTTokenResponse.IsValid == nil { if e.complexity.ValidateJWTTokenResponse.IsValid == nil {
break break
@@ -1912,8 +1868,6 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputListWebhookLogRequest, ec.unmarshalInputListWebhookLogRequest,
ec.unmarshalInputLoginInput, ec.unmarshalInputLoginInput,
ec.unmarshalInputMagicLinkLoginInput, ec.unmarshalInputMagicLinkLoginInput,
ec.unmarshalInputMobileLoginInput,
ec.unmarshalInputMobileSignUpInput,
ec.unmarshalInputOAuthRevokeInput, ec.unmarshalInputOAuthRevokeInput,
ec.unmarshalInputPaginatedInput, ec.unmarshalInputPaginatedInput,
ec.unmarshalInputPaginationInput, ec.unmarshalInputPaginationInput,
@@ -2105,7 +2059,6 @@ type Env {
SMTP_PORT: String SMTP_PORT: String
SMTP_USERNAME: String SMTP_USERNAME: String
SMTP_PASSWORD: String SMTP_PASSWORD: String
SMTP_LOCAL_NAME: String
SENDER_EMAIL: String SENDER_EMAIL: String
JWT_TYPE: String JWT_TYPE: String
JWT_SECRET: String JWT_SECRET: String
@@ -2148,7 +2101,6 @@ type Env {
type ValidateJWTTokenResponse { type ValidateJWTTokenResponse {
is_valid: Boolean! is_valid: Boolean!
claims: Map
} }
type GenerateJWTKeysResponse { type GenerateJWTKeysResponse {
@@ -2216,7 +2168,6 @@ input UpdateEnvInput {
SMTP_PORT: String SMTP_PORT: String
SMTP_USERNAME: String SMTP_USERNAME: String
SMTP_PASSWORD: String SMTP_PASSWORD: String
SMTP_LOCAL_NAME: String
SENDER_EMAIL: String SENDER_EMAIL: String
JWT_TYPE: String JWT_TYPE: String
JWT_SECRET: String JWT_SECRET: String
@@ -2264,28 +2215,6 @@ input AdminSignupInput {
admin_secret: String! admin_secret: String!
} }
input MobileSignUpInput {
email: String
given_name: String
family_name: String
middle_name: String
nickname: String
gender: String
birthdate: String
phone_number: String!
picture: String
password: String!
confirm_password: String!
roles: [String!]
scope: [String!]
redirect_uri: String
is_multi_factor_auth_enabled: Boolean
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
state: String
}
input SignUpInput { input SignUpInput {
email: String! email: String!
given_name: String given_name: String
@@ -2302,10 +2231,6 @@ input SignUpInput {
scope: [String!] scope: [String!]
redirect_uri: String redirect_uri: String
is_multi_factor_auth_enabled: Boolean is_multi_factor_auth_enabled: Boolean
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
state: String
} }
input LoginInput { input LoginInput {
@@ -2313,38 +2238,15 @@ input LoginInput {
password: String! password: String!
roles: [String!] roles: [String!]
scope: [String!] scope: [String!]
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
state: String
}
input MobileLoginInput {
phone_number: String!
password: String!
roles: [String!]
scope: [String!]
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
state: String
} }
input VerifyEmailInput { input VerifyEmailInput {
token: String! token: String!
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
state: String
} }
input ResendVerifyEmailInput { input ResendVerifyEmailInput {
email: String! email: String!
identifier: String! identifier: String!
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
state: String
} }
input UpdateProfileInput { input UpdateProfileInput {
@@ -2474,9 +2376,7 @@ input AddEmailTemplateRequest {
event_name: String! event_name: String!
subject: String! subject: String!
template: String! template: String!
# Design value is set when editor is used design: String!
# If raw HTML is used design value is set to null
design: String
} }
input UpdateEmailTemplateRequest { input UpdateEmailTemplateRequest {
@@ -2484,8 +2384,6 @@ input UpdateEmailTemplateRequest {
event_name: String event_name: String
template: String template: String
subject: String subject: String
# Design value is set when editor is used
# If raw HTML is used design value is set to null
design: String design: String
} }
@@ -2496,25 +2394,15 @@ input DeleteEmailTemplateRequest {
input VerifyOTPRequest { input VerifyOTPRequest {
email: String! email: String!
otp: String! otp: String!
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
state: String
} }
input ResendOTPRequest { input ResendOTPRequest {
email: String! email: String!
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
state: String
} }
type Mutation { type Mutation {
signup(params: SignUpInput!): AuthResponse! signup(params: SignUpInput!): AuthResponse!
mobile_signup(params: MobileSignUpInput): AuthResponse!
login(params: LoginInput!): AuthResponse! login(params: LoginInput!): AuthResponse!
mobile_login(params: MobileLoginInput!): AuthResponse!
magic_link_login(params: MagicLinkLoginInput!): Response! magic_link_login(params: MagicLinkLoginInput!): Response!
logout: Response! logout: Response!
update_profile(params: UpdateProfileInput!): Response! update_profile(params: UpdateProfileInput!): Response!
@@ -2853,36 +2741,6 @@ func (ec *executionContext) field_Mutation_magic_link_login_args(ctx context.Con
return args, nil return args, nil
} }
func (ec *executionContext) field_Mutation_mobile_login_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 model.MobileLoginInput
if tmp, ok := rawArgs["params"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params"))
arg0, err = ec.unmarshalNMobileLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileLoginInput(ctx, tmp)
if err != nil {
return nil, err
}
}
args["params"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_mobile_signup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 *model.MobileSignUpInput
if tmp, ok := rawArgs["params"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params"))
arg0, err = ec.unmarshalOMobileSignUpInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileSignUpInput(ctx, tmp)
if err != nil {
return nil, err
}
}
args["params"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_resend_otp_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { func (ec *executionContext) field_Mutation_resend_otp_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error var err error
args := map[string]interface{}{} args := map[string]interface{}{}
@@ -4584,47 +4442,6 @@ func (ec *executionContext) fieldContext_Env_SMTP_PASSWORD(ctx context.Context,
return fc, nil return fc, nil
} }
func (ec *executionContext) _Env_SMTP_LOCAL_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Env_SMTP_LOCAL_NAME(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.SMTPLocalName, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Env_SMTP_LOCAL_NAME(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Env",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Env_SENDER_EMAIL(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) { func (ec *executionContext) _Env_SENDER_EMAIL(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Env_SENDER_EMAIL(ctx, field) fc, err := ec.fieldContext_Env_SENDER_EMAIL(ctx, field)
if err != nil { if err != nil {
@@ -7114,77 +6931,6 @@ func (ec *executionContext) fieldContext_Mutation_signup(ctx context.Context, fi
return fc, nil return fc, nil
} }
func (ec *executionContext) _Mutation_mobile_signup(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_mobile_signup(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().MobileSignup(rctx, fc.Args["params"].(*model.MobileSignUpInput))
})
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.AuthResponse)
fc.Result = res
return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Mutation_mobile_signup(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Mutation",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "message":
return ec.fieldContext_AuthResponse_message(ctx, field)
case "should_show_otp_screen":
return ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field)
case "access_token":
return ec.fieldContext_AuthResponse_access_token(ctx, field)
case "id_token":
return ec.fieldContext_AuthResponse_id_token(ctx, field)
case "refresh_token":
return ec.fieldContext_AuthResponse_refresh_token(ctx, field)
case "expires_in":
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
case "user":
return ec.fieldContext_AuthResponse_user(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Mutation_mobile_signup_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return
}
return fc, nil
}
func (ec *executionContext) _Mutation_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { func (ec *executionContext) _Mutation_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_login(ctx, field) fc, err := ec.fieldContext_Mutation_login(ctx, field)
if err != nil { if err != nil {
@@ -7256,77 +7002,6 @@ func (ec *executionContext) fieldContext_Mutation_login(ctx context.Context, fie
return fc, nil return fc, nil
} }
func (ec *executionContext) _Mutation_mobile_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_mobile_login(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().MobileLogin(rctx, fc.Args["params"].(model.MobileLoginInput))
})
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.AuthResponse)
fc.Result = res
return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Mutation_mobile_login(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Mutation",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "message":
return ec.fieldContext_AuthResponse_message(ctx, field)
case "should_show_otp_screen":
return ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field)
case "access_token":
return ec.fieldContext_AuthResponse_access_token(ctx, field)
case "id_token":
return ec.fieldContext_AuthResponse_id_token(ctx, field)
case "refresh_token":
return ec.fieldContext_AuthResponse_refresh_token(ctx, field)
case "expires_in":
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
case "user":
return ec.fieldContext_AuthResponse_user(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Mutation_mobile_login_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return
}
return fc, nil
}
func (ec *executionContext) _Mutation_magic_link_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { func (ec *executionContext) _Mutation_magic_link_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_magic_link_login(ctx, field) fc, err := ec.fieldContext_Mutation_magic_link_login(ctx, field)
if err != nil { if err != nil {
@@ -9410,8 +9085,6 @@ func (ec *executionContext) fieldContext_Query_validate_jwt_token(ctx context.Co
switch field.Name { switch field.Name {
case "is_valid": case "is_valid":
return ec.fieldContext_ValidateJWTTokenResponse_is_valid(ctx, field) return ec.fieldContext_ValidateJWTTokenResponse_is_valid(ctx, field)
case "claims":
return ec.fieldContext_ValidateJWTTokenResponse_claims(ctx, field)
} }
return nil, fmt.Errorf("no field named %q was found under type ValidateJWTTokenResponse", field.Name) return nil, fmt.Errorf("no field named %q was found under type ValidateJWTTokenResponse", field.Name)
}, },
@@ -9671,8 +9344,6 @@ func (ec *executionContext) fieldContext_Query__env(ctx context.Context, field g
return ec.fieldContext_Env_SMTP_USERNAME(ctx, field) return ec.fieldContext_Env_SMTP_USERNAME(ctx, field)
case "SMTP_PASSWORD": case "SMTP_PASSWORD":
return ec.fieldContext_Env_SMTP_PASSWORD(ctx, field) return ec.fieldContext_Env_SMTP_PASSWORD(ctx, field)
case "SMTP_LOCAL_NAME":
return ec.fieldContext_Env_SMTP_LOCAL_NAME(ctx, field)
case "SENDER_EMAIL": case "SENDER_EMAIL":
return ec.fieldContext_Env_SENDER_EMAIL(ctx, field) return ec.fieldContext_Env_SENDER_EMAIL(ctx, field)
case "JWT_TYPE": case "JWT_TYPE":
@@ -11241,47 +10912,6 @@ func (ec *executionContext) fieldContext_ValidateJWTTokenResponse_is_valid(ctx c
return fc, nil return fc, nil
} }
func (ec *executionContext) _ValidateJWTTokenResponse_claims(ctx context.Context, field graphql.CollectedField, obj *model.ValidateJWTTokenResponse) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_ValidateJWTTokenResponse_claims(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Claims, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(map[string]interface{})
fc.Result = res
return ec.marshalOMap2map(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_ValidateJWTTokenResponse_claims(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "ValidateJWTTokenResponse",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Map does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _VerificationRequest_id(ctx context.Context, field graphql.CollectedField, obj *model.VerificationRequest) (ret graphql.Marshaler) { func (ec *executionContext) _VerificationRequest_id(ctx context.Context, field graphql.CollectedField, obj *model.VerificationRequest) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_VerificationRequest_id(ctx, field) fc, err := ec.fieldContext_VerificationRequest_id(ctx, field)
if err != nil { if err != nil {
@@ -14395,7 +14025,7 @@ func (ec *executionContext) unmarshalInputAddEmailTemplateRequest(ctx context.Co
var err error var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("design")) ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("design"))
it.Design, err = ec.unmarshalOString2string(ctx, v) it.Design, err = ec.unmarshalNString2string(ctx, v)
if err != nil { if err != nil {
return it, err return it, err
} }
@@ -14720,7 +14350,7 @@ func (ec *executionContext) unmarshalInputLoginInput(ctx context.Context, obj in
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"email", "password", "roles", "scope", "state"} fieldsInOrder := [...]string{"email", "password", "roles", "scope"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -14759,14 +14389,6 @@ func (ec *executionContext) unmarshalInputLoginInput(ctx context.Context, obj in
if err != nil { if err != nil {
return it, err return it, err
} }
case "state":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
it.State, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
} }
} }
@@ -14833,214 +14455,6 @@ func (ec *executionContext) unmarshalInputMagicLinkLoginInput(ctx context.Contex
return it, nil return it, nil
} }
func (ec *executionContext) unmarshalInputMobileLoginInput(ctx context.Context, obj interface{}) (model.MobileLoginInput, error) {
var it model.MobileLoginInput
asMap := map[string]interface{}{}
for k, v := range obj.(map[string]interface{}) {
asMap[k] = v
}
fieldsInOrder := [...]string{"phone_number", "password", "roles", "scope", "state"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "phone_number":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number"))
it.PhoneNumber, err = ec.unmarshalNString2string(ctx, v)
if err != nil {
return it, err
}
case "password":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password"))
it.Password, err = ec.unmarshalNString2string(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 "scope":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("scope"))
it.Scope, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v)
if err != nil {
return it, err
}
case "state":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
it.State, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputMobileSignUpInput(ctx context.Context, obj interface{}) (model.MobileSignUpInput, error) {
var it model.MobileSignUpInput
asMap := map[string]interface{}{}
for k, v := range obj.(map[string]interface{}) {
asMap[k] = v
}
fieldsInOrder := [...]string{"email", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "password", "confirm_password", "roles", "scope", "redirect_uri", "is_multi_factor_auth_enabled", "state"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "email":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
it.Email, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "given_name":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("given_name"))
it.GivenName, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "family_name":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("family_name"))
it.FamilyName, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "middle_name":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("middle_name"))
it.MiddleName, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "nickname":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("nickname"))
it.Nickname, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "gender":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gender"))
it.Gender, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "birthdate":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("birthdate"))
it.Birthdate, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "phone_number":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number"))
it.PhoneNumber, err = ec.unmarshalNString2string(ctx, v)
if err != nil {
return it, err
}
case "picture":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("picture"))
it.Picture, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "password":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password"))
it.Password, err = ec.unmarshalNString2string(ctx, v)
if err != nil {
return it, err
}
case "confirm_password":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("confirm_password"))
it.ConfirmPassword, err = ec.unmarshalNString2string(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 "scope":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("scope"))
it.Scope, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v)
if err != nil {
return it, err
}
case "redirect_uri":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("redirect_uri"))
it.RedirectURI, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "is_multi_factor_auth_enabled":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("is_multi_factor_auth_enabled"))
it.IsMultiFactorAuthEnabled, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
if err != nil {
return it, err
}
case "state":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
it.State, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputOAuthRevokeInput(ctx context.Context, obj interface{}) (model.OAuthRevokeInput, error) { func (ec *executionContext) unmarshalInputOAuthRevokeInput(ctx context.Context, obj interface{}) (model.OAuthRevokeInput, error) {
var it model.OAuthRevokeInput var it model.OAuthRevokeInput
asMap := map[string]interface{}{} asMap := map[string]interface{}{}
@@ -15140,7 +14554,7 @@ func (ec *executionContext) unmarshalInputResendOTPRequest(ctx context.Context,
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"email", "state"} fieldsInOrder := [...]string{"email"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -15155,14 +14569,6 @@ func (ec *executionContext) unmarshalInputResendOTPRequest(ctx context.Context,
if err != nil { if err != nil {
return it, err return it, err
} }
case "state":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
it.State, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
} }
} }
@@ -15176,7 +14582,7 @@ func (ec *executionContext) unmarshalInputResendVerifyEmailInput(ctx context.Con
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"email", "identifier", "state"} fieldsInOrder := [...]string{"email", "identifier"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -15199,14 +14605,6 @@ func (ec *executionContext) unmarshalInputResendVerifyEmailInput(ctx context.Con
if err != nil { if err != nil {
return it, err return it, err
} }
case "state":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
it.State, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
} }
} }
@@ -15300,7 +14698,7 @@ func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj i
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"email", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "password", "confirm_password", "roles", "scope", "redirect_uri", "is_multi_factor_auth_enabled", "state"} fieldsInOrder := [...]string{"email", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "password", "confirm_password", "roles", "scope", "redirect_uri", "is_multi_factor_auth_enabled"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -15427,14 +14825,6 @@ func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj i
if err != nil { if err != nil {
return it, err return it, err
} }
case "state":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
it.State, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
} }
} }
@@ -15580,7 +14970,7 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "ORGANIZATION_NAME", "ORGANIZATION_LOGO"} fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SENDER_EMAIL", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "ORGANIZATION_NAME", "ORGANIZATION_LOGO"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -15651,14 +15041,6 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
if err != nil { if err != nil {
return it, err return it, err
} }
case "SMTP_LOCAL_NAME":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("SMTP_LOCAL_NAME"))
it.SMTPLocalName, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "SENDER_EMAIL": case "SENDER_EMAIL":
var err error var err error
@@ -16320,7 +15702,7 @@ func (ec *executionContext) unmarshalInputVerifyEmailInput(ctx context.Context,
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"token", "state"} fieldsInOrder := [...]string{"token"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -16335,14 +15717,6 @@ func (ec *executionContext) unmarshalInputVerifyEmailInput(ctx context.Context,
if err != nil { if err != nil {
return it, err return it, err
} }
case "state":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
it.State, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
} }
} }
@@ -16356,7 +15730,7 @@ func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context,
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"email", "otp", "state"} fieldsInOrder := [...]string{"email", "otp"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -16379,14 +15753,6 @@ func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context,
if err != nil { if err != nil {
return it, err return it, err
} }
case "state":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
it.State, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
} }
} }
@@ -16660,10 +16026,6 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
out.Values[i] = ec._Env_SMTP_PASSWORD(ctx, field, obj) out.Values[i] = ec._Env_SMTP_PASSWORD(ctx, field, obj)
case "SMTP_LOCAL_NAME":
out.Values[i] = ec._Env_SMTP_LOCAL_NAME(ctx, field, obj)
case "SENDER_EMAIL": case "SENDER_EMAIL":
out.Values[i] = ec._Env_SENDER_EMAIL(ctx, field, obj) out.Values[i] = ec._Env_SENDER_EMAIL(ctx, field, obj)
@@ -17072,15 +16434,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
return ec._Mutation_signup(ctx, field) return ec._Mutation_signup(ctx, field)
}) })
if out.Values[i] == graphql.Null {
invalids++
}
case "mobile_signup":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_mobile_signup(ctx, field)
})
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
invalids++ invalids++
} }
@@ -17090,15 +16443,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
return ec._Mutation_login(ctx, field) return ec._Mutation_login(ctx, field)
}) })
if out.Values[i] == graphql.Null {
invalids++
}
case "mobile_login":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_mobile_login(ctx, field)
})
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
invalids++ invalids++
} }
@@ -17944,10 +17288,6 @@ func (ec *executionContext) _ValidateJWTTokenResponse(ctx context.Context, sel a
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
invalids++ invalids++
} }
case "claims":
out.Values[i] = ec._ValidateJWTTokenResponse_claims(ctx, field, obj)
default: default:
panic("unknown field " + strconv.Quote(field.Name)) panic("unknown field " + strconv.Quote(field.Name))
} }
@@ -18770,11 +18110,6 @@ func (ec *executionContext) marshalNMeta2ᚖgithubᚗcomᚋauthorizerdevᚋautho
return ec._Meta(ctx, sel, v) return ec._Meta(ctx, sel, v)
} }
func (ec *executionContext) unmarshalNMobileLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileLoginInput(ctx context.Context, v interface{}) (model.MobileLoginInput, error) {
res, err := ec.unmarshalInputMobileLoginInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) unmarshalNOAuthRevokeInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐOAuthRevokeInput(ctx context.Context, v interface{}) (model.OAuthRevokeInput, error) { func (ec *executionContext) unmarshalNOAuthRevokeInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐOAuthRevokeInput(ctx context.Context, v interface{}) (model.OAuthRevokeInput, error) {
res, err := ec.unmarshalInputOAuthRevokeInput(ctx, v) res, err := ec.unmarshalInputOAuthRevokeInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err) return res, graphql.ErrorOnPath(ctx, err)
@@ -19569,14 +18904,6 @@ func (ec *executionContext) marshalOMap2map(ctx context.Context, sel ast.Selecti
return res return res
} }
func (ec *executionContext) unmarshalOMobileSignUpInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileSignUpInput(ctx context.Context, v interface{}) (*model.MobileSignUpInput, error) {
if v == nil {
return nil, nil
}
res, err := ec.unmarshalInputMobileSignUpInput(ctx, v)
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) unmarshalOPaginatedInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginatedInput(ctx context.Context, v interface{}) (*model.PaginatedInput, error) { func (ec *executionContext) unmarshalOPaginatedInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginatedInput(ctx context.Context, v interface{}) (*model.PaginatedInput, error) {
if v == nil { if v == nil {
return nil, nil return nil, nil

View File

@@ -3,10 +3,10 @@
package model package model
type AddEmailTemplateRequest struct { type AddEmailTemplateRequest struct {
EventName string `json:"event_name"` EventName string `json:"event_name"`
Subject string `json:"subject"` Subject string `json:"subject"`
Template string `json:"template"` Template string `json:"template"`
Design *string `json:"design"` Design string `json:"design"`
} }
type AddWebhookRequest struct { type AddWebhookRequest struct {
@@ -74,7 +74,6 @@ type Env struct {
SMTPPort *string `json:"SMTP_PORT"` SMTPPort *string `json:"SMTP_PORT"`
SMTPUsername *string `json:"SMTP_USERNAME"` SMTPUsername *string `json:"SMTP_USERNAME"`
SMTPPassword *string `json:"SMTP_PASSWORD"` SMTPPassword *string `json:"SMTP_PASSWORD"`
SMTPLocalName *string `json:"SMTP_LOCAL_NAME"`
SenderEmail *string `json:"SENDER_EMAIL"` SenderEmail *string `json:"SENDER_EMAIL"`
JwtType *string `json:"JWT_TYPE"` JwtType *string `json:"JWT_TYPE"`
JwtSecret *string `json:"JWT_SECRET"` JwtSecret *string `json:"JWT_SECRET"`
@@ -151,7 +150,6 @@ type LoginInput struct {
Password string `json:"password"` Password string `json:"password"`
Roles []string `json:"roles"` Roles []string `json:"roles"`
Scope []string `json:"scope"` Scope []string `json:"scope"`
State *string `json:"state"`
} }
type MagicLinkLoginInput struct { type MagicLinkLoginInput struct {
@@ -179,33 +177,6 @@ type Meta struct {
IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"` IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"`
} }
type MobileLoginInput struct {
PhoneNumber string `json:"phone_number"`
Password string `json:"password"`
Roles []string `json:"roles"`
Scope []string `json:"scope"`
State *string `json:"state"`
}
type MobileSignUpInput struct {
Email *string `json:"email"`
GivenName *string `json:"given_name"`
FamilyName *string `json:"family_name"`
MiddleName *string `json:"middle_name"`
Nickname *string `json:"nickname"`
Gender *string `json:"gender"`
Birthdate *string `json:"birthdate"`
PhoneNumber string `json:"phone_number"`
Picture *string `json:"picture"`
Password string `json:"password"`
ConfirmPassword string `json:"confirm_password"`
Roles []string `json:"roles"`
Scope []string `json:"scope"`
RedirectURI *string `json:"redirect_uri"`
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
State *string `json:"state"`
}
type OAuthRevokeInput struct { type OAuthRevokeInput struct {
RefreshToken string `json:"refresh_token"` RefreshToken string `json:"refresh_token"`
} }
@@ -227,14 +198,12 @@ type PaginationInput struct {
} }
type ResendOTPRequest struct { type ResendOTPRequest struct {
Email string `json:"email"` Email string `json:"email"`
State *string `json:"state"`
} }
type ResendVerifyEmailInput struct { type ResendVerifyEmailInput struct {
Email string `json:"email"` Email string `json:"email"`
Identifier string `json:"identifier"` Identifier string `json:"identifier"`
State *string `json:"state"`
} }
type ResetPasswordInput struct { type ResetPasswordInput struct {
@@ -268,7 +237,6 @@ type SignUpInput struct {
Scope []string `json:"scope"` Scope []string `json:"scope"`
RedirectURI *string `json:"redirect_uri"` RedirectURI *string `json:"redirect_uri"`
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"` IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
State *string `json:"state"`
} }
type TestEndpointRequest struct { type TestEndpointRequest struct {
@@ -303,7 +271,6 @@ type UpdateEnvInput struct {
SMTPPort *string `json:"SMTP_PORT"` SMTPPort *string `json:"SMTP_PORT"`
SMTPUsername *string `json:"SMTP_USERNAME"` SMTPUsername *string `json:"SMTP_USERNAME"`
SMTPPassword *string `json:"SMTP_PASSWORD"` SMTPPassword *string `json:"SMTP_PASSWORD"`
SMTPLocalName *string `json:"SMTP_LOCAL_NAME"`
SenderEmail *string `json:"SENDER_EMAIL"` SenderEmail *string `json:"SENDER_EMAIL"`
JwtType *string `json:"JWT_TYPE"` JwtType *string `json:"JWT_TYPE"`
JwtSecret *string `json:"JWT_SECRET"` JwtSecret *string `json:"JWT_SECRET"`
@@ -417,8 +384,7 @@ type ValidateJWTTokenInput struct {
} }
type ValidateJWTTokenResponse struct { type ValidateJWTTokenResponse struct {
IsValid bool `json:"is_valid"` IsValid bool `json:"is_valid"`
Claims map[string]interface{} `json:"claims"`
} }
type VerificationRequest struct { type VerificationRequest struct {
@@ -439,14 +405,12 @@ type VerificationRequests struct {
} }
type VerifyEmailInput struct { type VerifyEmailInput struct {
Token string `json:"token"` Token string `json:"token"`
State *string `json:"state"`
} }
type VerifyOTPRequest struct { type VerifyOTPRequest struct {
Email string `json:"email"` Email string `json:"email"`
Otp string `json:"otp"` Otp string `json:"otp"`
State *string `json:"state"`
} }
type Webhook struct { type Webhook struct {

View File

@@ -110,7 +110,6 @@ type Env {
SMTP_PORT: String SMTP_PORT: String
SMTP_USERNAME: String SMTP_USERNAME: String
SMTP_PASSWORD: String SMTP_PASSWORD: String
SMTP_LOCAL_NAME: String
SENDER_EMAIL: String SENDER_EMAIL: String
JWT_TYPE: String JWT_TYPE: String
JWT_SECRET: String JWT_SECRET: String
@@ -153,7 +152,6 @@ type Env {
type ValidateJWTTokenResponse { type ValidateJWTTokenResponse {
is_valid: Boolean! is_valid: Boolean!
claims: Map
} }
type GenerateJWTKeysResponse { type GenerateJWTKeysResponse {
@@ -221,7 +219,6 @@ input UpdateEnvInput {
SMTP_PORT: String SMTP_PORT: String
SMTP_USERNAME: String SMTP_USERNAME: String
SMTP_PASSWORD: String SMTP_PASSWORD: String
SMTP_LOCAL_NAME: String
SENDER_EMAIL: String SENDER_EMAIL: String
JWT_TYPE: String JWT_TYPE: String
JWT_SECRET: String JWT_SECRET: String
@@ -269,28 +266,6 @@ input AdminSignupInput {
admin_secret: String! admin_secret: String!
} }
input MobileSignUpInput {
email: String
given_name: String
family_name: String
middle_name: String
nickname: String
gender: String
birthdate: String
phone_number: String!
picture: String
password: String!
confirm_password: String!
roles: [String!]
scope: [String!]
redirect_uri: String
is_multi_factor_auth_enabled: Boolean
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting `c_hash` in id_token
state: String
}
input SignUpInput { input SignUpInput {
email: String! email: String!
given_name: String given_name: String
@@ -307,10 +282,6 @@ input SignUpInput {
scope: [String!] scope: [String!]
redirect_uri: String redirect_uri: String
is_multi_factor_auth_enabled: Boolean is_multi_factor_auth_enabled: Boolean
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting `c_hash` in id_token
state: String
} }
input LoginInput { input LoginInput {
@@ -318,38 +289,15 @@ input LoginInput {
password: String! password: String!
roles: [String!] roles: [String!]
scope: [String!] scope: [String!]
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting `c_hash` in id_token
state: String
}
input MobileLoginInput {
phone_number: String!
password: String!
roles: [String!]
scope: [String!]
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting `c_hash` in id_token
state: String
} }
input VerifyEmailInput { input VerifyEmailInput {
token: String! token: String!
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting `c_hash` in id_token
state: String
} }
input ResendVerifyEmailInput { input ResendVerifyEmailInput {
email: String! email: String!
identifier: String! identifier: String!
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting `c_hash` in id_token
state: String
} }
input UpdateProfileInput { input UpdateProfileInput {
@@ -479,9 +427,7 @@ input AddEmailTemplateRequest {
event_name: String! event_name: String!
subject: String! subject: String!
template: String! template: String!
# Design value is set when editor is used design: String!
# If raw HTML is used design value is set to null
design: String
} }
input UpdateEmailTemplateRequest { input UpdateEmailTemplateRequest {
@@ -489,8 +435,6 @@ input UpdateEmailTemplateRequest {
event_name: String event_name: String
template: String template: String
subject: String subject: String
# Design value is set when editor is used
# If raw HTML is used design value is set to null
design: String design: String
} }
@@ -501,25 +445,15 @@ input DeleteEmailTemplateRequest {
input VerifyOTPRequest { input VerifyOTPRequest {
email: String! email: String!
otp: String! otp: String!
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting `c_hash` in id_token
state: String
} }
input ResendOTPRequest { input ResendOTPRequest {
email: String! email: String!
# state is used for authorization code grant flow
# it is used to get code for an on-going auth process during login
# and use that code for setting `c_hash` in id_token
state: String
} }
type Mutation { type Mutation {
signup(params: SignUpInput!): AuthResponse! signup(params: SignUpInput!): AuthResponse!
mobile_signup(params: MobileSignUpInput): AuthResponse!
login(params: LoginInput!): AuthResponse! login(params: LoginInput!): AuthResponse!
mobile_login(params: MobileLoginInput!): AuthResponse!
magic_link_login(params: MagicLinkLoginInput!): Response! magic_link_login(params: MagicLinkLoginInput!): Response!
logout: Response! logout: Response!
update_profile(params: UpdateProfileInput!): Response! update_profile(params: UpdateProfileInput!): Response!

View File

@@ -16,21 +16,11 @@ func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpInput)
return resolvers.SignupResolver(ctx, params) return resolvers.SignupResolver(ctx, params)
} }
// MobileSignup is the resolver for the mobile_signup field.
func (r *mutationResolver) MobileSignup(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error) {
return resolvers.MobileSignupResolver(ctx, params)
}
// Login is the resolver for the login field. // Login is the resolver for the login field.
func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) { func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) {
return resolvers.LoginResolver(ctx, params) return resolvers.LoginResolver(ctx, params)
} }
// MobileLogin is the resolver for the mobile_login field.
func (r *mutationResolver) MobileLogin(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error) {
return resolvers.MobileLoginResolver(ctx, params)
}
// MagicLinkLogin is the resolver for the magic_link_login field. // MagicLinkLogin is the resolver for the magic_link_login field.
func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) { func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
return resolvers.MagicLinkLoginResolver(ctx, params) return resolvers.MagicLinkLoginResolver(ctx, params)

View File

@@ -30,7 +30,7 @@ func AppHandler() gin.HandlerFunc {
return return
} }
redirectURI := strings.TrimSpace(c.Query("redirect_uri")) redirect_uri := strings.TrimSpace(c.Query("redirect_uri"))
state := strings.TrimSpace(c.Query("state")) state := strings.TrimSpace(c.Query("state"))
scopeString := strings.TrimSpace(c.Query("scope")) scopeString := strings.TrimSpace(c.Query("scope"))
@@ -41,11 +41,11 @@ func AppHandler() gin.HandlerFunc {
scope = strings.Split(scopeString, " ") scope = strings.Split(scopeString, " ")
} }
if redirectURI == "" { if redirect_uri == "" {
redirectURI = hostname + "/app" redirect_uri = hostname + "/app"
} else { } else {
// validate redirect url with allowed origins // validate redirect url with allowed origins
if !validators.IsValidOrigin(redirectURI) { if !validators.IsValidOrigin(redirect_uri) {
log.Debug("Invalid redirect_uri") log.Debug("Invalid redirect_uri")
c.JSON(400, gin.H{"error": "invalid redirect url"}) c.JSON(400, gin.H{"error": "invalid redirect url"})
return return
@@ -75,7 +75,7 @@ func AppHandler() gin.HandlerFunc {
c.HTML(http.StatusOK, "app.tmpl", gin.H{ c.HTML(http.StatusOK, "app.tmpl", gin.H{
"data": map[string]interface{}{ "data": map[string]interface{}{
"authorizerURL": hostname, "authorizerURL": hostname,
"redirectURL": redirectURI, "redirectURL": redirect_uri,
"scope": scope, "scope": scope,
"state": state, "state": state,
"organizationName": orgName, "organizationName": orgName,

View File

@@ -1,41 +1,10 @@
package handlers package handlers
/**
LOGIC TO REMEMBER THE AUTHORIZE FLOW
jargons
`at_hash` -> access_token_hash
`c_hash` -> code_hash
# ResponseType: Code
with /authorize request
- set state [state, code@@challenge]
- add &code to login redirect url
login resolver has optional param state
-if state found in store, split with @@
- if len > 1 -> response type is code and has code + challenge
- set `nonce, code` for createAuthToken request so that `c_hash` can be generated
- do not add `nonce` to id_token in code flow, instead set `c_hash` and `at_hash`
# ResponseType: token / id_token
with /authorize request
- set state [state, nonce]
- add &nonce to login redirect url
login resolver has optional param state
- if state found in store, split with @@
- if len < 1 -> response type is token / id_token and value is nonce
- send received nonce for createAuthToken with empty code value
- set `nonce` and `at_hash` in `id_token`
**/
import ( import (
"fmt"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
@@ -48,15 +17,6 @@ import (
"github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/token"
) )
// Check the flow for generating and verifying codes: https://developer.okta.com/blog/2019/08/22/okta-authjs-pkce#:~:text=PKCE%20works%20by%20having%20the,is%20called%20the%20Code%20Challenge.
// Check following docs for understanding request / response params for various types of requests: https://auth0.com/docs/authenticate/login/oidc-conformant-authentication/oidc-adoption-auth-code-flow
const (
authorizeWebMessageTemplate = "authorize_web_message.tmpl"
authorizeFormPostTemplate = "authorize_form_post.tmpl"
)
// AuthorizeHandler is the handler for the /authorize route // AuthorizeHandler is the handler for the /authorize route
// required params // required params
// ?redirect_uri = redirect url // ?redirect_uri = redirect url
@@ -64,6 +24,8 @@ const (
// state[recommended] = to prevent CSRF attack (for authorizer its compulsory) // state[recommended] = to prevent CSRF attack (for authorizer its compulsory)
// code_challenge = to prevent CSRF attack // code_challenge = to prevent CSRF attack
// code_challenge_method = to prevent CSRF attack [only sh256 is supported] // code_challenge_method = to prevent CSRF attack [only sh256 is supported]
// check the flow for generating and verifying codes: https://developer.okta.com/blog/2019/08/22/okta-authjs-pkce#:~:text=PKCE%20works%20by%20having%20the,is%20called%20the%20Code%20Challenge.
func AuthorizeHandler() gin.HandlerFunc { func AuthorizeHandler() gin.HandlerFunc {
return func(gc *gin.Context) { return func(gc *gin.Context) {
redirectURI := strings.TrimSpace(gc.Query("redirect_uri")) redirectURI := strings.TrimSpace(gc.Query("redirect_uri"))
@@ -72,8 +34,8 @@ func AuthorizeHandler() gin.HandlerFunc {
codeChallenge := strings.TrimSpace(gc.Query("code_challenge")) codeChallenge := strings.TrimSpace(gc.Query("code_challenge"))
scopeString := strings.TrimSpace(gc.Query("scope")) scopeString := strings.TrimSpace(gc.Query("scope"))
clientID := strings.TrimSpace(gc.Query("client_id")) clientID := strings.TrimSpace(gc.Query("client_id"))
template := "authorize.tmpl"
responseMode := strings.TrimSpace(gc.Query("response_mode")) responseMode := strings.TrimSpace(gc.Query("response_mode"))
nonce := strings.TrimSpace(gc.Query("nonce"))
var scope []string var scope []string
if scopeString == "" { if scopeString == "" {
@@ -83,98 +45,177 @@ func AuthorizeHandler() gin.HandlerFunc {
} }
if responseMode == "" { if responseMode == "" {
responseMode = constants.ResponseModeQuery responseMode = "query"
}
if responseMode != "query" && responseMode != "web_message" {
log.Debug("Invalid response_mode: ", responseMode)
gc.JSON(400, gin.H{"error": "invalid response mode"})
} }
if redirectURI == "" { if redirectURI == "" {
redirectURI = "/app" redirectURI = "/app"
} }
isQuery := responseMode == "query"
code := uuid.New().String()
loginURL := "/app?state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + "&code=" + code
if clientID == "" {
if isQuery {
gc.Redirect(http.StatusFound, loginURL)
} else {
log.Debug("Failed to get client_id: ", clientID)
gc.HTML(http.StatusOK, template, gin.H{
"target_origin": redirectURI,
"authorization_response": map[string]interface{}{
"type": "authorization_response",
"response": map[string]string{
"error": "client_id is required",
},
},
})
}
return
}
if client, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); client != clientID || err != nil {
if isQuery {
gc.Redirect(http.StatusFound, loginURL)
} else {
log.Debug("Invalid client_id: ", clientID)
gc.HTML(http.StatusOK, template, gin.H{
"target_origin": redirectURI,
"authorization_response": map[string]interface{}{
"type": "authorization_response",
"response": map[string]string{
"error": "invalid_client_id",
},
},
})
}
return
}
if state == "" {
if isQuery {
gc.Redirect(http.StatusFound, loginURL)
} else {
log.Debug("Failed to get state: ", state)
gc.HTML(http.StatusOK, template, gin.H{
"target_origin": redirectURI,
"authorization_response": map[string]interface{}{
"type": "authorization_response",
"response": map[string]string{
"error": "state is required",
},
},
})
}
return
}
if responseType == "" { if responseType == "" {
responseType = "token" responseType = "token"
} }
if err := validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge); err != nil { isResponseTypeCode := responseType == "code"
log.Debug("invalid authorization request: ", err) isResponseTypeToken := responseType == "token"
gc.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
if !isResponseTypeCode && !isResponseTypeToken {
if isQuery {
gc.Redirect(http.StatusFound, loginURL)
} else {
log.Debug("Invalid response_type: ", responseType)
gc.HTML(http.StatusOK, template, gin.H{
"target_origin": redirectURI,
"authorization_response": map[string]interface{}{
"type": "authorization_response",
"response": map[string]string{
"error": "response_type is invalid",
},
},
})
}
return return
} }
code := uuid.New().String() if isResponseTypeCode {
if nonce == "" { if codeChallenge == "" {
nonce = uuid.New().String() if isQuery {
} gc.Redirect(http.StatusFound, loginURL)
} else {
log := log.WithFields(log.Fields{ log.Debug("Failed to get code_challenge: ", codeChallenge)
"response_mode": responseMode, gc.HTML(http.StatusBadRequest, template, gin.H{
"response_type": responseType, "target_origin": redirectURI,
}) "authorization_response": map[string]interface{}{
"type": "authorization_response",
// TODO add state with timeout "response": map[string]string{
// used for response mode query or fragment "error": "code_challenge is required",
loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI },
if responseType == constants.ResponseTypeCode { },
loginState += "&code=" + code })
if err := memorystore.Provider.SetState(state, code+"@@"+codeChallenge); err != nil { }
log.Debug("Error setting temp code", err) return
}
} else {
loginState += "&nonce=" + nonce
if err := memorystore.Provider.SetState(state, nonce); err != nil {
log.Debug("Error setting temp code", err)
} }
} }
loginURL := "/app?" + loginState
if responseMode == constants.ResponseModeFragment {
loginURL = "/app#" + loginState
}
if responseType == constants.ResponseTypeCode && codeChallenge == "" {
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
"type": "authorization_response",
"response": map[string]interface{}{
"error": "code_challenge_required",
"error_description": "code challenge is required",
},
}, http.StatusOK)
return
}
loginError := map[string]interface{}{
"type": "authorization_response",
"response": map[string]interface{}{
"error": "login_required",
"error_description": "Login is required",
},
}
sessionToken, err := cookie.GetSession(gc) sessionToken, err := cookie.GetSession(gc)
if err != nil { if err != nil {
log.Debug("GetSession failed: ", err) if isQuery {
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) gc.Redirect(http.StatusFound, loginURL)
} else {
gc.HTML(http.StatusOK, template, gin.H{
"target_origin": redirectURI,
"authorization_response": map[string]interface{}{
"type": "authorization_response",
"response": map[string]string{
"error": "login_required",
"error_description": "Login is required",
},
},
})
}
return return
} }
// get session from cookie // get session from cookie
claims, err := token.ValidateBrowserSession(gc, sessionToken) claims, err := token.ValidateBrowserSession(gc, sessionToken)
if err != nil { if err != nil {
log.Debug("ValidateBrowserSession failed: ", err) if isQuery {
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) gc.Redirect(http.StatusFound, loginURL)
} else {
gc.HTML(http.StatusOK, template, gin.H{
"target_origin": redirectURI,
"authorization_response": map[string]interface{}{
"type": "authorization_response",
"response": map[string]string{
"error": "login_required",
"error_description": "Login is required",
},
},
})
}
return return
} }
userID := claims.Subject userID := claims.Subject
user, err := db.Provider.GetUserByID(gc, userID) user, err := db.Provider.GetUserByID(gc, userID)
if err != nil { if err != nil {
log.Debug("GetUserByID failed: ", err) if isQuery {
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ gc.Redirect(http.StatusFound, loginURL)
"type": "authorization_response", } else {
"response": map[string]interface{}{ gc.HTML(http.StatusOK, template, gin.H{
"error": "signup_required", "target_origin": redirectURI,
"error_description": "Sign up required", "authorization_response": map[string]interface{}{
}, "type": "authorization_response",
}, http.StatusOK) "response": map[string]string{
"error": "signup_required",
"error_description": "Sign up required",
},
},
})
}
return return
} }
@@ -183,102 +224,81 @@ func AuthorizeHandler() gin.HandlerFunc {
sessionKey = claims.LoginMethod + ":" + user.ID sessionKey = claims.LoginMethod + ":" + user.ID
} }
// rollover the session for security // if user is logged in
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce) // based on the response type code, generate the response
if responseType == constants.ResponseTypeCode { if isResponseTypeCode {
// rollover the session for security
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
nonce := uuid.New().String()
newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod) newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod)
if err != nil { if err != nil {
log.Debug("CreateSessionToken failed: ", err) if isQuery {
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) gc.Redirect(http.StatusFound, loginURL)
return } else {
} gc.HTML(http.StatusOK, template, gin.H{
"target_origin": redirectURI,
// TODO: add state with timeout "authorization_response": map[string]interface{}{
// if err := memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken); err != nil { "type": "authorization_response",
// log.Debug("SetState failed: ", err) "response": map[string]string{
// handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) "error": "login_required",
// return "error_description": "Login is required",
// } },
},
// TODO: add state with timeout })
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+newSessionToken); err != nil { }
log.Debug("SetState failed: ", err)
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
return
}
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken); err != nil {
log.Debug("SetUserSession failed: ", err)
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
return return
} }
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken)
cookie.SetSession(gc, newSessionToken) cookie.SetSession(gc, newSessionToken)
// in case, response type is code and user is already logged in send the code and state memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken)
// and cookie session will already be rolled over and set gc.HTML(http.StatusOK, template, gin.H{
// gc.HTML(http.StatusOK, authorizeWebMessageTemplate, gin.H{ "target_origin": redirectURI,
// "target_origin": redirectURI, "authorization_response": map[string]interface{}{
// "authorization_response": map[string]interface{}{ "type": "authorization_response",
// "type": "authorization_response", "response": map[string]string{
// "response": map[string]string{ "code": code,
// "code": code, "state": state,
// "state": state, },
// },
// },
// })
params := "code=" + code + "&state=" + state + "&nonce=" + nonce
if responseMode == constants.ResponseModeQuery {
if strings.Contains(redirectURI, "?") {
redirectURI = redirectURI + "&" + params
} else {
redirectURI = redirectURI + "?" + params
}
} else if responseMode == constants.ResponseModeFragment {
if strings.Contains(redirectURI, "#") {
redirectURI = redirectURI + "&" + params
} else {
redirectURI = redirectURI + "#" + params
}
}
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
"type": "authorization_response",
"response": map[string]interface{}{
"code": code,
"state": state,
}, },
}, http.StatusOK) })
return return
} }
if responseType == constants.ResponseTypeToken || responseType == constants.ResponseTypeIDToken { if isResponseTypeToken {
// rollover the session for security // rollover the session for security
authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod, nonce, "") authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod)
if err != nil { if err != nil {
log.Debug("CreateAuthToken failed: ", err) if isQuery {
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) gc.Redirect(http.StatusFound, loginURL)
return } else {
} gc.HTML(http.StatusOK, template, gin.H{
"target_origin": redirectURI,
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+nonce, authToken.FingerPrintHash); err != nil { "authorization_response": map[string]interface{}{
log.Debug("SetUserSession failed: ", err) "type": "authorization_response",
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) "response": map[string]string{
return "error": "login_required",
} "error_description": "Login is required",
},
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce, authToken.AccessToken.Token); err != nil { },
log.Debug("SetUserSession failed: ", err) })
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) }
return return
} }
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
cookie.SetSession(gc, authToken.FingerPrintHash) cookie.SetSession(gc, authToken.FingerPrintHash)
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {
expiresIn = 1
}
// used of query mode // used of query mode
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(authToken.IDToken.ExpiresAt, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&code=" + code
res := map[string]interface{}{ res := map[string]interface{}{
"access_token": authToken.AccessToken.Token, "access_token": authToken.AccessToken.Token,
@@ -286,12 +306,8 @@ func AuthorizeHandler() gin.HandlerFunc {
"state": state, "state": state,
"scope": scope, "scope": scope,
"token_type": "Bearer", "token_type": "Bearer",
"expires_in": authToken.AccessToken.ExpiresAt, "expires_in": expiresIn,
} "code": code,
if nonce != "" {
params += "&nonce=" + nonce
res["nonce"] = nonce
} }
if authToken.RefreshToken != nil { if authToken.RefreshToken != nil {
@@ -300,76 +316,38 @@ func AuthorizeHandler() gin.HandlerFunc {
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
} }
if responseMode == constants.ResponseModeQuery { if isQuery {
if strings.Contains(redirectURI, "?") { if strings.Contains(redirectURI, "?") {
redirectURI = redirectURI + "&" + params gc.Redirect(http.StatusFound, redirectURI+"&"+params)
} else { } else {
redirectURI = redirectURI + "?" + params gc.Redirect(http.StatusFound, redirectURI+"?"+params)
}
} else if responseMode == constants.ResponseModeFragment {
if strings.Contains(redirectURI, "#") {
redirectURI = redirectURI + "&" + params
} else {
redirectURI = redirectURI + "#" + params
} }
} else {
gc.HTML(http.StatusOK, template, gin.H{
"target_origin": redirectURI,
"authorization_response": map[string]interface{}{
"type": "authorization_response",
"response": res,
},
})
} }
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
"type": "authorization_response",
"response": res,
}, http.StatusOK)
return return
} }
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) if isQuery {
} gc.Redirect(http.StatusFound, loginURL)
} } else {
// by default return with error
func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge string) error { gc.HTML(http.StatusOK, template, gin.H{
if strings.TrimSpace(state) == "" { "target_origin": redirectURI,
return fmt.Errorf("invalid state. state is required to prevent csrf attack") "authorization_response": map[string]interface{}{
} "type": "authorization_response",
if responseType != constants.ResponseTypeCode && responseType != constants.ResponseTypeToken && responseType != constants.ResponseTypeIDToken { "response": map[string]string{
return fmt.Errorf("invalid response type %s. 'code' & 'token' are valid response_type", responseMode) "error": "login_required",
} "error_description": "Login is required",
},
if responseMode != constants.ResponseModeQuery && responseMode != constants.ResponseModeWebMessage && responseMode != constants.ResponseModeFragment && responseMode != constants.ResponseModeFormPost { },
return fmt.Errorf("invalid response mode %s. 'query', 'fragment', 'form_post' and 'web_message' are valid response_mode", responseMode) })
} }
if client, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); client != clientID || err != nil {
return fmt.Errorf("invalid client_id %s", clientID)
}
return nil
}
func handleResponse(gc *gin.Context, responseMode, loginURI, redirectURI string, data map[string]interface{}, httpStatusCode int) {
isAuthenticationRequired := false
if _, ok := data["response"].(map[string]interface{})["error"]; ok {
isAuthenticationRequired = true
}
if isAuthenticationRequired && responseMode != constants.ResponseModeWebMessage {
gc.Redirect(http.StatusFound, loginURI)
return
}
switch responseMode {
case constants.ResponseModeQuery, constants.ResponseModeFragment:
gc.Redirect(http.StatusFound, redirectURI)
return
case constants.ResponseModeWebMessage:
gc.HTML(httpStatusCode, authorizeWebMessageTemplate, gin.H{
"target_origin": redirectURI,
"authorization_response": data,
})
return
case constants.ResponseModeFormPost:
gc.HTML(httpStatusCode, authorizeFormPostTemplate, gin.H{
"target_origin": redirectURI,
"authorization_response": data["response"],
})
return
} }
} }

View File

@@ -5,7 +5,7 @@ import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io/ioutil"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
@@ -13,7 +13,6 @@ import (
"github.com/coreos/go-oidc/v3/oidc" "github.com/coreos/go-oidc/v3/oidc"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"golang.org/x/oauth2" "golang.org/x/oauth2"
@@ -56,20 +55,20 @@ func OAuthCallbackHandler() gin.HandlerFunc {
scopes := strings.Split(sessionSplit[3], ",") scopes := strings.Split(sessionSplit[3], ",")
user := models.User{} user := models.User{}
oauthCode := ctx.Request.FormValue("code") code := ctx.Request.FormValue("code")
switch provider { switch provider {
case constants.AuthRecipeMethodGoogle: case constants.AuthRecipeMethodGoogle:
user, err = processGoogleUserInfo(oauthCode) user, err = processGoogleUserInfo(code)
case constants.AuthRecipeMethodGithub: case constants.AuthRecipeMethodGithub:
user, err = processGithubUserInfo(oauthCode) user, err = processGithubUserInfo(code)
case constants.AuthRecipeMethodFacebook: case constants.AuthRecipeMethodFacebook:
user, err = processFacebookUserInfo(oauthCode) user, err = processFacebookUserInfo(code)
case constants.AuthRecipeMethodLinkedIn: case constants.AuthRecipeMethodLinkedIn:
user, err = processLinkedInUserInfo(oauthCode) user, err = processLinkedInUserInfo(code)
case constants.AuthRecipeMethodApple: case constants.AuthRecipeMethodApple:
user, err = processAppleUserInfo(oauthCode) user, err = processAppleUserInfo(code)
case constants.AuthRecipeMethodTwitter: case constants.AuthRecipeMethodTwitter:
user, err = processTwitterUserInfo(oauthCode, sessionState) user, err = processTwitterUserInfo(code, sessionState)
default: default:
log.Info("Invalid oauth provider") log.Info("Invalid oauth provider")
err = fmt.Errorf(`invalid oauth provider`) err = fmt.Errorf(`invalid oauth provider`)
@@ -197,53 +196,18 @@ func OAuthCallbackHandler() gin.HandlerFunc {
} }
} }
// TODO authToken, err := token.CreateAuthToken(ctx, user, inputRoles, scopes, provider)
// use stateValue to get code / nonce
// add code / nonce to id_token
code := ""
codeChallenge := ""
nonce := ""
if stateValue != "" {
// Get state from store
authorizeState, _ := memorystore.Provider.GetState(stateValue)
if authorizeState != "" {
authorizeStateSplit := strings.Split(authorizeState, "@@")
if len(authorizeStateSplit) > 1 {
code = authorizeStateSplit[0]
codeChallenge = authorizeStateSplit[1]
} else {
nonce = authorizeState
}
go memorystore.Provider.RemoveState(stateValue)
}
}
if nonce == "" {
nonce = uuid.New().String()
}
authToken, err := token.CreateAuthToken(ctx, user, inputRoles, scopes, provider, nonce, code)
if err != nil { if err != nil {
log.Debug("Failed to create auth token: ", err) log.Debug("Failed to create auth token: ", err)
ctx.JSON(500, gin.H{"error": err.Error()}) ctx.JSON(500, gin.H{"error": err.Error()})
} }
// Code challenge could be optional if PKCE flow is not used
if code != "" {
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
log.Debug("SetState failed: ", err)
ctx.JSON(500, gin.H{"error": err.Error()})
}
}
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 { if expiresIn <= 0 {
expiresIn = 1 expiresIn = 1
} }
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token + "&nonce=" + nonce params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token
if code != "" {
params += "&code=" + code
}
sessionKey := provider + ":" + user.ID sessionKey := provider + ":" + user.ID
cookie.SetSession(ctx, authToken.FingerPrintHash) cookie.SetSession(ctx, authToken.FingerPrintHash)
@@ -251,7 +215,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
if authToken.RefreshToken != nil { if authToken.RefreshToken != nil {
params += `&refresh_token=` + authToken.RefreshToken.Token params = params + `&refresh_token=` + authToken.RefreshToken.Token
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
} }
@@ -312,7 +276,7 @@ func processGoogleUserInfo(code string) (models.User, error) {
func processGithubUserInfo(code string) (models.User, error) { func processGithubUserInfo(code string) (models.User, error) {
user := models.User{} user := models.User{}
oauth2Token, err := oauth.OAuthProviders.GithubConfig.Exchange(context.TODO(), code) oauth2Token, err := oauth.OAuthProviders.GithubConfig.Exchange(oauth2.NoContext, code)
if err != nil { if err != nil {
log.Debug("Failed to exchange code for token: ", err) log.Debug("Failed to exchange code for token: ", err)
return user, fmt.Errorf("invalid github exchange code: %s", err.Error()) return user, fmt.Errorf("invalid github exchange code: %s", err.Error())
@@ -334,7 +298,7 @@ func processGithubUserInfo(code string) (models.User, error) {
} }
defer response.Body.Close() defer response.Body.Close()
body, err := io.ReadAll(response.Body) body, err := ioutil.ReadAll(response.Body)
if err != nil { if err != nil {
log.Debug("Failed to read github user info response body: ", err) log.Debug("Failed to read github user info response body: ", err)
return user, fmt.Errorf("failed to read github response body: %s", err.Error()) return user, fmt.Errorf("failed to read github response body: %s", err.Error())
@@ -383,7 +347,7 @@ func processGithubUserInfo(code string) (models.User, error) {
} }
defer response.Body.Close() defer response.Body.Close()
body, err := io.ReadAll(response.Body) body, err := ioutil.ReadAll(response.Body)
if err != nil { if err != nil {
log.Debug("Failed to read github user email response body: ", err) log.Debug("Failed to read github user email response body: ", err)
return user, fmt.Errorf("failed to read github response body: %s", err.Error()) return user, fmt.Errorf("failed to read github response body: %s", err.Error())
@@ -419,7 +383,7 @@ func processGithubUserInfo(code string) (models.User, error) {
func processFacebookUserInfo(code string) (models.User, error) { func processFacebookUserInfo(code string) (models.User, error) {
user := models.User{} user := models.User{}
oauth2Token, err := oauth.OAuthProviders.FacebookConfig.Exchange(context.TODO(), code) oauth2Token, err := oauth.OAuthProviders.FacebookConfig.Exchange(oauth2.NoContext, code)
if err != nil { if err != nil {
log.Debug("Invalid facebook exchange code: ", err) log.Debug("Invalid facebook exchange code: ", err)
return user, fmt.Errorf("invalid facebook exchange code: %s", err.Error()) return user, fmt.Errorf("invalid facebook exchange code: %s", err.Error())
@@ -438,7 +402,7 @@ func processFacebookUserInfo(code string) (models.User, error) {
} }
defer response.Body.Close() defer response.Body.Close()
body, err := io.ReadAll(response.Body) body, err := ioutil.ReadAll(response.Body)
if err != nil { if err != nil {
log.Debug("Failed to read facebook response: ", err) log.Debug("Failed to read facebook response: ", err)
return user, fmt.Errorf("failed to read facebook response body: %s", err.Error()) return user, fmt.Errorf("failed to read facebook response body: %s", err.Error())
@@ -470,7 +434,7 @@ func processFacebookUserInfo(code string) (models.User, error) {
func processLinkedInUserInfo(code string) (models.User, error) { func processLinkedInUserInfo(code string) (models.User, error) {
user := models.User{} user := models.User{}
oauth2Token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(context.TODO(), code) oauth2Token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(oauth2.NoContext, code)
if err != nil { if err != nil {
log.Debug("Failed to exchange code for token: ", err) log.Debug("Failed to exchange code for token: ", err)
return user, fmt.Errorf("invalid linkedin exchange code: %s", err.Error()) return user, fmt.Errorf("invalid linkedin exchange code: %s", err.Error())
@@ -493,7 +457,7 @@ func processLinkedInUserInfo(code string) (models.User, error) {
} }
defer response.Body.Close() defer response.Body.Close()
body, err := io.ReadAll(response.Body) body, err := ioutil.ReadAll(response.Body)
if err != nil { if err != nil {
log.Debug("Failed to read linkedin user info response body: ", err) log.Debug("Failed to read linkedin user info response body: ", err)
return user, fmt.Errorf("failed to read linkedin response body: %s", err.Error()) return user, fmt.Errorf("failed to read linkedin response body: %s", err.Error())
@@ -523,7 +487,7 @@ func processLinkedInUserInfo(code string) (models.User, error) {
} }
defer response.Body.Close() defer response.Body.Close()
body, err = io.ReadAll(response.Body) body, err = ioutil.ReadAll(response.Body)
if err != nil { if err != nil {
log.Debug("Failed to read linkedin email info response body: ", err) log.Debug("Failed to read linkedin email info response body: ", err)
return user, fmt.Errorf("failed to read linkedin email response body: %s", err.Error()) return user, fmt.Errorf("failed to read linkedin email response body: %s", err.Error())
@@ -552,7 +516,7 @@ func processLinkedInUserInfo(code string) (models.User, error) {
func processAppleUserInfo(code string) (models.User, error) { func processAppleUserInfo(code string) (models.User, error) {
user := models.User{} user := models.User{}
oauth2Token, err := oauth.OAuthProviders.AppleConfig.Exchange(context.TODO(), code) oauth2Token, err := oauth.OAuthProviders.AppleConfig.Exchange(oauth2.NoContext, code)
if err != nil { if err != nil {
log.Debug("Failed to exchange code for token: ", err) log.Debug("Failed to exchange code for token: ", err)
return user, fmt.Errorf("invalid apple exchange code: %s", err.Error()) return user, fmt.Errorf("invalid apple exchange code: %s", err.Error())
@@ -605,7 +569,7 @@ func processAppleUserInfo(code string) (models.User, error) {
func processTwitterUserInfo(code, verifier string) (models.User, error) { func processTwitterUserInfo(code, verifier string) (models.User, error) {
user := models.User{} user := models.User{}
oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(context.TODO(), code, oauth2.SetAuthURLParam("code_verifier", verifier)) oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(oauth2.NoContext, code, oauth2.SetAuthURLParam("code_verifier", verifier))
if err != nil { if err != nil {
log.Debug("Failed to exchange code for token: ", err) log.Debug("Failed to exchange code for token: ", err)
return user, fmt.Errorf("invalid twitter exchange code: %s", err.Error()) return user, fmt.Errorf("invalid twitter exchange code: %s", err.Error())
@@ -628,7 +592,7 @@ func processTwitterUserInfo(code, verifier string) (models.User, error) {
} }
defer response.Body.Close() defer response.Body.Close()
body, err := io.ReadAll(response.Body) body, err := ioutil.ReadAll(response.Body)
if err != nil { if err != nil {
log.Debug("Failed to read Twitter user info response body: ", err) log.Debug("Failed to read Twitter user info response body: ", err)
return user, fmt.Errorf("failed to read Twitter response body: %s", err.Error()) return user, fmt.Errorf("failed to read Twitter response body: %s", err.Error())

View File

@@ -22,7 +22,7 @@ func OpenIDConfigurationHandler() gin.HandlerFunc {
"jwks_uri": issuer + "/.well-known/jwks.json", "jwks_uri": issuer + "/.well-known/jwks.json",
"response_types_supported": []string{"code", "token", "id_token"}, "response_types_supported": []string{"code", "token", "id_token"},
"scopes_supported": []string{"openid", "email", "profile", "email_verified", "given_name", "family_name", "nick_name", "picture"}, "scopes_supported": []string{"openid", "email", "profile", "email_verified", "given_name", "family_name", "nick_name", "picture"},
"response_modes_supported": []string{"query", "fragment", "form_post", "web_message"}, "response_modes_supported": []string{"query", "fragment", "form_post"},
"id_token_signing_alg_values_supported": []string{jwtType}, "id_token_signing_alg_values_supported": []string{jwtType},
"claims_supported": []string{"aud", "exp", "iss", "iat", "sub", "given_name", "family_name", "middle_name", "nickname", "preferred_username", "picture", "email", "email_verified", "roles", "role", "gender", "birthdate", "phone_number", "phone_number_verified", "nonce", "updated_at", "created_at", "revoked_timestamp", "login_method", "signup_methods", "token_type"}, "claims_supported": []string{"aud", "exp", "iss", "iat", "sub", "given_name", "family_name", "middle_name", "nickname", "preferred_username", "picture", "email", "email_verified", "roles", "role", "gender", "birthdate", "phone_number", "phone_number_verified", "nonce", "updated_at", "created_at", "revoked_timestamp", "login_method", "signup_methods", "token_type"},
}) })

View File

@@ -8,7 +8,6 @@ import (
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
@@ -18,22 +17,12 @@ import (
"github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/token"
) )
type RequestBody struct {
CodeVerifier string `form:"code_verifier" json:"code_verifier"`
Code string `form:"code" json:"code"`
ClientID string `form:"client_id" json:"client_id"`
ClientSecret string `form:"client_secret" json:"client_secret"`
GrantType string `form:"grant_type" json:"grant_type"`
RefreshToken string `form:"refresh_token" json:"refresh_token"`
RedirectURI string `form:"redirect_uri" json:"redirect_uri"`
}
// TokenHandler to handle /oauth/token requests // TokenHandler to handle /oauth/token requests
// grant type required // grant type required
func TokenHandler() gin.HandlerFunc { func TokenHandler() gin.HandlerFunc {
return func(gc *gin.Context) { return func(gc *gin.Context) {
var reqBody RequestBody var reqBody map[string]string
if err := gc.Bind(&reqBody); err != nil { if err := gc.BindJSON(&reqBody); err != nil {
log.Debug("Error binding JSON: ", err) log.Debug("Error binding JSON: ", err)
gc.JSON(http.StatusBadRequest, gin.H{ gc.JSON(http.StatusBadRequest, gin.H{
"error": "error_binding_json", "error": "error_binding_json",
@@ -42,12 +31,11 @@ func TokenHandler() gin.HandlerFunc {
return return
} }
codeVerifier := strings.TrimSpace(reqBody.CodeVerifier) codeVerifier := strings.TrimSpace(reqBody["code_verifier"])
code := strings.TrimSpace(reqBody.Code) code := strings.TrimSpace(reqBody["code"])
clientID := strings.TrimSpace(reqBody.ClientID) clientID := strings.TrimSpace(reqBody["client_id"])
grantType := strings.TrimSpace(reqBody.GrantType) grantType := strings.TrimSpace(reqBody["grant_type"])
refreshToken := strings.TrimSpace(reqBody.RefreshToken) refreshToken := strings.TrimSpace(reqBody["refresh_token"])
clientSecret := strings.TrimSpace(reqBody.ClientSecret)
if grantType == "" { if grantType == "" {
grantType = "authorization_code" grantType = "authorization_code"
@@ -64,12 +52,6 @@ func TokenHandler() gin.HandlerFunc {
}) })
} }
// check if clientID & clientSecret are present as part of
// authorization header with basic auth
if clientID == "" && clientSecret == "" {
clientID, clientSecret, _ = gc.Request.BasicAuth()
}
if clientID == "" { if clientID == "" {
log.Debug("Client ID is empty") log.Debug("Client ID is empty")
gc.JSON(http.StatusBadRequest, gin.H{ gc.JSON(http.StatusBadRequest, gin.H{
@@ -94,6 +76,15 @@ func TokenHandler() gin.HandlerFunc {
sessionKey := "" sessionKey := ""
if isAuthorizationCodeGrant { if isAuthorizationCodeGrant {
if codeVerifier == "" {
log.Debug("Code verifier is empty")
gc.JSON(http.StatusBadRequest, gin.H{
"error": "invalid_code_verifier",
"error_description": "The code verifier is required",
})
return
}
if code == "" { if code == "" {
log.Debug("Code is empty") log.Debug("Code is empty")
gc.JSON(http.StatusBadRequest, gin.H{ gc.JSON(http.StatusBadRequest, gin.H{
@@ -103,53 +94,33 @@ func TokenHandler() gin.HandlerFunc {
return return
} }
if codeVerifier == "" && clientSecret == "" { hash := sha256.New()
gc.JSON(http.StatusBadRequest, gin.H{ hash.Write([]byte(codeVerifier))
"error": "invalid_dat", encryptedCode := strings.ReplaceAll(base64.URLEncoding.EncodeToString(hash.Sum(nil)), "+", "-")
"error_description": "The code verifier or client secret is required", encryptedCode = strings.ReplaceAll(encryptedCode, "/", "_")
}) encryptedCode = strings.ReplaceAll(encryptedCode, "=", "")
return sessionData, err := memorystore.Provider.GetState(encryptedCode)
}
// Get state
sessionData, err := memorystore.Provider.GetState(code)
if sessionData == "" || err != nil { if sessionData == "" || err != nil {
log.Debug("Session data is empty") log.Debug("Session data is empty")
gc.JSON(http.StatusBadRequest, gin.H{ gc.JSON(http.StatusBadRequest, gin.H{
"error": "invalid_code", "error": "invalid_code_verifier",
"error_description": "The code is invalid", "error_description": "The code verifier is invalid",
}) })
return return
} }
// [0] -> code_challenge go memorystore.Provider.RemoveState(encryptedCode)
// [1] -> session cookie // split session data
sessionDataSplit := strings.Split(sessionData, "@@") // it contains code@sessiontoken
sessionDataSplit := strings.Split(sessionData, "@")
go memorystore.Provider.RemoveState(code) if sessionDataSplit[0] != code {
log.Debug("Invalid code verifier. Unable to split session data")
if codeVerifier != "" { gc.JSON(http.StatusBadRequest, gin.H{
hash := sha256.New() "error": "invalid_code_verifier",
hash.Write([]byte(codeVerifier)) "error_description": "The code verifier is invalid",
encryptedCode := strings.ReplaceAll(base64.RawURLEncoding.EncodeToString(hash.Sum(nil)), "+", "-") })
encryptedCode = strings.ReplaceAll(encryptedCode, "/", "_") return
encryptedCode = strings.ReplaceAll(encryptedCode, "=", "")
if encryptedCode != sessionDataSplit[0] {
gc.JSON(http.StatusBadRequest, gin.H{
"error": "invalid_code_verifier",
"error_description": "The code verifier is invalid",
})
return
}
} else {
if clientHash, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientSecret); clientSecret != clientHash || err != nil {
log.Debug("Client Secret is invalid: ", clientID)
gc.JSON(http.StatusBadRequest, gin.H{
"error": "invalid_client_secret",
"error_description": "The client secret is invalid",
})
return
}
} }
// validate session // validate session
@@ -175,7 +146,6 @@ func TokenHandler() gin.HandlerFunc {
} }
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce) go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
} else { } else {
// validate refresh token // validate refresh token
if refreshToken == "" { if refreshToken == "" {
@@ -184,7 +154,6 @@ func TokenHandler() gin.HandlerFunc {
"error": "invalid_refresh_token", "error": "invalid_refresh_token",
"error_description": "The refresh token is invalid", "error_description": "The refresh token is invalid",
}) })
return
} }
claims, err := token.ValidateRefreshToken(gc, refreshToken) claims, err := token.ValidateRefreshToken(gc, refreshToken)
@@ -194,10 +163,9 @@ func TokenHandler() gin.HandlerFunc {
"error": "unauthorized", "error": "unauthorized",
"error_description": err.Error(), "error_description": err.Error(),
}) })
return
} }
userID = claims["sub"].(string) userID = claims["sub"].(string)
claimLoginMethod := claims["login_method"] loginMethod := claims["login_method"]
rolesInterface := claims["roles"].([]interface{}) rolesInterface := claims["roles"].([]interface{})
scopeInterface := claims["scope"].([]interface{}) scopeInterface := claims["scope"].([]interface{})
for _, v := range rolesInterface { for _, v := range rolesInterface {
@@ -208,11 +176,9 @@ func TokenHandler() gin.HandlerFunc {
} }
sessionKey = userID sessionKey = userID
if claimLoginMethod != nil && claimLoginMethod != "" { if loginMethod != nil && loginMethod != "" {
sessionKey = claimLoginMethod.(string) + ":" + sessionKey sessionKey = loginMethod.(string) + ":" + sessionKey
loginMethod = claimLoginMethod.(string)
} }
// remove older refresh token and rotate it for security // remove older refresh token and rotate it for security
go memorystore.Provider.DeleteUserSession(sessionKey, claims["nonce"].(string)) go memorystore.Provider.DeleteUserSession(sessionKey, claims["nonce"].(string))
} }
@@ -236,8 +202,7 @@ func TokenHandler() gin.HandlerFunc {
return return
} }
nonce := uuid.New().String() + "@@" + code authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod)
authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod, nonce, code)
if err != nil { if err != nil {
log.Debug("Error creating auth token: ", err) log.Debug("Error creating auth token: ", err)
gc.JSON(http.StatusUnauthorized, gin.H{ gc.JSON(http.StatusUnauthorized, gin.H{
@@ -246,7 +211,6 @@ func TokenHandler() gin.HandlerFunc {
}) })
return return
} }
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
cookie.SetSession(gc, authToken.FingerPrintHash) cookie.SetSession(gc, authToken.FingerPrintHash)

View File

@@ -7,7 +7,6 @@ import (
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
@@ -99,30 +98,7 @@ func VerifyEmailHandler() gin.HandlerFunc {
if verificationRequest.Identifier == constants.VerificationTypeMagicLinkLogin { if verificationRequest.Identifier == constants.VerificationTypeMagicLinkLogin {
loginMethod = constants.AuthRecipeMethodMagicLinkLogin loginMethod = constants.AuthRecipeMethodMagicLinkLogin
} }
authToken, err := token.CreateAuthToken(c, user, roles, scope, loginMethod)
code := ""
// Not required as /oauth/token cannot be resumed from other tab
// codeChallenge := ""
nonce := ""
if state != "" {
// Get state from store
authorizeState, _ := memorystore.Provider.GetState(state)
if authorizeState != "" {
authorizeStateSplit := strings.Split(authorizeState, "@@")
if len(authorizeStateSplit) > 1 {
code = authorizeStateSplit[0]
// Not required as /oauth/token cannot be resumed from other tab
// codeChallenge = authorizeStateSplit[1]
} else {
nonce = authorizeState
}
go memorystore.Provider.RemoveState(state)
}
}
if nonce == "" {
nonce = uuid.New().String()
}
authToken, err := token.CreateAuthToken(c, user, roles, scope, loginMethod, nonce, code)
if err != nil { if err != nil {
log.Debug("Error creating auth token: ", err) log.Debug("Error creating auth token: ", err)
errorRes["error_description"] = err.Error() errorRes["error_description"] = err.Error()
@@ -130,27 +106,12 @@ func VerifyEmailHandler() gin.HandlerFunc {
return return
} }
// Code challenge could be optional if PKCE flow is not used
// Not required as /oauth/token cannot be resumed from other tab
// if code != "" {
// if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
// log.Debug("Error setting code state ", err)
// errorRes["error_description"] = err.Error()
// c.JSON(500, errorRes)
// return
// }
// }
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 { if expiresIn <= 0 {
expiresIn = 1 expiresIn = 1
} }
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&nonce=" + nonce params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token
if code != "" {
params += "&code=" + code
}
sessionKey := loginMethod + ":" + user.ID sessionKey := loginMethod + ":" + user.ID
cookie.SetSession(c, authToken.FingerPrintHash) cookie.SetSession(c, authToken.FingerPrintHash)

View File

@@ -1,61 +0,0 @@
package logs
import (
"os"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
)
// LogUTCFormatter hels in setting UTC time format for the logs
type LogUTCFormatter struct {
log.Formatter
}
// Format helps fomratting time to UTC
func (u LogUTCFormatter) Format(e *log.Entry) ([]byte, error) {
e.Time = e.Time.UTC()
return u.Formatter.Format(e)
}
func InitLog(cliLogLevel string) *log.Logger {
// log instance for gin server
log := logrus.New()
log.SetFormatter(LogUTCFormatter{&logrus.JSONFormatter{}})
if cliLogLevel == "" {
cliLogLevel = os.Getenv("LOG_LEVEL")
}
var logLevel logrus.Level
switch cliLogLevel {
case "debug":
logLevel = logrus.DebugLevel
case "info":
logLevel = logrus.InfoLevel
case "warn":
logLevel = logrus.WarnLevel
case "error":
logLevel = logrus.ErrorLevel
case "fatal":
logLevel = logrus.FatalLevel
case "panic":
logLevel = logrus.PanicLevel
default:
logLevel = logrus.InfoLevel
}
// set log level globally
logrus.SetLevel(logLevel)
// set log level for go-gin middleware
log.SetLevel(logLevel)
// show file path in log for debug or other log levels.
if logLevel != logrus.InfoLevel {
logrus.SetReportCaller(true)
log.SetReportCaller(true)
}
return log
}

View File

@@ -3,42 +3,81 @@ package main
import ( import (
"flag" "flag"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/cli" "github.com/authorizerdev/authorizer/server/cli"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/env" "github.com/authorizerdev/authorizer/server/env"
"github.com/authorizerdev/authorizer/server/logs"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/oauth" "github.com/authorizerdev/authorizer/server/oauth"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/authorizerdev/authorizer/server/routes" "github.com/authorizerdev/authorizer/server/routes"
"github.com/sirupsen/logrus"
) )
// VERSION is used to define the version of authorizer from build tags
var VERSION string var VERSION string
type LogUTCFormatter struct {
log.Formatter
}
func (u LogUTCFormatter) Format(e *log.Entry) ([]byte, error) {
e.Time = e.Time.UTC()
return u.Formatter.Format(e)
}
func main() { func main() {
cli.ARG_DB_URL = flag.String("database_url", "", "Database connection string") cli.ARG_DB_URL = flag.String("database_url", "", "Database connection string")
cli.ARG_DB_TYPE = flag.String("database_type", "", "Database type, possible values are postgres,mysql,sqlite") cli.ARG_DB_TYPE = flag.String("database_type", "", "Database type, possible values are postgres,mysql,sqlite")
cli.ARG_ENV_FILE = flag.String("env_file", "", "Env file path") cli.ARG_ENV_FILE = flag.String("env_file", "", "Env file path")
cli.ARG_LOG_LEVEL = flag.String("log_level", "", "Log level, possible values are debug,info,warn,error,fatal,panic") cli.ARG_LOG_LEVEL = flag.String("log_level", "info", "Log level, possible values are debug,info,warn,error,fatal,panic")
cli.ARG_REDIS_URL = flag.String("redis_url", "", "Redis connection string") cli.ARG_REDIS_URL = flag.String("redis_url", "", "Redis connection string")
flag.Parse() flag.Parse()
// global log level // global log level
logrus.SetFormatter(logs.LogUTCFormatter{&logrus.JSONFormatter{}}) logrus.SetFormatter(LogUTCFormatter{&logrus.JSONFormatter{}})
// log instance for gin server
log := logrus.New()
log.SetFormatter(LogUTCFormatter{&logrus.JSONFormatter{}})
var logLevel logrus.Level
switch *cli.ARG_LOG_LEVEL {
case "debug":
logLevel = logrus.DebugLevel
case "info":
logLevel = logrus.InfoLevel
case "warn":
logLevel = logrus.WarnLevel
case "error":
logLevel = logrus.ErrorLevel
case "fatal":
logLevel = logrus.FatalLevel
case "panic":
logLevel = logrus.PanicLevel
default:
logLevel = logrus.InfoLevel
}
// set log level globally
logrus.SetLevel(logLevel)
// set log level for go-gin middleware
log.SetLevel(logLevel)
// show file path in log for debug or other log levels.
if logLevel != logrus.InfoLevel {
logrus.SetReportCaller(true)
log.SetReportCaller(true)
}
constants.VERSION = VERSION constants.VERSION = VERSION
// initialize required envs (mainly db, env file path and redis) // initialize required envs (mainly db, env file path and redis)
err := memorystore.InitRequiredEnv() err := memorystore.InitRequiredEnv()
if err != nil { if err != nil {
logrus.Fatal("Error while initializing required envs: ", err) log.Fatal("Error while initializing required envs: ", err)
} }
log := logs.InitLog(refs.StringValue(cli.ARG_LOG_LEVEL))
// initialize memory store // initialize memory store
err = memorystore.InitMemStore() err = memorystore.InitMemStore()
if err != nil { if err != nil {

View File

@@ -26,7 +26,6 @@ func InitMemStore() error {
// boolean envs // boolean envs
constants.EnvKeyDisableBasicAuthentication: false, constants.EnvKeyDisableBasicAuthentication: false,
constants.EnvKeyDisableMobileBasicAuthentication: false,
constants.EnvKeyDisableMagicLinkLogin: false, constants.EnvKeyDisableMagicLinkLogin: false,
constants.EnvKeyDisableEmailVerification: false, constants.EnvKeyDisableEmailVerification: false,
constants.EnvKeyDisableLoginPage: false, constants.EnvKeyDisableLoginPage: false,
@@ -58,7 +57,7 @@ func InitMemStore() error {
} }
redisURL := requiredEnvs.RedisURL redisURL := requiredEnvs.RedisURL
if redisURL != "" && !requiredEnvs.DisableRedisForEnv { if redisURL != "" && !requiredEnvs.disableRedisForEnv {
log.Info("Initializing Redis memory store") log.Info("Initializing Redis memory store")
Provider, err = redis.NewRedisProvider(redisURL) Provider, err = redis.NewRedisProvider(redisURL)
if err != nil { if err != nil {

View File

@@ -161,7 +161,7 @@ func (c *provider) GetEnvStore() (map[string]interface{}, error) {
return nil, err return nil, err
} }
for key, value := range data { for key, value := range data {
if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableMobileBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled || key == constants.EnvKeyEnforceMultiFactorAuthentication || key == constants.EnvKeyDisableMultiFactorAuthentication || key == constants.EnvKeyAppCookieSecure || key == constants.EnvKeyAdminCookieSecure { if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled || key == constants.EnvKeyEnforceMultiFactorAuthentication || key == constants.EnvKeyDisableMultiFactorAuthentication || key == constants.EnvKeyAppCookieSecure || key == constants.EnvKeyAdminCookieSecure {
boolValue, err := strconv.ParseBool(value) boolValue, err := strconv.ParseBool(value)
if err != nil { if err != nil {
return res, err return res, err

View File

@@ -27,11 +27,7 @@ type RequiredEnv struct {
DatabaseCertKey string `json:"DATABASE_CERT_KEY"` DatabaseCertKey string `json:"DATABASE_CERT_KEY"`
DatabaseCACert string `json:"DATABASE_CA_CERT"` DatabaseCACert string `json:"DATABASE_CA_CERT"`
RedisURL string `json:"REDIS_URL"` RedisURL string `json:"REDIS_URL"`
DisableRedisForEnv bool `json:"DISABLE_REDIS_FOR_ENV"` disableRedisForEnv bool `json:"DISABLE_REDIS_FOR_ENV"`
// AWS Related Envs
AwsRegion string `json:"AWS_REGION"`
AwsAccessKeyID string `json:"AWS_ACCESS_KEY_ID"`
AwsSecretAccessKey string `json:"AWS_SECRET_ACCESS_KEY"`
} }
// RequiredEnvObj is a simple in-memory store for sessions. // RequiredEnvObj is a simple in-memory store for sessions.
@@ -57,8 +53,7 @@ func (r *RequiredEnvStore) SetRequiredEnv(requiredEnv RequiredEnv) {
var RequiredEnvStoreObj *RequiredEnvStore var RequiredEnvStoreObj *RequiredEnvStore
// InitRequiredEnv to initialize EnvData and throw error if required env are not present // InitRequiredEnv to initialize EnvData and through error if required env are not present
// This includes env that only configurable via env vars and not the ui
func InitRequiredEnv() error { func InitRequiredEnv() error {
envPath := os.Getenv(constants.EnvKeyEnvPath) envPath := os.Getenv(constants.EnvKeyEnvPath)
@@ -90,9 +85,6 @@ func InitRequiredEnv() error {
dbCACert := os.Getenv(constants.EnvKeyDatabaseCACert) dbCACert := os.Getenv(constants.EnvKeyDatabaseCACert)
redisURL := os.Getenv(constants.EnvKeyRedisURL) redisURL := os.Getenv(constants.EnvKeyRedisURL)
disableRedisForEnv := os.Getenv(constants.EnvKeyDisableRedisForEnv) == "true" disableRedisForEnv := os.Getenv(constants.EnvKeyDisableRedisForEnv) == "true"
awsRegion := os.Getenv(constants.EnvAwsRegion)
awsAccessKeyID := os.Getenv(constants.EnvAwsAccessKeyID)
awsSecretAccessKey := os.Getenv(constants.EnvAwsSecretAccessKey)
if strings.TrimSpace(redisURL) == "" { if strings.TrimSpace(redisURL) == "" {
if cli.ARG_REDIS_URL != nil && *cli.ARG_REDIS_URL != "" { if cli.ARG_REDIS_URL != nil && *cli.ARG_REDIS_URL != "" {
@@ -121,8 +113,7 @@ func InitRequiredEnv() error {
dbURL = strings.TrimSpace(*cli.ARG_DB_URL) dbURL = strings.TrimSpace(*cli.ARG_DB_URL)
} }
// In dynamoDB these field are not always mandatory if dbURL == "" && dbPort == "" && dbHost == "" && dbUsername == "" && dbPassword == "" {
if dbType != constants.DbTypeDynamoDB && dbURL == "" && dbPort == "" && dbHost == "" && dbUsername == "" && dbPassword == "" {
log.Debug("DATABASE_URL is not set") log.Debug("DATABASE_URL is not set")
return errors.New("invalid database url. DATABASE_URL is required") return errors.New("invalid database url. DATABASE_URL is required")
} }
@@ -147,10 +138,7 @@ func InitRequiredEnv() error {
DatabaseCertKey: dbCertKey, DatabaseCertKey: dbCertKey,
DatabaseCACert: dbCACert, DatabaseCACert: dbCACert,
RedisURL: redisURL, RedisURL: redisURL,
DisableRedisForEnv: disableRedisForEnv, disableRedisForEnv: disableRedisForEnv,
AwsRegion: awsRegion,
AwsAccessKeyID: awsAccessKeyID,
AwsSecretAccessKey: awsSecretAccessKey,
} }
RequiredEnvStoreObj = &RequiredEnvStore{ RequiredEnvStoreObj = &RequiredEnvStore{

View File

@@ -9,6 +9,7 @@ import (
func CORSMiddleware() gin.HandlerFunc { func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
origin := c.Request.Header.Get("Origin") origin := c.Request.Header.Get("Origin")
if validators.IsValidOrigin(origin) { if validators.IsValidOrigin(origin) {
c.Writer.Header().Set("Access-Control-Allow-Origin", origin) c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
} }

View File

@@ -20,12 +20,12 @@ func GetHost(c *gin.Context) string {
authorizerURL = "" authorizerURL = ""
} }
if authorizerURL != "" { if authorizerURL != "" {
return strings.TrimSuffix(authorizerURL, "/") return authorizerURL
} }
authorizerURL = c.Request.Header.Get("X-Authorizer-URL") authorizerURL = c.Request.Header.Get("X-Authorizer-URL")
if authorizerURL != "" { if authorizerURL != "" {
return strings.TrimSuffix(authorizerURL, "/") return authorizerURL
} }
scheme := c.Request.Header.Get("X-Forwarded-Proto") scheme := c.Request.Header.Get("X-Forwarded-Proto")
@@ -33,7 +33,7 @@ func GetHost(c *gin.Context) string {
scheme = "http" scheme = "http"
} }
host := c.Request.Host host := c.Request.Host
return strings.TrimSuffix(scheme+"://"+host, "/") return scheme + "://" + host
} }
// GetHostName function returns hostname and port // GetHostName function returns hostname and port
@@ -91,7 +91,7 @@ func GetDomainName(uri string) string {
return host return host
} }
// GetAppURL to get /app url if not configured by user // GetAppURL to get /app/ url if not configured by user
func GetAppURL(gc *gin.Context) string { func GetAppURL(gc *gin.Context) string {
envAppURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppURL) envAppURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppURL)
if envAppURL == "" || err != nil { if envAppURL == "" || err != nil {

View File

@@ -8,7 +8,6 @@ import (
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/authorizerdev/authorizer/server/validators" "github.com/authorizerdev/authorizer/server/validators"
@@ -41,17 +40,15 @@ func AddEmailTemplateResolver(ctx context.Context, params model.AddEmailTemplate
return nil, fmt.Errorf("empty template not allowed") return nil, fmt.Errorf("empty template not allowed")
} }
var design string if strings.TrimSpace(params.Design) == "" {
return nil, fmt.Errorf("empty design not allowed")
if params.Design == nil || strings.TrimSpace(refs.StringValue(params.Design)) == "" {
design = ""
} }
_, err = db.Provider.AddEmailTemplate(ctx, models.EmailTemplate{ _, err = db.Provider.AddEmailTemplate(ctx, models.EmailTemplate{
EventName: params.EventName, EventName: params.EventName,
Template: params.Template, Template: params.Template,
Subject: params.Subject, Subject: params.Subject,
Design: design, Design: params.Design,
}) })
if err != nil { if err != nil {
log.Debug("Failed to add email template: ", err) log.Debug("Failed to add email template: ", err)

View File

@@ -89,9 +89,6 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
if val, ok := store[constants.EnvKeySenderEmail]; ok { if val, ok := store[constants.EnvKeySenderEmail]; ok {
res.SenderEmail = refs.NewStringRef(val.(string)) res.SenderEmail = refs.NewStringRef(val.(string))
} }
if val, ok := store[constants.EnvKeySmtpLocalName]; ok {
res.SMTPLocalName = refs.NewStringRef(val.(string))
}
if val, ok := store[constants.EnvKeyJwtType]; ok { if val, ok := store[constants.EnvKeyJwtType]; ok {
res.JwtType = refs.NewStringRef(val.(string)) res.JwtType = refs.NewStringRef(val.(string))
} }

View File

@@ -62,21 +62,12 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
log.Debug("Failed to generate nonce: ", err) log.Debug("Failed to generate nonce: ", err)
return res, err return res, err
} }
redirectURL := parsers.GetAppURL(gc)
redirectURI := ""
// give higher preference to params redirect uri
if strings.TrimSpace(refs.StringValue(params.RedirectURI)) != "" { if strings.TrimSpace(refs.StringValue(params.RedirectURI)) != "" {
redirectURI = refs.StringValue(params.RedirectURI) redirectURL = refs.StringValue(params.RedirectURI)
} else {
redirectURI, err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL)
if err != nil {
log.Debug("ResetPasswordURL not found using default app url: ", err)
redirectURI = hostname + "/app/reset-password"
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, redirectURI)
}
} }
verificationToken, err := token.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURI) verificationToken, err := token.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURL)
if err != nil { if err != nil {
log.Debug("Failed to create verification token", err) log.Debug("Failed to create verification token", err)
return res, err return res, err
@@ -87,18 +78,18 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
Email: params.Email, Email: params.Email,
Nonce: nonceHash, Nonce: nonceHash,
RedirectURI: redirectURI, RedirectURI: redirectURL,
}) })
if err != nil { if err != nil {
log.Debug("Failed to add verification request", err) log.Debug("Failed to add verification request", err)
return res, err return res, err
} }
// execute it as go routine so that we can reduce the api latency // exec it as go routine so that we can reduce the api latency
go email.SendEmail([]string{params.Email}, constants.VerificationTypeForgotPassword, map[string]interface{}{ go email.SendEmail([]string{params.Email}, constants.VerificationTypeForgotPassword, map[string]interface{}{
"user": user.ToMap(), "user": user.ToMap(),
"organization": utils.GetOrganization(), "organization": utils.GetOrganization(),
"verification_url": utils.GetForgotPasswordURL(verificationToken, redirectURI), "verification_url": utils.GetForgotPasswordURL(verificationToken, hostname),
}) })
res = &model.Response{ res = &model.Response{

View File

@@ -6,7 +6,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
@@ -141,43 +140,12 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
}, nil }, nil
} }
code := "" authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth)
codeChallenge := ""
nonce := ""
if params.State != nil {
// Get state from store
authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State))
if authorizeState != "" {
authorizeStateSplit := strings.Split(authorizeState, "@@")
if len(authorizeStateSplit) > 1 {
code = authorizeStateSplit[0]
codeChallenge = authorizeStateSplit[1]
} else {
nonce = authorizeState
}
go memorystore.Provider.RemoveState(refs.StringValue(params.State))
}
}
if nonce == "" {
nonce = uuid.New().String()
}
authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth, nonce, code)
if err != nil { if err != nil {
log.Debug("Failed to create auth token", err) log.Debug("Failed to create auth token", err)
return res, err return res, err
} }
// TODO add to other login options as well
// Code challenge could be optional if PKCE flow is not used
if code != "" {
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
log.Debug("SetState failed: ", err)
return res, err
}
}
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 { if expiresIn <= 0 {
expiresIn = 1 expiresIn = 1

View File

@@ -15,7 +15,6 @@ import (
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/parsers"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/authorizerdev/authorizer/server/validators" "github.com/authorizerdev/authorizer/server/validators"
@@ -186,7 +185,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
} }
redirectURLParams := "&roles=" + strings.Join(inputRoles, ",") redirectURLParams := "&roles=" + strings.Join(inputRoles, ",")
if params.State != nil { if params.State != nil {
redirectURLParams = redirectURLParams + "&state=" + refs.StringValue(params.State) redirectURLParams = redirectURLParams + "&state=" + *params.State
} }
if params.Scope != nil && len(params.Scope) > 0 { if params.Scope != nil && len(params.Scope) > 0 {
redirectURLParams = redirectURLParams + "&scope=" + strings.Join(params.Scope, " ") redirectURLParams = redirectURLParams + "&scope=" + strings.Join(params.Scope, " ")

View File

@@ -1,216 +0,0 @@
package resolvers
import (
"context"
"fmt"
"strings"
"time"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/bcrypt"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/cookie"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/authorizerdev/authorizer/server/validators"
)
// MobileLoginResolver is a resolver for mobile login mutation
func MobileLoginResolver(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error) {
var res *model.AuthResponse
gc, err := utils.GinContextFromContext(ctx)
if err != nil {
log.Debug("Failed to get GinContext: ", err)
return res, err
}
isBasiAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
if err != nil {
log.Debug("Error getting mobile basic auth disabled: ", err)
isBasiAuthDisabled = true
}
if isBasiAuthDisabled {
log.Debug("Basic authentication is disabled.")
return res, fmt.Errorf(`phone number based basic authentication is disabled for this instance`)
}
log := log.WithFields(log.Fields{
"phone_number": params.PhoneNumber,
})
user, err := db.Provider.GetUserByPhoneNumber(ctx, params.PhoneNumber)
if err != nil {
log.Debug("Failed to get user by phone number: ", err)
return res, fmt.Errorf(`bad user credentials`)
}
if user.RevokedTimestamp != nil {
log.Debug("User access is revoked")
return res, fmt.Errorf(`user access has been revoked`)
}
if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth) {
log.Debug("User signup method is not mobile basic auth")
return res, fmt.Errorf(`user has not signed up with phone number & password`)
}
if user.PhoneNumberVerifiedAt == nil {
log.Debug("User phone number is not verified")
return res, fmt.Errorf(`phone number is not verified`)
}
err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(params.Password))
if err != nil {
log.Debug("Failed to compare password: ", err)
return res, fmt.Errorf(`bad user credentials`)
}
defaultRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
roles := []string{}
if err != nil {
log.Debug("Error getting default roles: ", err)
defaultRolesString = ""
} else {
roles = strings.Split(defaultRolesString, ",")
}
currentRoles := strings.Split(user.Roles, ",")
if len(params.Roles) > 0 {
if !validators.IsValidRoles(params.Roles, currentRoles) {
log.Debug("Invalid roles: ", params.Roles)
return res, fmt.Errorf(`invalid roles`)
}
roles = params.Roles
}
scope := []string{"openid", "email", "profile"}
if params.Scope != nil && len(scope) > 0 {
scope = params.Scope
}
/*
// TODO use sms authentication for MFA
isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
if err != nil || !isEmailServiceEnabled {
log.Debug("Email service not enabled: ", err)
}
isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication)
if err != nil || !isEmailServiceEnabled {
log.Debug("MFA service not enabled: ", err)
}
// If email service is not enabled continue the process in any way
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && isEmailServiceEnabled && !isMFADisabled {
otp := utils.GenerateOTP()
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
Email: user.Email,
Otp: otp,
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
})
if err != nil {
log.Debug("Failed to add otp: ", err)
return nil, err
}
go func() {
// exec it as go routine so that we can reduce the api latency
go email.SendEmail([]string{params.PhoneNumber}, constants.VerificationTypeOTP, map[string]interface{}{
"user": user.ToMap(),
"organization": utils.GetOrganization(),
"otp": otpData.Otp,
})
if err != nil {
log.Debug("Failed to send otp email: ", err)
}
}()
return &model.AuthResponse{
Message: "Please check the OTP in your inbox",
ShouldShowOtpScreen: refs.NewBoolRef(true),
}, nil
}
*/
code := ""
codeChallenge := ""
nonce := ""
if params.State != nil {
// Get state from store
authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State))
if authorizeState != "" {
authorizeStateSplit := strings.Split(authorizeState, "@@")
if len(authorizeStateSplit) > 1 {
code = authorizeStateSplit[0]
codeChallenge = authorizeStateSplit[1]
} else {
nonce = authorizeState
}
go memorystore.Provider.RemoveState(refs.StringValue(params.State))
}
}
if nonce == "" {
nonce = uuid.New().String()
}
authToken, err := token.CreateAuthToken(gc, *user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code)
if err != nil {
log.Debug("Failed to create auth token", err)
return res, err
}
// TODO add to other login options as well
// Code challenge could be optional if PKCE flow is not used
if code != "" {
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
log.Debug("SetState failed: ", err)
return res, err
}
}
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {
expiresIn = 1
}
res = &model.AuthResponse{
Message: `Logged in successfully`,
AccessToken: &authToken.AccessToken.Token,
IDToken: &authToken.IDToken.Token,
ExpiresIn: &expiresIn,
User: user.AsAPIUser(),
}
cookie.SetSession(gc, authToken.FingerPrintHash)
sessionStoreKey := constants.AuthRecipeMethodMobileBasicAuth + ":" + user.ID
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
if authToken.RefreshToken != nil {
res.RefreshToken = &authToken.RefreshToken.Token
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
}
go func() {
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, *user)
db.Provider.AddSession(ctx, models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(gc.Request),
IP: utils.GetIP(gc.Request),
})
}()
return res, nil
}

View File

@@ -1,270 +0,0 @@
package resolvers
import (
"context"
"fmt"
"strings"
"time"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/cookie"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/authorizerdev/authorizer/server/validators"
)
// MobileSignupResolver is a resolver for mobile_basic_auth_signup mutation
func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error) {
var res *model.AuthResponse
gc, err := utils.GinContextFromContext(ctx)
if err != nil {
log.Debug("Failed to get GinContext: ", err)
return res, err
}
isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp)
if err != nil {
log.Debug("Error getting signup disabled: ", err)
isSignupDisabled = true
}
if isSignupDisabled {
log.Debug("Signup is disabled")
return res, fmt.Errorf(`signup is disabled for this instance`)
}
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
if err != nil {
log.Debug("Error getting basic auth disabled: ", err)
isBasicAuthDisabled = true
}
if isBasicAuthDisabled {
log.Debug("Mobile based Basic authentication is disabled")
return res, fmt.Errorf(`phone number based basic authentication is disabled for this instance`)
}
if params.ConfirmPassword != params.Password {
log.Debug("Passwords do not match")
return res, fmt.Errorf(`password and confirm password does not match`)
}
if err := validators.IsValidPassword(params.Password); err != nil {
log.Debug("Invalid password")
return res, err
}
mobile := strings.TrimSpace(params.PhoneNumber)
if mobile == "" || len(mobile) < 10 {
log.Debug("Invalid phone number")
return res, fmt.Errorf("invalid phone number")
}
emailInput := strings.ToLower(strings.TrimSpace(refs.StringValue(params.Email)))
// if email is null set random dummy email for db constraint
if emailInput != "" && !validators.IsValidEmail(emailInput) {
log.Debug("Invalid email: ", emailInput)
return res, fmt.Errorf(`invalid email address`)
}
if emailInput == "" {
emailInput = mobile + "@authorizer.dev"
}
log := log.WithFields(log.Fields{
"email": emailInput,
"phone_number": mobile,
})
// find user with email
existingUser, err := db.Provider.GetUserByPhoneNumber(ctx, mobile)
if err != nil {
log.Debug("Failed to get user by email: ", err)
}
if existingUser != nil {
if existingUser.PhoneNumberVerifiedAt != nil {
// email is verified
log.Debug("Phone number is already verified and signed up.")
return res, fmt.Errorf(`%s has already signed up`, mobile)
} else if existingUser.ID != "" && existingUser.PhoneNumberVerifiedAt == nil {
log.Debug("Phone number is already signed up. Verification pending...")
return res, fmt.Errorf("%s has already signed up. please complete the phone number verification process or reset the password", mobile)
}
}
inputRoles := []string{}
if len(params.Roles) > 0 {
// check if roles exists
rolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRoles)
roles := []string{}
if err != nil {
log.Debug("Error getting roles: ", err)
return res, err
} else {
roles = strings.Split(rolesString, ",")
}
if !validators.IsValidRoles(params.Roles, roles) {
log.Debug("Invalid roles: ", params.Roles)
return res, fmt.Errorf(`invalid roles`)
} else {
inputRoles = params.Roles
}
} else {
inputRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
if err != nil {
log.Debug("Error getting default roles: ", err)
return res, err
} else {
inputRoles = strings.Split(inputRolesString, ",")
}
}
now := time.Now().Unix()
user := models.User{
Email: emailInput,
PhoneNumber: &mobile,
PhoneNumberVerifiedAt: &now,
}
user.Roles = strings.Join(inputRoles, ",")
password, _ := crypto.EncryptPassword(params.Password)
user.Password = &password
if params.GivenName != nil {
user.GivenName = params.GivenName
}
if params.FamilyName != nil {
user.FamilyName = params.FamilyName
}
if params.MiddleName != nil {
user.MiddleName = params.MiddleName
}
if params.Nickname != nil {
user.Nickname = params.Nickname
}
if params.Gender != nil {
user.Gender = params.Gender
}
if params.Birthdate != nil {
user.Birthdate = params.Birthdate
}
if params.Picture != nil {
user.Picture = params.Picture
}
if params.IsMultiFactorAuthEnabled != nil {
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
}
isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication)
if err != nil {
log.Debug("MFA service not enabled: ", err)
isMFAEnforced = false
}
if isMFAEnforced {
user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true)
}
user.SignupMethods = constants.AuthRecipeMethodMobileBasicAuth
user, err = db.Provider.AddUser(ctx, user)
if err != nil {
log.Debug("Failed to add user: ", err)
return res, err
}
roles := strings.Split(user.Roles, ",")
userToReturn := user.AsAPIUser()
scope := []string{"openid", "email", "profile"}
if params.Scope != nil && len(scope) > 0 {
scope = params.Scope
}
code := ""
codeChallenge := ""
nonce := ""
if params.State != nil {
// Get state from store
authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State))
if authorizeState != "" {
authorizeStateSplit := strings.Split(authorizeState, "@@")
if len(authorizeStateSplit) > 1 {
code = authorizeStateSplit[0]
codeChallenge = authorizeStateSplit[1]
} else {
nonce = authorizeState
}
go memorystore.Provider.RemoveState(refs.StringValue(params.State))
}
}
if nonce == "" {
nonce = uuid.New().String()
}
authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code)
if err != nil {
log.Debug("Failed to create auth token: ", err)
return res, err
}
// Code challenge could be optional if PKCE flow is not used
if code != "" {
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
log.Debug("SetState failed: ", err)
return res, err
}
}
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {
expiresIn = 1
}
res = &model.AuthResponse{
Message: `Signed up successfully.`,
AccessToken: &authToken.AccessToken.Token,
ExpiresIn: &expiresIn,
User: userToReturn,
}
sessionKey := constants.AuthRecipeMethodMobileBasicAuth + ":" + user.ID
cookie.SetSession(gc, authToken.FingerPrintHash)
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
if authToken.RefreshToken != nil {
res.RefreshToken = &authToken.RefreshToken.Token
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
}
go func() {
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
db.Provider.AddSession(ctx, models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(gc.Request),
IP: utils.GetIP(gc.Request),
})
}()
return res, nil
}

View File

@@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
@@ -71,8 +70,7 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
scope = params.Scope scope = params.Scope
} }
nonce := uuid.New().String() authToken, err := token.CreateAuthToken(gc, user, claimRoles, scope, claims.LoginMethod)
authToken, err := token.CreateAuthToken(gc, user, claimRoles, scope, claims.LoginMethod, nonce, "")
if err != nil { if err != nil {
log.Debug("Failed to create auth token: ", err) log.Debug("Failed to create auth token: ", err)
return res, err return res, err

View File

@@ -6,7 +6,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
@@ -243,42 +242,12 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
scope = params.Scope scope = params.Scope
} }
code := "" authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth)
codeChallenge := ""
nonce := ""
if params.State != nil {
// Get state from store
authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State))
if authorizeState != "" {
authorizeStateSplit := strings.Split(authorizeState, "@@")
if len(authorizeStateSplit) > 1 {
code = authorizeStateSplit[0]
codeChallenge = authorizeStateSplit[1]
} else {
nonce = authorizeState
}
go memorystore.Provider.RemoveState(refs.StringValue(params.State))
}
}
if nonce == "" {
nonce = uuid.New().String()
}
authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth, nonce, code)
if err != nil { if err != nil {
log.Debug("Failed to create auth token: ", err) log.Debug("Failed to create auth token: ", err)
return res, err return res, err
} }
// Code challenge could be optional if PKCE flow is not used
if code != "" {
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
log.Debug("SetState failed: ", err)
return res, err
}
}
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 { if expiresIn <= 0 {
expiresIn = 1 expiresIn = 1

View File

@@ -25,7 +25,6 @@ import (
// remove the session tokens for those methods // remove the session tokens for those methods
func clearSessionIfRequired(currentData, updatedData map[string]interface{}) { func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
isCurrentBasicAuthEnabled := !currentData[constants.EnvKeyDisableBasicAuthentication].(bool) isCurrentBasicAuthEnabled := !currentData[constants.EnvKeyDisableBasicAuthentication].(bool)
isCurrentMobileBasicAuthEnabled := !currentData[constants.EnvKeyDisableMobileBasicAuthentication].(bool)
isCurrentMagicLinkLoginEnabled := !currentData[constants.EnvKeyDisableMagicLinkLogin].(bool) isCurrentMagicLinkLoginEnabled := !currentData[constants.EnvKeyDisableMagicLinkLogin].(bool)
isCurrentAppleLoginEnabled := currentData[constants.EnvKeyAppleClientID] != nil && currentData[constants.EnvKeyAppleClientSecret] != nil && currentData[constants.EnvKeyAppleClientID].(string) != "" && currentData[constants.EnvKeyAppleClientSecret].(string) != "" isCurrentAppleLoginEnabled := currentData[constants.EnvKeyAppleClientID] != nil && currentData[constants.EnvKeyAppleClientSecret] != nil && currentData[constants.EnvKeyAppleClientID].(string) != "" && currentData[constants.EnvKeyAppleClientSecret].(string) != ""
isCurrentFacebookLoginEnabled := currentData[constants.EnvKeyFacebookClientID] != nil && currentData[constants.EnvKeyFacebookClientSecret] != nil && currentData[constants.EnvKeyFacebookClientID].(string) != "" && currentData[constants.EnvKeyFacebookClientSecret].(string) != "" isCurrentFacebookLoginEnabled := currentData[constants.EnvKeyFacebookClientID] != nil && currentData[constants.EnvKeyFacebookClientSecret] != nil && currentData[constants.EnvKeyFacebookClientID].(string) != "" && currentData[constants.EnvKeyFacebookClientSecret].(string) != ""
@@ -35,7 +34,6 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
isCurrentTwitterLoginEnabled := currentData[constants.EnvKeyTwitterClientID] != nil && currentData[constants.EnvKeyTwitterClientSecret] != nil && currentData[constants.EnvKeyTwitterClientID].(string) != "" && currentData[constants.EnvKeyTwitterClientSecret].(string) != "" isCurrentTwitterLoginEnabled := currentData[constants.EnvKeyTwitterClientID] != nil && currentData[constants.EnvKeyTwitterClientSecret] != nil && currentData[constants.EnvKeyTwitterClientID].(string) != "" && currentData[constants.EnvKeyTwitterClientSecret].(string) != ""
isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool) isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool)
isUpdatedMobileBasicAuthEnabled := !updatedData[constants.EnvKeyDisableMobileBasicAuthentication].(bool)
isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool) isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool)
isUpdatedAppleLoginEnabled := updatedData[constants.EnvKeyAppleClientID] != nil && updatedData[constants.EnvKeyAppleClientSecret] != nil && updatedData[constants.EnvKeyAppleClientID].(string) != "" && updatedData[constants.EnvKeyAppleClientSecret].(string) != "" isUpdatedAppleLoginEnabled := updatedData[constants.EnvKeyAppleClientID] != nil && updatedData[constants.EnvKeyAppleClientSecret] != nil && updatedData[constants.EnvKeyAppleClientID].(string) != "" && updatedData[constants.EnvKeyAppleClientSecret].(string) != ""
isUpdatedFacebookLoginEnabled := updatedData[constants.EnvKeyFacebookClientID] != nil && updatedData[constants.EnvKeyFacebookClientSecret] != nil && updatedData[constants.EnvKeyFacebookClientID].(string) != "" && updatedData[constants.EnvKeyFacebookClientSecret].(string) != "" isUpdatedFacebookLoginEnabled := updatedData[constants.EnvKeyFacebookClientID] != nil && updatedData[constants.EnvKeyFacebookClientSecret] != nil && updatedData[constants.EnvKeyFacebookClientID].(string) != "" && updatedData[constants.EnvKeyFacebookClientSecret].(string) != ""
@@ -48,10 +46,6 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth) memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth)
} }
if isCurrentMobileBasicAuthEnabled && !isUpdatedMobileBasicAuthEnabled {
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMobileBasicAuth)
}
if isCurrentMagicLinkLoginEnabled && !isUpdatedMagicLinkLoginEnabled { if isCurrentMagicLinkLoginEnabled && !isUpdatedMagicLinkLoginEnabled {
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMagicLinkLogin) memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMagicLinkLogin)
} }

View File

@@ -88,11 +88,6 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
} }
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) { if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
// verify if phone number is unique
if _, err := db.Provider.GetUserByPhoneNumber(ctx, strings.TrimSpace(refs.StringValue(params.PhoneNumber))); err == nil {
log.Debug("user with given phone number already exists")
return nil, errors.New("user with given phone number already exists")
}
user.PhoneNumber = params.PhoneNumber user.PhoneNumber = params.PhoneNumber
} }
@@ -159,14 +154,8 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
isBasicAuthDisabled = true isBasicAuthDisabled = true
} }
isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
if err != nil {
log.Debug("Error getting mobile basic auth disabled: ", err)
isBasicAuthDisabled = true
}
if params.NewPassword != nil && params.ConfirmNewPassword != nil { if params.NewPassword != nil && params.ConfirmNewPassword != nil {
if isBasicAuthDisabled || isMobileBasicAuthDisabled { if isBasicAuthDisabled {
log.Debug("Cannot update password as basic authentication is disabled") log.Debug("Cannot update password as basic authentication is disabled")
return res, fmt.Errorf(`basic authentication is disabled for this instance`) return res, fmt.Errorf(`basic authentication is disabled for this instance`)
} }

View File

@@ -83,11 +83,6 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
} }
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) { if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
// verify if phone number is unique
if _, err := db.Provider.GetUserByPhoneNumber(ctx, strings.TrimSpace(refs.StringValue(params.PhoneNumber))); err == nil {
log.Debug("user with given phone number already exists")
return nil, errors.New("user with given phone number already exists")
}
user.PhoneNumber = params.PhoneNumber user.PhoneNumber = params.PhoneNumber
} }
@@ -130,6 +125,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
return res, fmt.Errorf("user with this email address already exists") return res, fmt.Errorf("user with this email address already exists")
} }
// TODO figure out how to do this
go memorystore.Provider.DeleteAllUserSessions(user.ID) go memorystore.Provider.DeleteAllUserSessions(user.ID)
hostname := parsers.GetHost(gc) hostname := parsers.GetHost(gc)

View File

@@ -77,16 +77,7 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken
} }
} }
claimKey := "roles" claimRolesInterface := claims["roles"]
if tokenType == constants.TokenTypeIdentityToken {
claimKey, err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtRoleClaim)
if err != nil {
claimKey = "roles"
}
}
claimRolesInterface := claims[claimKey]
roleSlice := utils.ConvertInterfaceToSlice(claimRolesInterface) roleSlice := utils.ConvertInterfaceToSlice(claimRolesInterface)
for _, v := range roleSlice { for _, v := range roleSlice {
claimRoles = append(claimRoles, v.(string)) claimRoles = append(claimRoles, v.(string))
@@ -102,6 +93,5 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken
} }
return &model.ValidateJWTTokenResponse{ return &model.ValidateJWTTokenResponse{
IsValid: true, IsValid: true,
Claims: claims,
}, nil }, nil
} }

View File

@@ -6,7 +6,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
@@ -16,7 +15,6 @@ import (
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/parsers"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
@@ -86,42 +84,12 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
roles := strings.Split(user.Roles, ",") roles := strings.Split(user.Roles, ",")
scope := []string{"openid", "email", "profile"} scope := []string{"openid", "email", "profile"}
code := "" authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod)
// Not required as /oauth/token cannot be resumed from other tab
// codeChallenge := ""
nonce := ""
if params.State != nil {
// Get state from store
authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State))
if authorizeState != "" {
authorizeStateSplit := strings.Split(authorizeState, "@@")
if len(authorizeStateSplit) > 1 {
code = authorizeStateSplit[0]
// Not required as /oauth/token cannot be resumed from other tab
// codeChallenge = authorizeStateSplit[1]
} else {
nonce = authorizeState
}
go memorystore.Provider.RemoveState(refs.StringValue(params.State))
}
}
if nonce == "" {
nonce = uuid.New().String()
}
authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod, nonce, code)
if err != nil { if err != nil {
log.Debug("Failed to create auth token: ", err) log.Debug("Failed to create auth token: ", err)
return res, err return res, err
} }
// Code challenge could be optional if PKCE flow is not used
// Not required as /oauth/token cannot be resumed from other tab
// if code != "" {
// if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
// log.Debug("SetState failed: ", err)
// return res, err
// }
// }
go func() { go func() {
if isSignUp { if isSignUp {
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user) utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user)

View File

@@ -12,10 +12,8 @@ import (
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@@ -59,40 +57,12 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
roles := strings.Split(user.Roles, ",") roles := strings.Split(user.Roles, ",")
scope := []string{"openid", "email", "profile"} scope := []string{"openid", "email", "profile"}
code := "" authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod)
codeChallenge := ""
nonce := ""
if params.State != nil {
// Get state from store
authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State))
if authorizeState != "" {
authorizeStateSplit := strings.Split(authorizeState, "@@")
if len(authorizeStateSplit) > 1 {
code = authorizeStateSplit[0]
codeChallenge = authorizeStateSplit[1]
} else {
nonce = authorizeState
}
go memorystore.Provider.RemoveState(refs.StringValue(params.State))
}
}
if nonce == "" {
nonce = uuid.New().String()
}
authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod, nonce, code)
if err != nil { if err != nil {
log.Debug("Failed to create auth token: ", err) log.Debug("Failed to create auth token: ", err)
return res, err return res, err
} }
// Code challenge could be optional if PKCE flow is not used
if code != "" {
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
log.Debug("Failed to set code state: ", err)
return res, err
}
}
go func() { go func() {
db.Provider.DeleteOTP(gc, otp) db.Provider.DeleteOTP(gc, otp)
if isSignUp { if isSignUp {

View File

@@ -51,15 +51,24 @@ func addEmailTemplateTest(t *testing.T, s TestSetup) {
assert.Nil(t, emailTemplate) assert.Nil(t, emailTemplate)
}) })
design := "" t.Run("should not add email template with empty design", func(t *testing.T) {
emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{
EventName: s.TestInfo.TestEmailTemplateEventTypes[0],
Template: "test",
Subject: "test",
Design: " ",
})
assert.Error(t, err)
assert.Nil(t, emailTemplate)
})
for _, eventType := range s.TestInfo.TestEmailTemplateEventTypes { for _, eventType := range s.TestInfo.TestEmailTemplateEventTypes {
t.Run("should add email template with empty design for "+eventType, func(t *testing.T) { t.Run("should add email template for "+eventType, func(t *testing.T) {
emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{ emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{
EventName: eventType, EventName: eventType,
Template: "Test email", Template: "Test email",
Subject: "Test email", Subject: "Test email",
Design: &design, Design: "Test design",
}) })
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, emailTemplate) assert.NotNil(t, emailTemplate)
@@ -69,7 +78,7 @@ func addEmailTemplateTest(t *testing.T, s TestSetup) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, et.EventName, eventType) assert.Equal(t, et.EventName, eventType)
assert.Equal(t, "Test email", et.Subject) assert.Equal(t, "Test email", et.Subject)
assert.Equal(t, "", et.Design) assert.Equal(t, "Test design", et.Design)
}) })
} }
}) })

View File

@@ -1,58 +0,0 @@
package test
import (
"strings"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert"
)
func mobileLoginTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should login via mobile`, func(t *testing.T) {
_, ctx := createContext(s)
email := "mobile_login." + s.TestInfo.Email
phoneNumber := "2234567890"
signUpRes, err := resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
Email: refs.NewStringRef(email),
PhoneNumber: phoneNumber,
Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password,
})
assert.NoError(t, err)
assert.NotNil(t, signUpRes)
assert.Equal(t, email, signUpRes.User.Email)
assert.Equal(t, phoneNumber, refs.StringValue(signUpRes.User.PhoneNumber))
assert.True(t, strings.Contains(signUpRes.User.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth))
assert.Len(t, strings.Split(signUpRes.User.SignupMethods, ","), 1)
res, err := resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{
PhoneNumber: phoneNumber,
Password: "random_test",
})
assert.Error(t, err)
assert.Nil(t, res)
// Should fail for email login
res, err = resolvers.LoginResolver(ctx, model.LoginInput{
Email: email,
Password: s.TestInfo.Password,
})
assert.Error(t, err)
assert.Nil(t, res)
res, err = resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{
PhoneNumber: phoneNumber,
Password: s.TestInfo.Password,
})
assert.NoError(t, err)
assert.NotEmpty(t, res.AccessToken)
assert.NotEmpty(t, res.IDToken)
cleanData(email)
})
}

View File

@@ -1,85 +0,0 @@
package test
import (
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert"
)
func mobileSingupTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should complete the signup with mobile and check duplicates`, func(t *testing.T) {
_, ctx := createContext(s)
email := "mobile_basic_auth_signup." + s.TestInfo.Email
res, err := resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
Email: refs.NewStringRef(email),
Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password + "s",
})
assert.NotNil(t, err, "invalid password")
assert.Nil(t, res)
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
Email: refs.NewStringRef(email),
Password: "test",
ConfirmPassword: "test",
})
assert.NotNil(t, err, "invalid password")
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, true)
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
Email: refs.NewStringRef(email),
Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password,
})
assert.NotNil(t, err, "singup disabled")
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, false)
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication, true)
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
Email: refs.NewStringRef(email),
Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password,
})
assert.NotNil(t, err, "singup disabled")
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication, false)
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
PhoneNumber: " ",
Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password,
})
assert.NotNil(t, err, "invalid mobile")
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
PhoneNumber: "test",
Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password,
})
assert.NotNil(t, err, "invalid mobile")
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
PhoneNumber: "1234567890",
Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password,
})
assert.NoError(t, err)
assert.NotEmpty(t, res.AccessToken)
assert.Equal(t, "1234567890@authorizer.dev", res.User.Email)
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
PhoneNumber: "1234567890",
Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password,
})
assert.Error(t, err, "user exists")
cleanData(email)
cleanData("1234567890@authorizer.dev")
})
}

View File

@@ -20,7 +20,6 @@ func TestResolvers(t *testing.T) {
constants.DbTypeArangodb: "http://localhost:8529", constants.DbTypeArangodb: "http://localhost:8529",
constants.DbTypeMongodb: "mongodb://localhost:27017", constants.DbTypeMongodb: "mongodb://localhost:27017",
constants.DbTypeScyllaDB: "127.0.0.1:9042", constants.DbTypeScyllaDB: "127.0.0.1:9042",
constants.DbTypeDynamoDB: "http://0.0.0.0:8000",
} }
testDBs := strings.Split(os.Getenv("TEST_DBS"), ",") testDBs := strings.Split(os.Getenv("TEST_DBS"), ",")
@@ -52,33 +51,25 @@ func TestResolvers(t *testing.T) {
os.Setenv(constants.EnvKeyDatabaseURL, dbURL) os.Setenv(constants.EnvKeyDatabaseURL, dbURL)
os.Setenv(constants.EnvKeyDatabaseType, dbType) os.Setenv(constants.EnvKeyDatabaseType, dbType)
os.Setenv(constants.EnvKeyDatabaseName, testDb) os.Setenv(constants.EnvKeyDatabaseName, testDb)
if dbType == constants.DbTypeDynamoDB {
memorystore.Provider.UpdateEnvVariable(constants.EnvAwsRegion, "ap-south-1")
os.Setenv(constants.EnvAwsRegion, "ap-south-1")
}
memorystore.InitRequiredEnv() memorystore.InitRequiredEnv()
err := db.InitDB() err := db.InitDB()
if err != nil { if err != nil {
t.Logf("Error initializing database: %s", err.Error()) t.Errorf("Error initializing database: %s", err.Error())
} }
// clean the persisted config for test to use fresh config // clean the persisted config for test to use fresh config
envData, err := db.Provider.GetEnv(ctx) envData, err := db.Provider.GetEnv(ctx)
if err == nil && envData.ID != "" { if err == nil {
envData.EnvData = "" envData.EnvData = ""
_, err = db.Provider.UpdateEnv(ctx, envData) _, err = db.Provider.UpdateEnv(ctx, envData)
if err != nil { if err != nil {
t.Logf("Error updating env: %s", err.Error()) t.Errorf("Error updating env: %s", err.Error())
} }
} else if err != nil {
t.Logf("Error getting env: %s", err.Error())
} }
err = env.PersistEnv() err = env.PersistEnv()
if err != nil { if err != nil {
t.Logf("Error persisting env: %s", err.Error()) t.Errorf("Error persisting env: %s", err.Error())
} }
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEnv, "test") memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEnv, "test")
@@ -111,8 +102,6 @@ func TestResolvers(t *testing.T) {
// user resolvers tests // user resolvers tests
loginTests(t, s) loginTests(t, s)
signupTests(t, s) signupTests(t, s)
mobileSingupTest(t, s)
mobileLoginTests(t, s)
forgotPasswordTest(t, s) forgotPasswordTest(t, s)
resendVerifyEmailTests(t, s) resendVerifyEmailTests(t, s)
resetPasswordTest(t, s) resetPasswordTest(t, s)

View File

@@ -84,7 +84,7 @@ func testSetup() TestSetup {
testData := TestData{ testData := TestData{
Email: fmt.Sprintf("%d_authorizer_tester@yopmail.com", time.Now().Unix()), Email: fmt.Sprintf("%d_authorizer_tester@yopmail.com", time.Now().Unix()),
Password: "Test@123", Password: "Test@123",
WebhookEndpoint: "https://62f93101e05644803533cf36.mockapi.io/authorizer/webhook", WebhookEndpoint: "https://62cbc6738042b16aa7c22df2.mockapi.io/api/v1/webhook",
TestWebhookEventTypes: []string{constants.UserAccessEnabledWebhookEvent, constants.UserAccessRevokedWebhookEvent, constants.UserCreatedWebhookEvent, constants.UserDeletedWebhookEvent, constants.UserLoginWebhookEvent, constants.UserSignUpWebhookEvent}, TestWebhookEventTypes: []string{constants.UserAccessEnabledWebhookEvent, constants.UserAccessRevokedWebhookEvent, constants.UserCreatedWebhookEvent, constants.UserDeletedWebhookEvent, constants.UserLoginWebhookEvent, constants.UserSignUpWebhookEvent},
TestEmailTemplateEventTypes: []string{constants.VerificationTypeBasicAuthSignup, constants.VerificationTypeForgotPassword, constants.VerificationTypeMagicLinkLogin, constants.VerificationTypeUpdateEmail}, TestEmailTemplateEventTypes: []string{constants.VerificationTypeBasicAuthSignup, constants.VerificationTypeForgotPassword, constants.VerificationTypeMagicLinkLogin, constants.VerificationTypeUpdateEmail},
} }

Some files were not shown because too many files have changed in this diff Show More