Compare commits
No commits in common. "discours" and "fix-webhook-test-endpoint" have entirely different histories.
discours
...
fix-webhoo
|
@ -1,5 +1,4 @@
|
|||
ENV=production
|
||||
DATABASE_URL=data.db
|
||||
DATABASE_TYPE=sqlite
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT="function(user,tokenPayload){var data = tokenPayload;data.extra = {'x-extra-id': user.id};return data;}"
|
||||
DISABLE_PLAYGROUND=true
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT="function(user,tokenPayload){var data = tokenPayload;data.extra = {'x-extra-id': user.id};return data;}"
|
|
@ -12,4 +12,4 @@ TWILIO_API_SECRET=test
|
|||
TWILIO_ACCOUNT_SID=ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
TWILIO_SENDER=909921212112
|
||||
SENDER_NAME="Authorizer"
|
||||
AWS_REGION=ap-south-1
|
||||
AWS_REGION=ap-south-1
|
|
@ -1,36 +0,0 @@
|
|||
name: "deploy"
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cloning repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get Repo Name
|
||||
id: repo_name
|
||||
run: echo "::set-output name=repo::$(echo ${GITHUB_REPOSITORY##*/})"
|
||||
|
||||
- name: Get Branch Name
|
||||
id: branch_name
|
||||
run: echo "::set-output name=branch::$(echo ${GITHUB_REF##*/})"
|
||||
|
||||
- name: Push branch 'discours-dev' to staging
|
||||
if: steps.branch_name.outputs.branch == 'discours-dev'
|
||||
uses: dokku/github-action@master
|
||||
with:
|
||||
branch: "main"
|
||||
git_remote_url: "ssh://dokku@staging.discours.io:22/authorizer"
|
||||
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
|
||||
- name: Push branch 'discours' to v2.discours.io
|
||||
if: steps.branch_name.outputs.branch == 'discours'
|
||||
uses: dokku/github-action@master
|
||||
with:
|
||||
branch: "main"
|
||||
git_remote_url: "ssh://dokku@v2.discours.io:22/authorizer"
|
||||
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
git_push_flags: '--force'
|
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
|
@ -62,14 +62,12 @@ jobs:
|
|||
run: |
|
||||
make clean && \
|
||||
make build && \
|
||||
mkdir -p authorizer-${VERSION}-darwin-arm64/build authorizer-${VERSION}-darwin-arm64/app authorizer-${VERSION}-darwin-arm64/dashboard && cp build/darwin/arm64/server authorizer-${VERSION}-darwin-arm64/build/ && cp .env authorizer-${VERSION}-darwin-arm64/.env && cp -rf app/build authorizer-${VERSION}-darwin-arm64/app/build && cp -rf templates authorizer-${VERSION}-darwin-arm64/ && cp -rf dashboard/build authorizer-${VERSION}-darwin-arm64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-arm64.tar.gz authorizer-${VERSION}-darwin-arm64 && \
|
||||
mkdir -p authorizer-${VERSION}-darwin-amd64/build authorizer-${VERSION}-darwin-amd64/app authorizer-${VERSION}-darwin-amd64/dashboard && cp build/darwin/amd64/server authorizer-${VERSION}-darwin-amd64/build/ && cp .env authorizer-${VERSION}-darwin-amd64/.env && cp -rf app/build authorizer-${VERSION}-darwin-amd64/app/build && cp -rf templates authorizer-${VERSION}-darwin-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-darwin-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-amd64.tar.gz authorizer-${VERSION}-darwin-amd64 && \
|
||||
mkdir -p authorizer-${VERSION}-linux-amd64/build authorizer-${VERSION}-linux-amd64/app authorizer-${VERSION}-linux-amd64/dashboard && cp build/linux/amd64/server authorizer-${VERSION}-linux-amd64/build/ && cp .env authorizer-${VERSION}-linux-amd64/.env && cp -rf app/build authorizer-${VERSION}-linux-amd64/app/build && cp -rf templates authorizer-${VERSION}-linux-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz authorizer-${VERSION}-linux-amd64 && \
|
||||
mkdir -p authorizer-${VERSION}-linux-arm64/build authorizer-${VERSION}-linux-arm64/app authorizer-${VERSION}-linux-arm64/dashboard && cp build/linux/arm64/server authorizer-${VERSION}-linux-arm64/build/ && cp .env authorizer-${VERSION}-linux-arm64/.env && cp -rf app/build authorizer-${VERSION}-linux-arm64/app/build && cp -rf templates authorizer-${VERSION}-linux-arm64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-arm64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-arm64.tar.gz authorizer-${VERSION}-linux-arm64 && \
|
||||
mkdir -p authorizer-${VERSION}-windows-amd64/build authorizer-${VERSION}-windows-amd64/app authorizer-${VERSION}-windows-amd64/dashboard && cp build/windows/amd64/server.exe authorizer-${VERSION}-windows-amd64/build/ && cp .env authorizer-${VERSION}-windows-amd64/.env && cp -rf app/build authorizer-${VERSION}-windows-amd64/app/build && cp -rf templates authorizer-${VERSION}-windows-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-windows-amd64/dashboard/build && zip -vr authorizer-${VERSION}-windows-amd64.zip authorizer-${VERSION}-windows-amd64
|
||||
- name: Upload assets
|
||||
run: |
|
||||
github-assets-uploader -f authorizer-${VERSION}-darwin-arm64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
|
||||
github-assets-uploader -f authorizer-${VERSION}-darwin-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
|
||||
github-assets-uploader -f authorizer-${VERSION}-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}
|
||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -17,6 +17,4 @@ test.db
|
|||
yalc.lock
|
||||
certs/
|
||||
*-shm
|
||||
*-wal
|
||||
.idea
|
||||
*.iml
|
||||
*-wal
|
|
@ -1,4 +1,4 @@
|
|||
FROM golang:1.21.3-alpine3.18 AS go-builder
|
||||
FROM golang:1.19.5-alpine as go-builder
|
||||
WORKDIR /authorizer
|
||||
COPY server server
|
||||
COPY Makefile .
|
||||
|
@ -11,7 +11,7 @@ RUN apk add build-base &&\
|
|||
make clean && make && \
|
||||
chmod 777 build/server
|
||||
|
||||
FROM node:20-alpine3.18 AS node-builder
|
||||
FROM node:17-alpine3.12 as node-builder
|
||||
WORKDIR /authorizer
|
||||
COPY app app
|
||||
COPY dashboard dashboard
|
||||
|
@ -20,7 +20,7 @@ RUN apk add build-base &&\
|
|||
make build-app && \
|
||||
make build-dashboard
|
||||
|
||||
FROM alpine:3.18
|
||||
FROM alpine:latest
|
||||
RUN adduser -D -h /authorizer -u 1000 -k /dev/null authorizer
|
||||
WORKDIR /authorizer
|
||||
RUN mkdir app dashboard
|
||||
|
|
8
Makefile
8
Makefile
|
@ -5,7 +5,7 @@ cmd:
|
|||
cd server && go build -ldflags "-w -X main.VERSION=$(VERSION)" -o '../build/server'
|
||||
build:
|
||||
cd server && gox \
|
||||
-osarch="linux/amd64 linux/arm64 darwin/arm64 darwin/amd64 windows/amd64" \
|
||||
-osarch="linux/amd64 linux/arm64 darwin/amd64 windows/amd64" \
|
||||
-ldflags "-w -X main.VERSION=$(VERSION)" \
|
||||
-output="../build/{{.OS}}/{{.Arch}}/server" \
|
||||
./...
|
||||
|
@ -30,7 +30,7 @@ test-arangodb:
|
|||
cd server && go clean --testcache && TEST_DBS="arangodb" go test -p 1 -v ./test
|
||||
docker rm -vf authorizer_arangodb
|
||||
test-dynamodb:
|
||||
docker run -d --name dynamodb-local-test -p 8000:8000 amazon/dynamodb-local:latest
|
||||
docker run -d --name dynamodb-local-test -p 8000:8000 amazon/dynamodb-local:latest
|
||||
cd server && go clean --testcache && TEST_DBS="dynamodb" go test -p 1 -v ./test
|
||||
docker rm -vf dynamodb-local-test
|
||||
test-couchbase:
|
||||
|
@ -46,7 +46,7 @@ test-all-db:
|
|||
docker run -d --name dynamodb-local-test -p 8000:8000 amazon/dynamodb-local:latest
|
||||
docker run -d --name couchbase-local-test -p 8091-8097:8091-8097 -p 11210:11210 -p 11207:11207 -p 18091-18095:18091-18095 -p 18096:18096 -p 18097:18097 couchbase:latest
|
||||
sh scripts/couchbase-test.sh
|
||||
cd server && go clean --testcache && TEST_DBS="sqlite,mongodb,arangodb,scylladb,dynamodb,couchbase" 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_mongodb_db
|
||||
docker rm -vf authorizer_arangodb
|
||||
|
@ -56,4 +56,4 @@ generate-graphql:
|
|||
cd server && go run github.com/99designs/gqlgen generate && go mod tidy
|
||||
generate-db-template:
|
||||
cp -rf server/db/providers/provider_template server/db/providers/${dbname}
|
||||
find server/db/providers/${dbname} -type f -exec sed -i -e 's/provider_template/${dbname}/g' {} \;
|
||||
find server/db/providers/${dbname} -type f -exec sed -i -e 's/provider_template/${dbname}/g' {} \;
|
|
@ -68,8 +68,6 @@ Deploy production ready Authorizer instance using one click deployment options a
|
|||
| Railway.app | <a href="https://railway.app/new/template/nwXp1C?referralCode=FEF4uT"><img src="https://railway.app/button.svg" style="height: 44px" alt="Deploy on Railway"></a> | [docs](https://docs.authorizer.dev/deployment/railway) |
|
||||
| Heroku | <a href="https://heroku.com/deploy?template=https://github.com/authorizerdev/authorizer-heroku"><img src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy to Heroku" style="height: 44px;"></a> | [docs](https://docs.authorizer.dev/deployment/heroku) |
|
||||
| Render | [](https://render.com/deploy?repo=https://github.com/authorizerdev/authorizer-render) | [docs](https://docs.authorizer.dev/deployment/render) |
|
||||
| Koyeb | <a target="_blank" href="https://app.koyeb.com/deploy?name=authorizer&type=docker&image=docker.io/lakhansamani/authorizer&env[PORT]=8000&env[DATABASE_TYPE]=postgres&env[DATABASE_URL]=CHANGE_ME&ports=8000;http;/"><img alt="Deploy to Koyeb" src="https://www.koyeb.com/static/images/deploy/button.svg" /></a> | [docs](https://docs.authorizer.dev/deployment/koyeb) |
|
||||
| RepoCloud | <a href="https://repocloud.io/details/?app_id=174"><img src="https://d16t0pc4846x52.cloudfront.net/deploy.png" alt="Deploy on RepoCloud"></a> | [docs](https://repocloud.io/details/?app_id=174) |
|
||||
|
||||
### Deploy Authorizer Using Source Code
|
||||
|
||||
|
|
875
app/package-lock.json
generated
875
app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -12,7 +12,7 @@
|
|||
"author": "Lakhan Samani",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-react": "^1.3.2",
|
||||
"@authorizerdev/authorizer-react": "^1.1.13",
|
||||
"@types/react": "^17.0.15",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"esbuild": "^0.12.17",
|
||||
|
|
|
@ -27,12 +27,13 @@ export default function App() {
|
|||
if (redirectURL) {
|
||||
urlProps.redirectURL = redirectURL;
|
||||
} else {
|
||||
urlProps.redirectURL = window.location.href;
|
||||
urlProps.redirectURL = window.location.origin + '/app';
|
||||
}
|
||||
const globalState: Record<string, string> = {
|
||||
...window['__authorizer__'],
|
||||
...urlProps,
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
|
@ -53,7 +54,7 @@ export default function App() {
|
|||
<img
|
||||
src={`${globalState.organizationLogo}`}
|
||||
alt="logo"
|
||||
style={{ height: 60, objectFit: 'cover' }}
|
||||
style={{ height: 60, width: 60, objectFit: 'cover' }}
|
||||
/>
|
||||
<h1>{globalState.organizationName}</h1>
|
||||
</div>
|
||||
|
|
|
@ -59,9 +59,7 @@ export default function Root({
|
|||
useEffect(() => {
|
||||
if (token) {
|
||||
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}`;
|
||||
// Note: If OIDC breaks in the future, use the above params
|
||||
let params = `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 !== '') {
|
||||
params += `&code=${code}`;
|
||||
|
|
|
@ -32,35 +32,29 @@ const FooterContent = styled.div`
|
|||
export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
||||
const { config } = useAuthorizer();
|
||||
const [view, setView] = useState<VIEW_TYPES>(VIEW_TYPES.LOGIN);
|
||||
const isBasicAuth = config.is_basic_authentication_enabled;
|
||||
return (
|
||||
<Fragment>
|
||||
{view === VIEW_TYPES.LOGIN && (
|
||||
<Fragment>
|
||||
<h1 style={{ textAlign: 'center' }}>Login</h1>
|
||||
<AuthorizerSocialLogin urlProps={urlProps} />
|
||||
<br />
|
||||
{(config.is_basic_authentication_enabled ||
|
||||
config.is_mobile_basic_authentication_enabled) &&
|
||||
<AuthorizerSocialLogin urlProps={urlProps} />
|
||||
{config.is_basic_authentication_enabled &&
|
||||
!config.is_magic_link_login_enabled && (
|
||||
<AuthorizerBasicAuthLogin urlProps={urlProps} />
|
||||
)}
|
||||
{config.is_magic_link_login_enabled && (
|
||||
<AuthorizerMagicLinkLogin urlProps={urlProps} />
|
||||
)}
|
||||
{(config.is_basic_authentication_enabled ||
|
||||
config.is_mobile_basic_authentication_enabled) &&
|
||||
!config.is_magic_link_login_enabled && (
|
||||
<Footer>
|
||||
<Link
|
||||
to="#"
|
||||
onClick={() => setView(VIEW_TYPES.FORGOT_PASSWORD)}
|
||||
style={{ marginBottom: 10 }}
|
||||
>
|
||||
Forgot Password?
|
||||
</Link>
|
||||
</Footer>
|
||||
)}
|
||||
<Footer>
|
||||
<Link
|
||||
to="#"
|
||||
onClick={() => setView(VIEW_TYPES.FORGOT_PASSWORD)}
|
||||
style={{ marginBottom: 10 }}
|
||||
>
|
||||
Forgot Password?
|
||||
</Link>
|
||||
</Footer>
|
||||
</Fragment>
|
||||
)}
|
||||
{view === VIEW_TYPES.FORGOT_PASSWORD && (
|
||||
|
@ -71,9 +65,6 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
|||
...urlProps,
|
||||
redirect_uri: `${window.location.origin}/app/reset-password`,
|
||||
}}
|
||||
onPasswordReset={() => {
|
||||
setView(VIEW_TYPES.LOGIN);
|
||||
}}
|
||||
/>
|
||||
<Footer>
|
||||
<Link
|
||||
|
@ -90,7 +81,7 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
|||
!config.is_magic_link_login_enabled &&
|
||||
config.is_sign_up_enabled && (
|
||||
<FooterContent>
|
||||
Don't have an account? <Link to="/app/signup"> Sign Up</Link>
|
||||
Don't have an account? <Link to="/app/signup"> Sign Up</Link>
|
||||
</FooterContent>
|
||||
)}
|
||||
</Fragment>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { Fragment } from 'react';
|
||||
import { AuthorizerSignup, AuthorizerSocialLogin } from '@authorizerdev/authorizer-react';
|
||||
import { AuthorizerSignup } from '@authorizerdev/authorizer-react';
|
||||
import styled from 'styled-components';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
|
@ -19,7 +19,6 @@ export default function SignUp({
|
|||
<Fragment>
|
||||
<h1 style={{ textAlign: 'center' }}>Sign Up</h1>
|
||||
<br />
|
||||
<AuthorizerSocialLogin urlProps={urlProps} />
|
||||
<AuthorizerSignup urlProps={urlProps} />
|
||||
<FooterContent>
|
||||
Already have an account? <Link to="/app"> Login</Link>
|
||||
|
|
865
app/yarn.lock
865
app/yarn.lock
File diff suppressed because it is too large
Load Diff
2658
dashboard/package-lock.json
generated
2658
dashboard/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB |
|
@ -24,7 +24,6 @@ const Features = ({ variables, setVariables }: any) => {
|
|||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Flex>
|
||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Email Verification:</Text>
|
||||
|
@ -53,7 +52,7 @@ const Features = ({ variables, setVariables }: any) => {
|
|||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Email Basic Authentication:</Text>
|
||||
<Text fontSize="sm">Basic Authentication:</Text>
|
||||
</Flex>
|
||||
<Flex justifyContent="start">
|
||||
<InputField
|
||||
|
@ -64,19 +63,6 @@ const Features = ({ variables, setVariables }: any) => {
|
|||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Mobile Basic Authentication:</Text>
|
||||
</Flex>
|
||||
<Flex justifyContent="start">
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={SwitchInputType.DISABLE_MOBILE_BASIC_AUTHENTICATION}
|
||||
hasReversedValue
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Sign Up:</Text>
|
||||
|
@ -111,7 +97,6 @@ const Features = ({ variables, setVariables }: any) => {
|
|||
also ignore the user MFA setting.
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex justifyContent="start" mb={3}>
|
||||
<InputField
|
||||
variables={variables}
|
||||
|
@ -121,41 +106,6 @@ const Features = ({ variables, setVariables }: any) => {
|
|||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
{!variables.DISABLE_MULTI_FACTOR_AUTHENTICATION && (
|
||||
<Flex alignItems="center">
|
||||
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||
<Text fontSize="sm">Time Based OTP (TOTP):</Text>
|
||||
<Text fontSize="x-small">Note: to enable totp mfa</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex justifyContent="start" mb={3}>
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={SwitchInputType.DISABLE_TOTP_LOGIN}
|
||||
hasReversedValue
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
{!variables.DISABLE_MULTI_FACTOR_AUTHENTICATION && (
|
||||
<Flex alignItems="center">
|
||||
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||
<Text fontSize="sm">EMAIL OTP:</Text>
|
||||
<Text fontSize="x-small">Note: to enable email otp mfa</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex justifyContent="start" mb={3}>
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={SwitchInputType.DISABLE_MAIL_OTP_LOGIN}
|
||||
hasReversedValue
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
<Flex alignItems="center">
|
||||
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||
<Text fontSize="sm">
|
||||
|
@ -174,19 +124,6 @@ const Features = ({ variables, setVariables }: any) => {
|
|||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Playground:</Text>
|
||||
</Flex>
|
||||
<Flex justifyContent="start">
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={SwitchInputType.DISABLE_PLAYGROUND}
|
||||
hasReversedValue
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Stack>
|
||||
<Divider paddingY={5} />
|
||||
<Text fontSize="md" paddingTop={5} fontWeight="bold" mb={5}>
|
||||
|
|
|
@ -17,8 +17,6 @@ import {
|
|||
FaApple,
|
||||
FaTwitter,
|
||||
FaMicrosoft,
|
||||
FaTwitch,
|
||||
FaDiscord,
|
||||
} from 'react-icons/fa';
|
||||
import {
|
||||
TextInputType,
|
||||
|
@ -310,44 +308,6 @@ const OAuthConfig = ({
|
|||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||
h="35px"
|
||||
marginRight="1.5%"
|
||||
border="1px solid #3b5998"
|
||||
borderRadius="5px"
|
||||
>
|
||||
<FaDiscord style={{ color: '#7289da' }} />
|
||||
</Center>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
marginRight="1.5%"
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={envVariables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.DISCORD_CLIENT_ID}
|
||||
placeholder="Discord Client ID"
|
||||
/>
|
||||
</Center>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={envVariables}
|
||||
setVariables={setVariables}
|
||||
fieldVisibility={fieldVisibility}
|
||||
setFieldVisibility={setFieldVisibility}
|
||||
inputType={HiddenInputType.DISCORD_CLIENT_SECRET}
|
||||
placeholder="Discord Client Secret"
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||
|
@ -437,85 +397,6 @@ const OAuthConfig = ({
|
|||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||
h="35px"
|
||||
marginRight="1.5%"
|
||||
border="1px solid #3b5998"
|
||||
borderRadius="5px"
|
||||
>
|
||||
<FaTwitch />
|
||||
</Center>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
marginRight="1.5%"
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={envVariables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.TWITCH_CLIENT_ID}
|
||||
placeholder="Twitch Client ID"
|
||||
/>
|
||||
</Center>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={envVariables}
|
||||
setVariables={setVariables}
|
||||
fieldVisibility={fieldVisibility}
|
||||
setFieldVisibility={setFieldVisibility}
|
||||
inputType={HiddenInputType.TWITCH_CLIENT_SECRET}
|
||||
placeholder="Twitch Client Secret"
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||
h="35px"
|
||||
marginRight="1.5%"
|
||||
border="1px solid #3b5998"
|
||||
borderRadius="5px"
|
||||
>
|
||||
<img
|
||||
src="https://authorizer.dev/_next/image?url=%2Fimages%2Froblox.png&w=25&q=25"
|
||||
alt="Roblox"
|
||||
/>
|
||||
</Center>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
marginRight="1.5%"
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={envVariables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.ROBLOX_CLIENT_ID}
|
||||
placeholder="Roblox Client ID"
|
||||
/>
|
||||
</Center>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={envVariables}
|
||||
setVariables={setVariables}
|
||||
fieldVisibility={fieldVisibility}
|
||||
setFieldVisibility={setFieldVisibility}
|
||||
inputType={HiddenInputType.ROBLOX_CLIENT_SECRET}
|
||||
placeholder="Roblox Client Secret"
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Box>
|
||||
</div>
|
||||
|
|
|
@ -9,12 +9,9 @@ export const TextInputType = {
|
|||
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
|
||||
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
|
||||
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
|
||||
DISCORD_CLIENT_ID: 'DISCORD_CLIENT_ID',
|
||||
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
|
||||
MICROSOFT_CLIENT_ID: 'MICROSOFT_CLIENT_ID',
|
||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: 'MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID',
|
||||
TWITCH_CLIENT_ID: 'TWITCH_CLIENT_ID',
|
||||
ROBLOX_CLIENT_ID: 'ROBLOX_CLIENT_ID',
|
||||
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
||||
REDIS_URL: 'REDIS_URL',
|
||||
SMTP_HOST: 'SMTP_HOST',
|
||||
|
@ -43,11 +40,8 @@ export const HiddenInputType = {
|
|||
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
|
||||
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
|
||||
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
||||
DISCORD_CLIENT_SECRET: 'DISCORD_CLIENT_SECRET',
|
||||
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
||||
MICROSOFT_CLIENT_SECRET: 'MICROSOFT_CLIENT_SECRET',
|
||||
TWITCH_CLIENT_SECRET: 'TWITCH_CLIENT_SECRET',
|
||||
ROBLOX_CLIENT_SECRET: 'ROBLOX_CLIENT_SECRET',
|
||||
JWT_SECRET: 'JWT_SECRET',
|
||||
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
||||
ADMIN_SECRET: 'ADMIN_SECRET',
|
||||
|
@ -85,15 +79,11 @@ export const SwitchInputType = {
|
|||
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
|
||||
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
|
||||
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: 'DISABLE_MOBILE_BASIC_AUTHENTICATION',
|
||||
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
|
||||
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
|
||||
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
|
||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: 'DISABLE_MULTI_FACTOR_AUTHENTICATION',
|
||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: 'ENFORCE_MULTI_FACTOR_AUTHENTICATION',
|
||||
DISABLE_PLAYGROUND: 'DISABLE_PLAYGROUND',
|
||||
DISABLE_TOTP_LOGIN: 'DISABLE_TOTP_LOGIN',
|
||||
DISABLE_MAIL_OTP_LOGIN: 'DISABLE_MAIL_OTP_LOGIN',
|
||||
};
|
||||
|
||||
export const DateInputType = {
|
||||
|
@ -134,17 +124,11 @@ export interface envVarTypes {
|
|||
LINKEDIN_CLIENT_SECRET: string;
|
||||
APPLE_CLIENT_ID: string;
|
||||
APPLE_CLIENT_SECRET: string;
|
||||
DISCORD_CLIENT_ID: string;
|
||||
DISCORD_CLIENT_SECRET: string;
|
||||
TWITTER_CLIENT_ID: string;
|
||||
TWITTER_CLIENT_SECRET: string;
|
||||
MICROSOFT_CLIENT_ID: string;
|
||||
MICROSOFT_CLIENT_SECRET: string;
|
||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: string;
|
||||
TWITCH_CLIENT_ID: string;
|
||||
TWITCH_CLIENT_SECRET: string;
|
||||
ROBLOX_CLIENT_ID: string;
|
||||
ROBLOX_CLIENT_SECRET: string;
|
||||
ROLES: [string] | [];
|
||||
DEFAULT_ROLES: [string] | [];
|
||||
PROTECTED_ROLES: [string] | [];
|
||||
|
@ -172,7 +156,6 @@ export interface envVarTypes {
|
|||
DISABLE_MAGIC_LINK_LOGIN: boolean;
|
||||
DISABLE_EMAIL_VERIFICATION: boolean;
|
||||
DISABLE_BASIC_AUTHENTICATION: boolean;
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: boolean;
|
||||
DISABLE_SIGN_UP: boolean;
|
||||
DISABLE_STRONG_PASSWORD: boolean;
|
||||
OLD_ADMIN_SECRET: string;
|
||||
|
@ -184,9 +167,6 @@ export interface envVarTypes {
|
|||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: boolean;
|
||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: string;
|
||||
DEFAULT_AUTHORIZE_RESPONSE_MODE: string;
|
||||
DISABLE_PLAYGROUND: boolean;
|
||||
DISABLE_TOTP_LOGIN: boolean;
|
||||
DISABLE_MAIL_OTP_LOGIN: boolean;
|
||||
}
|
||||
|
||||
export const envSubViews = {
|
||||
|
@ -240,7 +220,6 @@ export const webhookEventNames = {
|
|||
'User deleted': 'user.deleted',
|
||||
'User access enabled': 'user.access_enabled',
|
||||
'User access revoked': 'user.access_revoked',
|
||||
'User deactivated': 'user.deactivated',
|
||||
};
|
||||
|
||||
export const emailTemplateEventNames = {
|
||||
|
|
|
@ -30,17 +30,11 @@ export const EnvVariablesQuery = `
|
|||
LINKEDIN_CLIENT_SECRET
|
||||
APPLE_CLIENT_ID
|
||||
APPLE_CLIENT_SECRET
|
||||
DISCORD_CLIENT_ID
|
||||
DISCORD_CLIENT_SECRET
|
||||
TWITTER_CLIENT_ID
|
||||
TWITTER_CLIENT_SECRET
|
||||
MICROSOFT_CLIENT_ID
|
||||
MICROSOFT_CLIENT_SECRET
|
||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID
|
||||
TWITCH_CLIENT_ID
|
||||
TWITCH_CLIENT_SECRET
|
||||
ROBLOX_CLIENT_ID
|
||||
ROBLOX_CLIENT_SECRET
|
||||
DEFAULT_ROLES
|
||||
PROTECTED_ROLES
|
||||
ROLES
|
||||
|
@ -67,7 +61,6 @@ export const EnvVariablesQuery = `
|
|||
DISABLE_MAGIC_LINK_LOGIN
|
||||
DISABLE_EMAIL_VERIFICATION
|
||||
DISABLE_BASIC_AUTHENTICATION
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION
|
||||
DISABLE_SIGN_UP
|
||||
DISABLE_STRONG_PASSWORD
|
||||
DISABLE_REDIS_FOR_ENV
|
||||
|
@ -80,9 +73,6 @@ export const EnvVariablesQuery = `
|
|||
ENFORCE_MULTI_FACTOR_AUTHENTICATION
|
||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE
|
||||
DEFAULT_AUTHORIZE_RESPONSE_MODE
|
||||
DISABLE_PLAYGROUND
|
||||
DISABLE_TOTP_LOGIN
|
||||
DISABLE_MAIL_OTP_LOGIN
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -100,7 +90,6 @@ export const UserDetailsQuery = `
|
|||
id
|
||||
email
|
||||
email_verified
|
||||
phone_number_verified
|
||||
given_name
|
||||
family_name
|
||||
middle_name
|
||||
|
|
|
@ -50,17 +50,11 @@ const Environment = () => {
|
|||
LINKEDIN_CLIENT_SECRET: '',
|
||||
APPLE_CLIENT_ID: '',
|
||||
APPLE_CLIENT_SECRET: '',
|
||||
DISCORD_CLIENT_ID: '',
|
||||
DISCORD_CLIENT_SECRET: '',
|
||||
TWITTER_CLIENT_ID: '',
|
||||
TWITTER_CLIENT_SECRET: '',
|
||||
MICROSOFT_CLIENT_ID: '',
|
||||
MICROSOFT_CLIENT_SECRET: '',
|
||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: '',
|
||||
TWITCH_CLIENT_ID: '',
|
||||
TWITCH_CLIENT_SECRET: '',
|
||||
ROBLOX_CLIENT_ID: '',
|
||||
ROBLOX_CLIENT_SECRET: '',
|
||||
ROLES: [],
|
||||
DEFAULT_ROLES: [],
|
||||
PROTECTED_ROLES: [],
|
||||
|
@ -88,7 +82,6 @@ const Environment = () => {
|
|||
DISABLE_MAGIC_LINK_LOGIN: false,
|
||||
DISABLE_EMAIL_VERIFICATION: false,
|
||||
DISABLE_BASIC_AUTHENTICATION: false,
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: false,
|
||||
DISABLE_SIGN_UP: false,
|
||||
DISABLE_STRONG_PASSWORD: false,
|
||||
OLD_ADMIN_SECRET: '',
|
||||
|
@ -100,9 +93,6 @@ const Environment = () => {
|
|||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: false,
|
||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: '',
|
||||
DEFAULT_AUTHORIZE_RESPONSE_MODE: '',
|
||||
DISABLE_PLAYGROUND: false,
|
||||
DISABLE_TOTP_LOGIN: false,
|
||||
DISABLE_MAIL_OTP_LOGIN: true,
|
||||
});
|
||||
|
||||
const [fieldVisibility, setFieldVisibility] = React.useState<
|
||||
|
@ -113,9 +103,7 @@ const Environment = () => {
|
|||
FACEBOOK_CLIENT_SECRET: false,
|
||||
LINKEDIN_CLIENT_SECRET: false,
|
||||
APPLE_CLIENT_SECRET: false,
|
||||
DISCORD_CLIENT_SECRET: false,
|
||||
TWITTER_CLIENT_SECRET: false,
|
||||
TWITCH_CLIENT_SECRET: false,
|
||||
JWT_SECRET: false,
|
||||
SMTP_PASSWORD: false,
|
||||
ADMIN_SECRET: false,
|
||||
|
|
|
@ -165,25 +165,14 @@ export default function Users() {
|
|||
};
|
||||
|
||||
const userVerificationHandler = async (user: userDataTypes) => {
|
||||
const { id, email, phone_number } = user;
|
||||
let params = {};
|
||||
if (email) {
|
||||
params = {
|
||||
id,
|
||||
email,
|
||||
email_verified: true,
|
||||
};
|
||||
}
|
||||
if (phone_number) {
|
||||
params = {
|
||||
id,
|
||||
phone_number,
|
||||
phone_number_verified: true,
|
||||
};
|
||||
}
|
||||
const { id, email } = user;
|
||||
const res = await client
|
||||
.mutation(UpdateUser, {
|
||||
params,
|
||||
params: {
|
||||
id,
|
||||
email,
|
||||
email_verified: true,
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
if (res.error) {
|
||||
|
@ -309,7 +298,7 @@ export default function Users() {
|
|||
<Table variant="simple">
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>Email / Phone</Th>
|
||||
<Th>Email</Th>
|
||||
<Th>Created At</Th>
|
||||
<Th>Signup Methods</Th>
|
||||
<Th>Roles</Th>
|
||||
|
@ -325,15 +314,10 @@ export default function Users() {
|
|||
</Thead>
|
||||
<Tbody>
|
||||
{userList.map((user: userDataTypes) => {
|
||||
const {
|
||||
email_verified,
|
||||
phone_number_verified,
|
||||
created_at,
|
||||
...rest
|
||||
}: any = user;
|
||||
const { email_verified, created_at, ...rest }: any = user;
|
||||
return (
|
||||
<Tr key={user.id} style={{ fontSize: 14 }}>
|
||||
<Td maxW="300">{user.email || user.phone_number}</Td>
|
||||
<Td maxW="300">{user.email}</Td>
|
||||
<Td>
|
||||
{dayjs(user.created_at * 1000).format('MMM DD, YYYY')}
|
||||
</Td>
|
||||
|
@ -343,15 +327,9 @@ export default function Users() {
|
|||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme={
|
||||
user.email_verified || user.phone_number_verified
|
||||
? 'green'
|
||||
: 'yellow'
|
||||
}
|
||||
colorScheme={user.email_verified ? 'green' : 'yellow'}
|
||||
>
|
||||
{(
|
||||
user.email_verified || user.phone_number_verified
|
||||
).toString()}
|
||||
{user.email_verified.toString()}
|
||||
</Tag>
|
||||
</Td>
|
||||
<Td>
|
||||
|
@ -390,14 +368,13 @@ export default function Users() {
|
|||
</Flex>
|
||||
</MenuButton>
|
||||
<MenuList>
|
||||
{!user.email_verified &&
|
||||
!user.phone_number_verified && (
|
||||
<MenuItem
|
||||
onClick={() => userVerificationHandler(user)}
|
||||
>
|
||||
Verify User
|
||||
</MenuItem>
|
||||
)}
|
||||
{!user.email_verified && (
|
||||
<MenuItem
|
||||
onClick={() => userVerificationHandler(user)}
|
||||
>
|
||||
Verify User
|
||||
</MenuItem>
|
||||
)}
|
||||
<EditUserModal
|
||||
user={rest}
|
||||
updateUserList={updateUserList}
|
||||
|
|
2248
dashboard/yarn.lock
2248
dashboard/yarn.lock
File diff suppressed because it is too large
Load Diff
20
go.mod
20
go.mod
|
@ -1,20 +0,0 @@
|
|||
module server
|
||||
|
||||
go 1.21.5
|
||||
|
||||
require (
|
||||
github.com/99designs/gqlgen v0.17.43 // indirect
|
||||
github.com/agnivade/levenshtein v1.1.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sosodev/duration v1.1.0 // indirect
|
||||
github.com/urfave/cli/v2 v2.25.5 // indirect
|
||||
github.com/vektah/gqlparser/v2 v2.5.11 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
golang.org/x/mod v0.10.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/tools v0.9.3 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
31
go.sum
31
go.sum
|
@ -1,31 +0,0 @@
|
|||
github.com/99designs/gqlgen v0.17.43 h1:I4SYg6ahjowErAQcHFVKy5EcWuwJ3+Xw9z2fLpuFCPo=
|
||||
github.com/99designs/gqlgen v0.17.43/go.mod h1:lO0Zjy8MkZgBdv4T1U91x09r0e0WFOdhVUutlQs1Rsc=
|
||||
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
|
||||
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sosodev/duration v1.1.0 h1:kQcaiGbJaIsRqgQy7VGlZrVw1giWO+lDoX3MCPnpVO4=
|
||||
github.com/sosodev/duration v1.1.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
|
||||
github.com/urfave/cli/v2 v2.25.5 h1:d0NIAyhh5shGscroL7ek/Ya9QYQE0KNabJgiUinIQkc=
|
||||
github.com/urfave/cli/v2 v2.25.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||
github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8=
|
||||
github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
|
||||
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -1,25 +0,0 @@
|
|||
package providers
|
||||
|
||||
import "context"
|
||||
|
||||
// AuthenticatorConfig defines authenticator config
|
||||
type AuthenticatorConfig struct {
|
||||
// ScannerImage is the base64 of QR code image
|
||||
ScannerImage string
|
||||
// Secrets is the secret key
|
||||
Secret string
|
||||
// RecoveryCode is the list of recovery codes
|
||||
RecoveryCodes []string
|
||||
// RecoveryCodeMap is the map of recovery codes
|
||||
RecoveryCodeMap map[string]bool
|
||||
}
|
||||
|
||||
// Provider defines authenticators provider
|
||||
type Provider interface {
|
||||
// Generate totp: to generate totp, store secret into db and returns base64 of QR code image
|
||||
Generate(ctx context.Context, id string) (*AuthenticatorConfig, error)
|
||||
// Validate totp: user passcode with secret stored in our db
|
||||
Validate(ctx context.Context, passcode string, userID string) (bool, error)
|
||||
// ValidateRecoveryCode totp: allows user to validate using recovery code incase if they lost their device
|
||||
ValidateRecoveryCode(ctx context.Context, recoveryCode, userID string) (bool, error)
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package totp
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type provider struct {
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// TOTPConfig defines totp config
|
||||
type TOTPConfig struct {
|
||||
ScannerImage string
|
||||
Secret string
|
||||
}
|
||||
|
||||
// NewProvider returns a new totp provider
|
||||
func NewProvider() (*provider, error) {
|
||||
ctx := context.Background()
|
||||
return &provider{
|
||||
ctx: ctx,
|
||||
}, nil
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
package totp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image/png"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pquerna/otp/totp"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/authenticators/providers"
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/crypto"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
)
|
||||
|
||||
// Generate generates a Time-Based One-Time Password (TOTP) for a user and returns the base64-encoded QR code for frontend display.
|
||||
func (p *provider) Generate(ctx context.Context, id string) (*providers.AuthenticatorConfig, error) {
|
||||
var buf bytes.Buffer
|
||||
//get user details
|
||||
user, err := db.Provider.GetUserByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// generate totp, Authenticators hash is valid for 30 seconds
|
||||
key, err := totp.Generate(totp.GenerateOpts{
|
||||
Issuer: "authorizer",
|
||||
AccountName: refs.StringValue(user.Email),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//generating image for key and encoding to base64 for displaying in frontend
|
||||
img, err := key.Image(200, 200)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
png.Encode(&buf, img)
|
||||
encodedText := crypto.EncryptB64(buf.String())
|
||||
secret := key.Secret()
|
||||
recoveryCodes := []string{}
|
||||
for i := 0; i < 10; i++ {
|
||||
recoveryCodes = append(recoveryCodes, uuid.NewString())
|
||||
}
|
||||
// Converting recoveryCodes to string
|
||||
recoverCodesMap := map[string]bool{}
|
||||
for i := 0; i < len(recoveryCodes); i++ {
|
||||
recoverCodesMap[recoveryCodes[i]] = false
|
||||
}
|
||||
// Converting recoveryCodesMap to string
|
||||
jsonData, err := json.Marshal(recoverCodesMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
recoveryCodesString := string(jsonData)
|
||||
totpModel := &models.Authenticator{
|
||||
Secret: secret,
|
||||
RecoveryCodes: refs.NewStringRef(recoveryCodesString),
|
||||
UserID: user.ID,
|
||||
Method: constants.EnvKeyTOTPAuthenticator,
|
||||
}
|
||||
authenticator, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, user.ID, constants.EnvKeyTOTPAuthenticator)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get authenticator details by user id, creating new record: ", err)
|
||||
// continue
|
||||
}
|
||||
if authenticator == nil {
|
||||
// if authenticator is nil then create new authenticator
|
||||
_, err = db.Provider.AddAuthenticator(ctx, totpModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
authenticator.Secret = secret
|
||||
authenticator.RecoveryCodes = refs.NewStringRef(recoveryCodesString)
|
||||
// if authenticator is not nil then update authenticator
|
||||
_, err = db.Provider.UpdateAuthenticator(ctx, authenticator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &providers.AuthenticatorConfig{
|
||||
ScannerImage: encodedText,
|
||||
Secret: secret,
|
||||
RecoveryCodes: recoveryCodes,
|
||||
RecoveryCodeMap: recoverCodesMap,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Validate validates a Time-Based One-Time Password (TOTP) against the stored TOTP secret for a user.
|
||||
func (p *provider) Validate(ctx context.Context, passcode string, userID string) (bool, error) {
|
||||
// get totp details
|
||||
totpModel, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, userID, constants.EnvKeyTOTPAuthenticator)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// validate totp
|
||||
status := totp.Validate(passcode, totpModel.Secret)
|
||||
// checks if user not signed in for totp and totp code is correct then VerifiedAt will be stored in db
|
||||
if totpModel.VerifiedAt == nil && status {
|
||||
timeNow := time.Now().Unix()
|
||||
totpModel.VerifiedAt = &timeNow
|
||||
_, err = db.Provider.UpdateAuthenticator(ctx, totpModel)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// ValidateRecoveryCode validates a Time-Based One-Time Password (TOTP) recovery code against the stored TOTP recovery code for a user.
|
||||
func (p *provider) ValidateRecoveryCode(ctx context.Context, recoveryCode, userID string) (bool, error) {
|
||||
// get totp details
|
||||
totpModel, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, userID, constants.EnvKeyTOTPAuthenticator)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// convert recoveryCodes to map
|
||||
recoveryCodesMap := map[string]bool{}
|
||||
err = json.Unmarshal([]byte(refs.StringValue(totpModel.RecoveryCodes)), &recoveryCodesMap)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// check if recovery code is valid
|
||||
if val, ok := recoveryCodesMap[recoveryCode]; !ok {
|
||||
return false, fmt.Errorf("invalid recovery code")
|
||||
} else if val {
|
||||
return false, fmt.Errorf("recovery code already used")
|
||||
}
|
||||
// update recovery code map
|
||||
recoveryCodesMap[recoveryCode] = true
|
||||
// convert recoveryCodesMap to string
|
||||
jsonData, err := json.Marshal(recoveryCodesMap)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
recoveryCodesString := string(jsonData)
|
||||
totpModel.RecoveryCodes = refs.NewStringRef(recoveryCodesString)
|
||||
// update recovery code map in db
|
||||
_, err = db.Provider.UpdateAuthenticator(ctx, totpModel)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package authenticators
|
||||
|
||||
import (
|
||||
"github.com/authorizerdev/authorizer/server/authenticators/providers"
|
||||
"github.com/authorizerdev/authorizer/server/authenticators/providers/totp"
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
)
|
||||
|
||||
// Provider is the global authenticators provider.
|
||||
var Provider providers.Provider
|
||||
|
||||
// InitTOTPStore initializes the TOTP authenticator store if it's not disabled in the environment variables.
|
||||
// It sets the global Provider variable to a new TOTP provider.
|
||||
func InitTOTPStore() error {
|
||||
var err error
|
||||
isTOTPEnvServiceDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin)
|
||||
|
||||
if !isTOTPEnvServiceDisabled {
|
||||
Provider, err = totp.NewProvider()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -19,14 +19,8 @@ const (
|
|||
AuthRecipeMethodLinkedIn = "linkedin"
|
||||
// AuthRecipeMethodApple is the apple auth method
|
||||
AuthRecipeMethodApple = "apple"
|
||||
// AuthRecipeMethodDiscord is the discord auth method
|
||||
AuthRecipeMethodDiscord = "discord"
|
||||
// AuthRecipeMethodTwitter is the twitter auth method
|
||||
AuthRecipeMethodTwitter = "twitter"
|
||||
// AuthRecipeMethodMicrosoft is the microsoft auth method
|
||||
AuthRecipeMethodMicrosoft = "microsoft"
|
||||
// AuthRecipeMethodTwitch is the twitch auth method
|
||||
AuthRecipeMethodTwitch = "twitch"
|
||||
// AuthRecipeMethodRoblox is the roblox auth method
|
||||
AuthRecipeMethodRoblox = "roblox"
|
||||
)
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package constants
|
||||
|
||||
// Authenticators Methods
|
||||
const (
|
||||
// EnvKeyTOTPAuthenticator key for env variable TOTP
|
||||
EnvKeyTOTPAuthenticator = "totp"
|
||||
)
|
|
@ -5,6 +5,4 @@ const (
|
|||
AppCookieName = "cookie"
|
||||
// AdminCookieName is the name of the cookie that is used to store the admin token
|
||||
AdminCookieName = "authorizer-admin"
|
||||
// MfaCookieName is the name of the cookie that is used to store the mfa session
|
||||
MfaCookieName = "mfa"
|
||||
)
|
||||
|
|
|
@ -5,8 +5,6 @@ const (
|
|||
DbTypePostgres = "postgres"
|
||||
// DbTypeSqlite is the sqlite database type
|
||||
DbTypeSqlite = "sqlite"
|
||||
// DbTypeLibSQL is the libsql / Turso database type
|
||||
DbTypeLibSQL = "libsql"
|
||||
// DbTypeMysql is the mysql database type
|
||||
DbTypeMysql = "mysql"
|
||||
// DbTypeSqlserver is the sqlserver database type
|
||||
|
|
|
@ -108,10 +108,6 @@ const (
|
|||
EnvKeyAppleClientID = "APPLE_CLIENT_ID"
|
||||
// EnvKeyAppleClientSecret key for env variable APPLE_CLIENT_SECRET
|
||||
EnvKeyAppleClientSecret = "APPLE_CLIENT_SECRET"
|
||||
// EnvKeyDiscordClientID key for env variable DISCORD_CLIENT_ID
|
||||
EnvKeyDiscordClientID = "DISCORD_CLIENT_ID"
|
||||
// EnvKeyDiscordClientSecret key for env variable DISCORD_CLIENT_SECRET
|
||||
EnvKeyDiscordClientSecret = "DISCORD_CLIENT_SECRET"
|
||||
// EnvKeyTwitterClientID key for env variable TWITTER_CLIENT_ID
|
||||
EnvKeyTwitterClientID = "TWITTER_CLIENT_ID"
|
||||
// EnvKeyTwitterClientSecret key for env variable TWITTER_CLIENT_SECRET
|
||||
|
@ -122,14 +118,6 @@ const (
|
|||
EnvKeyMicrosoftActiveDirectoryTenantID = "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID"
|
||||
// EnvKeyMicrosoftClientSecret key for env variable MICROSOFT_CLIENT_SECRET
|
||||
EnvKeyMicrosoftClientSecret = "MICROSOFT_CLIENT_SECRET"
|
||||
// EnvKeyTwitchClientID key for env variable TWITCH_CLIENT_ID
|
||||
EnvKeyTwitchClientID = "TWITCH_CLIENT_ID"
|
||||
// EnvKeyTwitchClientSecret key for env variable TWITCH_CLIENT_SECRET
|
||||
EnvKeyTwitchClientSecret = "TWITCH_CLIENT_SECRET"
|
||||
// EnvKeyRobloxClientID key for env variable ROBLOX_CLIENT_ID
|
||||
EnvKeyRobloxClientID = "ROBLOX_CLIENT_ID"
|
||||
// EnvKeyRobloxClientSecret key for env variable ROBLOX_CLIENT_SECRET
|
||||
EnvKeyRobloxClientSecret = "ROBLOX_CLIENT_SECRET"
|
||||
// EnvKeyOrganizationName key for env variable ORGANIZATION_NAME
|
||||
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
||||
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
||||
|
@ -172,18 +160,9 @@ const (
|
|||
// EnvKeyDisableMultiFactorAuthentication is key for env variable DISABLE_MULTI_FACTOR_AUTHENTICATION
|
||||
// this variable is used to completely disable multi factor authentication. It will have no effect on profile preference
|
||||
EnvKeyDisableMultiFactorAuthentication = "DISABLE_MULTI_FACTOR_AUTHENTICATION"
|
||||
// EnvKeyDisableTOTPLogin is key for env variable DISABLE_TOTP_LOGIN
|
||||
// this variable is used to completely disable totp verification
|
||||
EnvKeyDisableTOTPLogin = "DISABLE_TOTP_LOGIN"
|
||||
// EnvKeyDisableMailOTPLogin is key for env variable DISABLE_MAIL_OTP_LOGIN
|
||||
// this variable is used to completely disable totp verification
|
||||
EnvKeyDisableMailOTPLogin = "DISABLE_MAIL_OTP_LOGIN"
|
||||
// EnvKeyDisablePhoneVerification is key for env variable DISABLE_PHONE_VERIFICATION
|
||||
// this variable is used to disable phone verification
|
||||
EnvKeyDisablePhoneVerification = "DISABLE_PHONE_VERIFICATION"
|
||||
// EnvKeyDisablePlayGround is key for env variable DISABLE_PLAYGROUND
|
||||
// this variable will disable or enable playground use in dashboard
|
||||
EnvKeyDisablePlayGround = "DISABLE_PLAYGROUND"
|
||||
|
||||
// Slice variables
|
||||
// EnvKeyRoles key for env variable ROLES
|
||||
|
|
|
@ -16,7 +16,4 @@ const (
|
|||
ResponseTypeToken = "token"
|
||||
// For the Implicit grant of id_token, use response_type=id_token to include an identifier token.
|
||||
ResponseTypeIDToken = "id_token"
|
||||
|
||||
// Constant indicating the "signup" screen hint for customizing authentication process and redirect to a signup page.
|
||||
ScreenHintSignUp = "signup"
|
||||
)
|
||||
|
|
|
@ -17,10 +17,6 @@ const (
|
|||
|
||||
TwitterUserInfoURL = "https://api.twitter.com/2/users/me?user.fields=id,name,profile_image_url,username"
|
||||
|
||||
// RobloxUserInfoURL is the URL to get user info from Roblox
|
||||
RobloxUserInfoURL = "https://apis.roblox.com/oauth/v1/userinfo"
|
||||
|
||||
DiscordUserInfoURL = "https://discord.com/api/oauth2/@me"
|
||||
// Get microsoft user info.
|
||||
// Ref: https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo
|
||||
MicrosoftUserInfoURL = "https://graph.microsoft.com/oidc/userinfo"
|
||||
|
|
|
@ -15,6 +15,4 @@ const (
|
|||
UserAccessEnabledWebhookEvent = `user.access_enabled`
|
||||
// UserDeletedWebhookEvent name for user deleted event
|
||||
UserDeletedWebhookEvent = `user.deleted`
|
||||
// UserDeactivatedWebhookEvent name for user deactivated event
|
||||
UserDeactivatedWebhookEvent = `user.deactivated`
|
||||
)
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
package cookie
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/parsers"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// SetMfaSession sets the mfa session cookie in the response
|
||||
func SetMfaSession(gc *gin.Context, sessionID string) {
|
||||
appCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAppCookieSecure)
|
||||
if err != nil {
|
||||
log.Debug("Error while getting app cookie secure from env variable: %v", err)
|
||||
appCookieSecure = true
|
||||
}
|
||||
|
||||
secure := appCookieSecure
|
||||
httpOnly := appCookieSecure
|
||||
hostname := parsers.GetHost(gc)
|
||||
host, _ := parsers.GetHostParts(hostname)
|
||||
domain := parsers.GetDomainName(hostname)
|
||||
if domain != "localhost" {
|
||||
domain = "." + domain
|
||||
}
|
||||
|
||||
// Since app cookie can come from cross site it becomes important to set this in lax mode when insecure.
|
||||
// Example person using custom UI on their app domain and making request to authorizer domain.
|
||||
// For more information check:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
|
||||
// https://github.com/gin-gonic/gin/blob/master/context.go#L86
|
||||
// TODO add ability to sameSite = none / strict from dashboard
|
||||
if !appCookieSecure {
|
||||
gc.SetSameSite(http.SameSiteLaxMode)
|
||||
} else {
|
||||
gc.SetSameSite(http.SameSiteNoneMode)
|
||||
}
|
||||
// TODO allow configuring from dashboard
|
||||
age := 60
|
||||
|
||||
gc.SetCookie(constants.MfaCookieName+"_session", sessionID, age, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(constants.MfaCookieName+"_session_domain", sessionID, age, "/", domain, secure, httpOnly)
|
||||
}
|
||||
|
||||
// DeleteMfaSession deletes the mfa session cookies to expire
|
||||
func DeleteMfaSession(gc *gin.Context) {
|
||||
appCookieSecure, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyAppCookieSecure)
|
||||
if err != nil {
|
||||
log.Debug("Error while getting app cookie secure from env variable: %v", err)
|
||||
appCookieSecure = true
|
||||
}
|
||||
|
||||
secure := appCookieSecure
|
||||
httpOnly := appCookieSecure
|
||||
hostname := parsers.GetHost(gc)
|
||||
host, _ := parsers.GetHostParts(hostname)
|
||||
domain := parsers.GetDomainName(hostname)
|
||||
if domain != "localhost" {
|
||||
domain = "." + domain
|
||||
}
|
||||
|
||||
gc.SetSameSite(http.SameSiteNoneMode)
|
||||
gc.SetCookie(constants.MfaCookieName+"_session", "", -1, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(constants.MfaCookieName+"_session_domain", "", -1, "/", domain, secure, httpOnly)
|
||||
}
|
||||
|
||||
// GetMfaSession gets the mfa session cookie from context
|
||||
func GetMfaSession(gc *gin.Context) (string, error) {
|
||||
var cookie *http.Cookie
|
||||
var err error
|
||||
cookie, err = gc.Request.Cookie(constants.MfaCookieName + "_session")
|
||||
if err != nil {
|
||||
cookie, err = gc.Request.Cookie(constants.MfaCookieName + "_session_domain")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
decodedValue, err := url.PathUnescape(cookie.Value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return decodedValue, nil
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
|
@ -127,27 +125,12 @@ func EncryptEnvData(data map[string]interface{}) (string, error) {
|
|||
return EncryptB64(string(encryptedConfig)), nil
|
||||
}
|
||||
|
||||
// getSHA256 calculates the SHA-256 hash of a string
|
||||
func getSHA256(input string) string {
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte(input))
|
||||
return hex.EncodeToString(hash.Sum(nil))
|
||||
}
|
||||
|
||||
// VerifyPassword compares a stored hashed password with a user-provided password
|
||||
func VerifyPassword(storedHashedPassword, userProvidedPassword string) error {
|
||||
// CompareHashAndPassword returns nil on success
|
||||
passwordSHA256 := getSHA256(userProvidedPassword)
|
||||
err := bcrypt.CompareHashAndPassword([]byte(storedHashedPassword), []byte(passwordSHA256))
|
||||
return err
|
||||
}
|
||||
|
||||
// EncryptPassword is used for encrypting password
|
||||
func EncryptPassword(password string) (string, error) {
|
||||
passwordSHA256 := getSHA256(password)
|
||||
pw, err := bcrypt.GenerateFromPassword([]byte(passwordSHA256), bcrypt.DefaultCost)
|
||||
pw, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(pw), nil
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@ package crypto
|
|||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
)
|
||||
|
@ -118,24 +116,3 @@ func AsRSAStr(privateKey *rsa.PrivateKey, publickKey *rsa.PublicKey) (string, st
|
|||
|
||||
return privParsedPem, pubParsedPem, nil
|
||||
}
|
||||
|
||||
func EncryptRSA(message string, key rsa.PublicKey) (string, error) {
|
||||
label := []byte("OAEP Encrypted")
|
||||
rng := rand.Reader
|
||||
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rng, &key, []byte(message), label)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||||
}
|
||||
|
||||
func DecryptRSA(cipherText string, privateKey rsa.PrivateKey) (string, error) {
|
||||
ct, _ := base64.StdEncoding.DecodeString(cipherText)
|
||||
label := []byte("OAEP Encrypted")
|
||||
rng := rand.Reader
|
||||
plaintext, err := rsa.DecryptOAEP(sha256.New(), rng, &privateKey, ct, label)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(plaintext), nil
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ func InitDB() error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if isArangoDB {
|
||||
log.Info("Initializing ArangoDB Driver")
|
||||
Provider, err = arangodb.NewProvider()
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
package models
|
||||
|
||||
// Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation
|
||||
|
||||
// Authenticators model for db
|
||||
type Authenticator struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||
UserID string `gorm:"type:char(36)" json:"user_id" bson:"user_id" cql:"user_id" dynamo:"user_id" index:"user_id,hash"`
|
||||
Method string `json:"method" bson:"method" cql:"method" dynamo:"method"`
|
||||
Secret string `json:"secret" bson:"secret" cql:"secret" dynamo:"secret"`
|
||||
RecoveryCodes *string `json:"recovery_codes" bson:"recovery_codes" cql:"recovery_codes" dynamo:"recovery_codes"`
|
||||
VerifiedAt *int64 `json:"verified_at" bson:"verified_at" cql:"verified_at" dynamo:"verified_at"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package models
|
||||
|
||||
// CollectionList / Tables available for authorizer in the database
|
||||
// Collections / Tables available for authorizer in the database
|
||||
type CollectionList struct {
|
||||
User string
|
||||
VerificationRequest string
|
||||
|
@ -11,7 +11,6 @@ type CollectionList struct {
|
|||
EmailTemplate string
|
||||
OTP string
|
||||
SMSVerificationRequest string
|
||||
Authenticators string
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -28,6 +27,5 @@ var (
|
|||
EmailTemplate: Prefix + "email_templates",
|
||||
OTP: Prefix + "otps",
|
||||
SMSVerificationRequest: Prefix + "sms_verification_requests",
|
||||
Authenticators: Prefix + "authenticators",
|
||||
}
|
||||
)
|
||||
|
|
|
@ -11,8 +11,8 @@ const (
|
|||
type OTP struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||
Email string `gorm:"index" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
||||
PhoneNumber string `gorm:"index" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number"`
|
||||
Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
||||
PhoneNumber string `gorm:"index:unique_index_phone_number,unique" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number"`
|
||||
Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"`
|
||||
ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||
|
|
|
@ -15,7 +15,7 @@ type User struct {
|
|||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||
|
||||
Email *string `gorm:"index" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
||||
Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
||||
EmailVerifiedAt *int64 `json:"email_verified_at" bson:"email_verified_at" cql:"email_verified_at" dynamo:"email_verified_at"`
|
||||
Password *string `json:"password" bson:"password" cql:"password" dynamo:"password"`
|
||||
SignupMethods string `json:"signup_methods" bson:"signup_methods" cql:"signup_methods" dynamo:"signup_methods"`
|
||||
|
@ -33,14 +33,12 @@ type User struct {
|
|||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled" bson:"is_multi_factor_auth_enabled" cql:"is_multi_factor_auth_enabled" dynamo:"is_multi_factor_auth_enabled"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||
AppData *string `json:"app_data" bson:"app_data" cql:"app_data" dynamo:"app_data"`
|
||||
}
|
||||
|
||||
func (user *User) AsAPIUser() *model.User {
|
||||
isEmailVerified := user.EmailVerifiedAt != nil
|
||||
isPhoneVerified := user.PhoneNumberVerifiedAt != nil
|
||||
appDataMap := make(map[string]interface{})
|
||||
json.Unmarshal([]byte(refs.StringValue(user.AppData)), &appDataMap)
|
||||
|
||||
// id := user.ID
|
||||
// if strings.Contains(id, Collections.User+"/") {
|
||||
// id = strings.TrimPrefix(id, Collections.User+"/")
|
||||
|
@ -54,7 +52,7 @@ func (user *User) AsAPIUser() *model.User {
|
|||
FamilyName: user.FamilyName,
|
||||
MiddleName: user.MiddleName,
|
||||
Nickname: user.Nickname,
|
||||
PreferredUsername: user.Email,
|
||||
PreferredUsername: refs.NewStringRef(user.Email),
|
||||
Gender: user.Gender,
|
||||
Birthdate: user.Birthdate,
|
||||
PhoneNumber: user.PhoneNumber,
|
||||
|
@ -65,7 +63,6 @@ func (user *User) AsAPIUser() *model.User {
|
|||
IsMultiFactorAuthEnabled: user.IsMultiFactorAuthEnabled,
|
||||
CreatedAt: refs.NewInt64Ref(user.CreatedAt),
|
||||
UpdatedAt: refs.NewInt64Ref(user.UpdatedAt),
|
||||
AppData: appDataMap,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
package arangodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
arangoDriver "github.com/arangodb/go-driver"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
)
|
||||
|
||||
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||
if exists != nil {
|
||||
return authenticators, nil
|
||||
}
|
||||
if authenticators.ID == "" {
|
||||
authenticators.ID = uuid.New().String()
|
||||
}
|
||||
|
||||
authenticators.Key = authenticators.ID
|
||||
authenticators.CreatedAt = time.Now().Unix()
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
|
||||
authenticatorsCollection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
||||
meta, err := authenticatorsCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authenticators.Key = meta.Key
|
||||
authenticators.ID = meta.ID.String()
|
||||
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
|
||||
collection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
||||
meta, err := collection.UpdateDocument(ctx, authenticators.Key, authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
authenticators.Key = meta.Key
|
||||
authenticators.ID = meta.ID.String()
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||
var authenticators *models.Authenticator
|
||||
query := fmt.Sprintf("FOR d in %s FILTER d.user_id == @user_id AND d.method == @method LIMIT 1 RETURN d", models.Collections.Authenticators)
|
||||
bindVars := map[string]interface{}{
|
||||
"user_id": userId,
|
||||
"method": authenticatorType,
|
||||
}
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
if !cursor.HasMore() {
|
||||
if authenticators == nil {
|
||||
return authenticators, fmt.Errorf("authenticator not found")
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(ctx, &authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
|
@ -23,7 +23,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er
|
|||
configCollection, _ := p.db.Collection(ctx, models.Collections.Env)
|
||||
meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
env.Key = meta.Key
|
||||
env.ID = meta.ID.String()
|
||||
|
@ -36,7 +36,7 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env,
|
|||
collection, _ := p.db.Collection(ctx, models.Collections.Env)
|
||||
meta, err := collection.UpdateDocument(ctx, env.Key, env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
|
||||
env.Key = meta.Key
|
||||
|
@ -50,7 +50,7 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
|||
query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.Env)
|
||||
cursor, err := p.db.Query(ctx, query, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
|
@ -62,7 +62,7 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
|||
}
|
||||
_, err := cursor.ReadDocument(ctx, &env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -186,7 +186,6 @@ func NewProvider() (*provider, error) {
|
|||
webhookLogCollection.EnsureHashIndex(ctx, []string{"webhook_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
emailTemplateCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.EmailTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -205,7 +204,6 @@ func NewProvider() (*provider, error) {
|
|||
Unique: true,
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
otpCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.OTP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -224,26 +222,6 @@ func NewProvider() (*provider, error) {
|
|||
Unique: true,
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
//authenticators table define
|
||||
authenticatorsCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !authenticatorsCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.Authenticators, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
authenticatorsCollection, err := arangodb.Collection(ctx, models.Collections.Authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authenticatorsCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
return &provider{
|
||||
db: arangodb,
|
||||
}, err
|
||||
|
|
|
@ -27,7 +27,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
|
@ -36,10 +36,6 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
|
@ -47,7 +43,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||
meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
user.Key = meta.Key
|
||||
user.ID = meta.ID.String()
|
||||
|
@ -62,7 +58,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||
meta, err := collection.UpdateDocument(ctx, user.Key, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
user.Key = meta.Key
|
||||
|
@ -129,19 +125,19 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
|||
}
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
if !cursor.HasMore() {
|
||||
if user == nil {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
return user, fmt.Errorf("user not found")
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(ctx, &user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
}
|
||||
return user, nil
|
||||
|
@ -156,19 +152,19 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
|||
}
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
if !cursor.HasMore() {
|
||||
if user == nil {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
return user, fmt.Errorf("user not found")
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(ctx, &user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
}
|
||||
return user, nil
|
||||
|
|
|
@ -22,7 +22,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
|||
verificationRequestRequestCollection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
|
||||
meta, err := verificationRequestRequestCollection.CreateDocument(ctx, verificationRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
verificationRequest.Key = meta.Key
|
||||
verificationRequest.ID = meta.ID.String()
|
||||
|
@ -38,7 +38,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
|||
}
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
|
@ -50,7 +50,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
|||
}
|
||||
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
}
|
||||
return verificationRequest, nil
|
||||
|
@ -66,7 +66,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
|||
}
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
|
@ -78,7 +78,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
|||
}
|
||||
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
}
|
||||
return verificationRequest, nil
|
||||
|
|
|
@ -1,133 +0,0 @@
|
|||
package cassandradb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
)
|
||||
|
||||
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||
if exists != nil {
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
if authenticators.ID == "" {
|
||||
authenticators.ID = uuid.New().String()
|
||||
}
|
||||
|
||||
authenticators.CreatedAt = time.Now().Unix()
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
|
||||
bytes, err := json.Marshal(authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||
decoder.UseNumber()
|
||||
authenticatorsMap := map[string]interface{}{}
|
||||
err = decoder.Decode(&authenticatorsMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fields := "("
|
||||
values := "("
|
||||
for key, value := range authenticatorsMap {
|
||||
if value != nil {
|
||||
if key == "_id" {
|
||||
fields += "id,"
|
||||
} else {
|
||||
fields += key + ","
|
||||
}
|
||||
|
||||
valueType := reflect.TypeOf(value)
|
||||
if valueType.Name() == "string" {
|
||||
values += fmt.Sprintf("'%s',", value.(string))
|
||||
} else {
|
||||
values += fmt.Sprintf("%v,", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fields = fields[:len(fields)-1] + ")"
|
||||
values = values[:len(values)-1] + ")"
|
||||
|
||||
query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.Authenticators, fields, values)
|
||||
err = p.db.Query(query).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
|
||||
bytes, err := json.Marshal(authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||
decoder.UseNumber()
|
||||
authenticatorsMap := map[string]interface{}{}
|
||||
err = decoder.Decode(&authenticatorsMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updateFields := ""
|
||||
for key, value := range authenticatorsMap {
|
||||
if key == "_id" {
|
||||
continue
|
||||
}
|
||||
|
||||
if key == "_key" {
|
||||
continue
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
updateFields += fmt.Sprintf("%s = null, ", key)
|
||||
continue
|
||||
}
|
||||
|
||||
valueType := reflect.TypeOf(value)
|
||||
if valueType.Name() == "string" {
|
||||
updateFields += fmt.Sprintf("%s = '%s', ", key, value.(string))
|
||||
} else {
|
||||
updateFields += fmt.Sprintf("%s = %v, ", key, value)
|
||||
}
|
||||
}
|
||||
updateFields = strings.Trim(updateFields, " ")
|
||||
updateFields = strings.TrimSuffix(updateFields, ",")
|
||||
|
||||
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Authenticators, updateFields, authenticators.ID)
|
||||
err = p.db.Query(query).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||
var authenticators models.Authenticator
|
||||
query := fmt.Sprintf("SELECT id, user_id, method, secret, recovery_codes, verified_at, created_at, updated_at FROM %s WHERE user_id = '%s' AND method = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.Authenticators, userId, authenticatorType)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&authenticators.ID, &authenticators.UserID, &authenticators.Method, &authenticators.Secret, &authenticators.RecoveryCodes, &authenticators.VerifiedAt, &authenticators.CreatedAt, &authenticators.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &authenticators, nil
|
||||
}
|
|
@ -20,7 +20,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er
|
|||
insertEnvQuery := fmt.Sprintf("INSERT INTO %s (id, env, hash, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.Env, env.ID, env.EnvData, env.Hash, env.CreatedAt, env.UpdatedAt)
|
||||
err := p.db.Query(insertEnvQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
|
||||
return env, nil
|
||||
|
@ -32,7 +32,7 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env,
|
|||
updateEnvQuery := fmt.Sprintf("UPDATE %s SET env = '%s', updated_at = %d WHERE id = '%s'", KeySpace+"."+models.Collections.Env, env.EnvData, env.UpdatedAt, env.ID)
|
||||
err := p.db.Query(updateEnvQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
|
|
@ -261,26 +261,12 @@ func NewProvider() (*provider, error) {
|
|||
log.Debug("Failed to alter table as column exists: ", err)
|
||||
// continue
|
||||
}
|
||||
// Add app_data column to users table
|
||||
appDataAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD (app_data text);`, KeySpace, models.Collections.User)
|
||||
err = session.Query(appDataAlterQuery).Exec()
|
||||
if err != nil {
|
||||
log.Debug("Failed to alter user table as app_data column exists: ", err)
|
||||
// continue
|
||||
}
|
||||
// Add phone number index
|
||||
otpIndexQueryPhoneNumber := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_otp_phone_number ON %s.%s (phone_number)", KeySpace, models.Collections.OTP)
|
||||
err = session.Query(otpIndexQueryPhoneNumber).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// add authenticators table
|
||||
totpCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, user_id text, method text, secret text, recovery_codes text, verified_at bigint, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.Authenticators)
|
||||
err = session.Query(totpCollectionQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &provider{
|
||||
db: session,
|
||||
}, err
|
||||
|
|
|
@ -26,7 +26,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
|
@ -35,10 +35,6 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
|
@ -46,7 +42,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
|
||||
bytes, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
|
@ -55,7 +51,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
userMap := map[string]interface{}{}
|
||||
err = decoder.Decode(&userMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
fields := "("
|
||||
|
@ -82,9 +78,8 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
|
||||
query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.User, fields, values)
|
||||
err = p.db.Query(query).Exec()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
|
@ -96,7 +91,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
|
||||
bytes, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||
|
@ -104,7 +99,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
userMap := map[string]interface{}{}
|
||||
err = decoder.Decode(&userMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
updateFields := ""
|
||||
|
@ -135,7 +130,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, updateFields, user.ID)
|
||||
err = p.db.Query(query).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
|
@ -182,17 +177,13 @@ func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination)
|
|||
// there is no offset in cassandra
|
||||
// so we fetch till limit + offset
|
||||
// and return the results from offset to limit
|
||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.User,
|
||||
pagination.Limit+pagination.Offset)
|
||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.User, pagination.Limit+pagination.Offset)
|
||||
scanner := p.db.Query(query).Iter().Scanner()
|
||||
counter := int64(0)
|
||||
for scanner.Next() {
|
||||
if counter >= pagination.Offset {
|
||||
var user models.User
|
||||
err := scanner.Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods,
|
||||
&user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber,
|
||||
&user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled,
|
||||
&user.AppData, &user.CreatedAt, &user.UpdatedAt)
|
||||
err := scanner.Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.CreatedAt, &user.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -209,8 +200,8 @@ func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination)
|
|||
// GetUserByEmail to get user information from database using email address
|
||||
func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) {
|
||||
var user models.User
|
||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, email)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.AppData, &user.CreatedAt, &user.UpdatedAt)
|
||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, email)
|
||||
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
|
||||
}
|
||||
|
@ -220,8 +211,8 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
|||
// GetUserByID to get user information from database using user ID
|
||||
func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) {
|
||||
var user models.User
|
||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1", KeySpace+"."+models.Collections.User, id)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.AppData, &user.CreatedAt, &user.UpdatedAt)
|
||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1", KeySpace+"."+models.Collections.User, id)
|
||||
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
|
||||
}
|
||||
|
@ -306,15 +297,17 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUserByPhoneNumber to get user information from database using phone number
|
||||
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||
var user models.User
|
||||
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, phoneNumber)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.AppData, &user.CreatedAt, &user.UpdatedAt)
|
||||
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
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
|||
query := fmt.Sprintf("INSERT INTO %s (id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, '%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.VerificationRequest, verificationRequest.ID, verificationRequest.Token, verificationRequest.Identifier, verificationRequest.ExpiresAt, verificationRequest.Email, verificationRequest.Nonce, verificationRequest.RedirectURI, verificationRequest.CreatedAt, verificationRequest.UpdatedAt)
|
||||
err := p.db.Query(query).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination *mod
|
|||
var verificationRequest models.VerificationRequest
|
||||
err := scanner.Scan(&verificationRequest.ID, &verificationRequest.Token, &verificationRequest.Identifier, &verificationRequest.ExpiresAt, &verificationRequest.Email, &verificationRequest.Nonce, &verificationRequest.RedirectURI, &verificationRequest.CreatedAt, &verificationRequest.UpdatedAt)
|
||||
if err != nil {
|
||||
fmt.Println("=> getting error here...", err)
|
||||
return nil, err
|
||||
}
|
||||
verificationRequests = append(verificationRequests, verificationRequest.AsAPIVerificationRequest())
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
)
|
||||
|
||||
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||
if exists != nil {
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
if authenticators.ID == "" {
|
||||
authenticators.ID = uuid.New().String()
|
||||
}
|
||||
authenticators.Key = authenticators.ID
|
||||
authenticators.CreatedAt = time.Now().Unix()
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
insertOpt := gocb.InsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.Authenticators).Insert(authenticators.ID, authenticators, &insertOpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
bytes, err := json.Marshal(authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||
decoder.UseNumber()
|
||||
authenticator := map[string]interface{}{}
|
||||
err = decoder.Decode(&authenticator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updateFields, params := GetSetFields(authenticator)
|
||||
query := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = '%s'", p.scopeName, models.Collections.Authenticators, updateFields, authenticators.ID)
|
||||
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
NamedParameters: params,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||
var authenticators *models.Authenticator
|
||||
query := fmt.Sprintf("SELECT _id, user_id, method, secret, recovery_code, verified_at, created_at, updated_at FROM %s.%s WHERE user_id = $1 AND method = $2 LIMIT 1", p.scopeName, models.Collections.Authenticators)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{userId, authenticatorType},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = q.One(&authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
|
@ -24,7 +24,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.Env).Insert(env.ID, env, &insertOpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env,
|
|||
PositionalParameters: []interface{}{env.EnvData, env.UpdatedAt, env.UpdatedAt, env.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -55,11 +55,11 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
|||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
err = q.One(&env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
env.Hash = env.EncryptionKey
|
||||
return env, nil
|
||||
|
|
|
@ -50,7 +50,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.OTP).Insert(otp.ID, otp, &insertOpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return otp, err
|
||||
}
|
||||
} else {
|
||||
query := fmt.Sprintf(`UPDATE %s.%s SET otp=$1, expires_at=$2, updated_at=$3 WHERE _id=$4`, p.scopeName, models.Collections.OTP)
|
||||
|
@ -58,7 +58,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
|||
PositionalParameters: []interface{}{otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return otp, err
|
||||
}
|
||||
}
|
||||
return otp, nil
|
||||
|
|
|
@ -127,7 +127,7 @@ func CreateBucketAndScope(cluster *gocb.Cluster, bucketName string, scopeName st
|
|||
if scopeName != defaultScope {
|
||||
err = bucket.Collections().CreateScope(scopeName, nil)
|
||||
if err != nil && !errors.Is(err, gocb.ErrScopeExists) {
|
||||
return nil, err
|
||||
return bucket, err
|
||||
}
|
||||
}
|
||||
return bucket, nil
|
||||
|
|
|
@ -47,7 +47,7 @@ func (p *provider) GetTotalDocs(ctx context.Context, collection string) (int64,
|
|||
})
|
||||
queryRes.One(&totalDocs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return totalDocs.Total, err
|
||||
}
|
||||
return totalDocs.Total, nil
|
||||
}
|
||||
|
|
|
@ -4,14 +4,12 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
@ -25,21 +23,11 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
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 && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
insertOpt := gocb.InsertOptions{
|
||||
|
@ -47,7 +35,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.User).Insert(user.ID, user, &insertOpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -55,12 +43,12 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
// UpdateUser to update user information in database
|
||||
func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) {
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
upsertOpt := gocb.UpsertOptions{
|
||||
unsertOpt := gocb.UpsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &upsertOpt)
|
||||
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &unsertOpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -81,7 +69,7 @@ func (p *provider) DeleteUser(ctx context.Context, user *models.User) error {
|
|||
func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination) (*model.Users, error) {
|
||||
users := []*model.User{}
|
||||
paginationClone := pagination
|
||||
userQuery := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s ORDER BY id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.User)
|
||||
userQuery := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s ORDER BY id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.User)
|
||||
queryResult, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
|
@ -115,18 +103,18 @@ func (p *provider) ListUsers(ctx context.Context, pagination *model.Pagination)
|
|||
// GetUserByEmail to get user information from database using email address
|
||||
func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.User, error) {
|
||||
var user *models.User
|
||||
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{email},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
err = q.One(&user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -134,18 +122,18 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
|||
// GetUserByID to get user information from database using user ID
|
||||
func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, error) {
|
||||
var user *models.User
|
||||
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{id},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
err = q.One(&user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -187,18 +175,18 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
|||
// GetUserByPhoneNumber to get user information from database using phone number
|
||||
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||
var user *models.User
|
||||
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, app_data, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||
query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{phoneNumber},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
err = q.One(&user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.VerificationRequest).Insert(verificationRequest.ID, verificationRequest, &insertOpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
@ -44,12 +44,12 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
err = queryResult.One(&verificationRequest)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
|||
var verificationRequest *models.VerificationRequest
|
||||
err = queryResult.One(&verificationRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*mo
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.Webhook).Insert(webhook.ID, webhook, &insertOpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return webhook.AsAPIWebhook(), err
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.Webhook
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.WebhookLog).Insert(webhookLog.ID, webhookLog, &insertOpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return webhookLog.AsAPIWebhookLog(), err
|
||||
}
|
||||
return webhookLog.AsAPIWebhookLog(), nil
|
||||
}
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
package dynamodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
)
|
||||
|
||||
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||
if exists != nil {
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
collection := p.db.Table(models.Collections.Authenticators)
|
||||
if authenticators.ID == "" {
|
||||
authenticators.ID = uuid.New().String()
|
||||
}
|
||||
|
||||
authenticators.CreatedAt = time.Now().Unix()
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
err := collection.Put(authenticators).RunWithContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
collection := p.db.Table(models.Collections.Authenticators)
|
||||
if authenticators.ID != "" {
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
err := UpdateByHashKey(collection, "id", authenticators.ID, authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return authenticators, nil
|
||||
|
||||
}
|
||||
|
||||
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||
var authenticators *models.Authenticator
|
||||
collection := p.db.Table(models.Collections.Authenticators)
|
||||
iter := collection.Scan().Filter("'user_id' = ?", userId).Filter("'method' = ?", authenticatorType).Iter()
|
||||
for iter.NextWithContext(ctx, &authenticators) {
|
||||
return authenticators, nil
|
||||
}
|
||||
err := iter.Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
|
@ -21,7 +21,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er
|
|||
env.UpdatedAt = time.Now().Unix()
|
||||
err := collection.Put(env).RunWithContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env,
|
|||
env.UpdatedAt = time.Now().Unix()
|
||||
err := UpdateByHashKey(collection, "id", env.ID, env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
|||
iter := collection.Scan().Limit(1).Iter()
|
||||
for iter.NextWithContext(ctx, &env) {
|
||||
if env == nil {
|
||||
return nil, errors.New("no documets found")
|
||||
return env, errors.New("no documets found")
|
||||
} else {
|
||||
return env, nil
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ func NewProvider() (*provider, error) {
|
|||
db.CreateTable(models.Collections.VerificationRequest, models.VerificationRequest{}).Wait()
|
||||
db.CreateTable(models.Collections.Webhook, models.Webhook{}).Wait()
|
||||
db.CreateTable(models.Collections.WebhookLog, models.WebhookLog{}).Wait()
|
||||
db.CreateTable(models.Collections.Authenticators, models.Authenticator{}).Wait()
|
||||
return &provider{
|
||||
db: db,
|
||||
}, nil
|
||||
|
|
|
@ -26,24 +26,20 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
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 && u.ID != user.ID {
|
||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
err := collection.Put(user).RunWithContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -55,8 +51,12 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
user.UpdatedAt = time.Now().Unix()
|
||||
err := UpdateByHashKey(collection, "id", user.ID, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
|||
user = users[0]
|
||||
return user, nil
|
||||
} else {
|
||||
return nil, errors.New("no record found")
|
||||
return user, errors.New("no record found")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,8 +136,8 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
|||
var user *models.User
|
||||
err := collection.Get("id", id).OneWithContext(ctx, &user)
|
||||
if err != nil {
|
||||
if refs.StringValue(user.Email) == "" {
|
||||
return nil, errors.New("no documets found")
|
||||
if user.Email == "" {
|
||||
return user, errors.New("no documets found")
|
||||
} else {
|
||||
return user, nil
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
|||
verificationRequest.UpdatedAt = time.Now().Unix()
|
||||
err := collection.Put(verificationRequest).RunWithContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
}
|
||||
return verificationRequest, nil
|
||||
|
@ -35,7 +35,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
|||
}
|
||||
err := iter.Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
|||
}
|
||||
err := iter.Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model
|
|||
return nil, err
|
||||
}
|
||||
if webhook.ID == "" {
|
||||
return nil, errors.New("no documets found")
|
||||
return webhook.AsAPIWebhook(), errors.New("no documets found")
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package mongodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
)
|
||||
|
||||
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||
if exists != nil {
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
if authenticators.ID == "" {
|
||||
authenticators.ID = uuid.New().String()
|
||||
}
|
||||
authenticators.CreatedAt = time.Now().Unix()
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
authenticators.Key = authenticators.ID
|
||||
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||
_, err := authenticatorsCollection.InsertOne(ctx, authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||
_, err := authenticatorsCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": authenticators.ID}}, bson.M{"$set": authenticators})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||
var authenticators *models.Authenticator
|
||||
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||
err := authenticatorsCollection.FindOne(ctx, bson.M{"user_id": userId, "method": authenticatorType}).Decode(&authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
|
@ -22,7 +22,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er
|
|||
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||
_, err := configCollection.InsertOne(ctx, env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env,
|
|||
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||
_, err := configCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -44,13 +44,13 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
|||
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||
cursor, err := configCollection.Find(ctx, bson.M{}, options.Find())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
for cursor.Next(nil) {
|
||||
err := cursor.Decode(&env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return env, err
|
||||
}
|
||||
}
|
||||
if env == nil {
|
||||
|
|
|
@ -47,6 +47,8 @@ func NewProvider() (*provider, error) {
|
|||
Keys: bson.M{"email": 1},
|
||||
Options: options.Index().SetUnique(true).SetSparse(true),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
userCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.M{"phone_number": 1},
|
||||
Options: options.Index().SetUnique(true).SetSparse(true).SetPartialFilterExpression(map[string]interface{}{
|
||||
|
@ -54,6 +56,7 @@ func NewProvider() (*provider, error) {
|
|||
}),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
|
||||
mongodb.CreateCollection(ctx, models.Collections.VerificationRequest, options.CreateCollection())
|
||||
verificationRequestCollection := mongodb.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||
verificationRequestCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
|
@ -122,15 +125,6 @@ func NewProvider() (*provider, error) {
|
|||
},
|
||||
}, options.CreateIndexes())
|
||||
|
||||
mongodb.CreateCollection(ctx, models.Collections.Authenticators, options.CreateCollection())
|
||||
authenticatorsCollection := mongodb.Collection(models.Collections.Authenticators, options.Collection())
|
||||
authenticatorsCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.M{"user_id": 1},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
|
||||
return &provider{
|
||||
db: mongodb,
|
||||
}, nil
|
||||
|
|
|
@ -2,15 +2,12 @@ package mongodb
|
|||
|
||||
import (
|
||||
"context"
|
||||
"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"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
|
@ -26,26 +23,17 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
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 && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
user.Key = user.ID
|
||||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||
_, err := userCollection.InsertOne(ctx, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -56,7 +44,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||
_, err := userCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -115,7 +103,7 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
|||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||
err := userCollection.FindOne(ctx, bson.M{"email": email}).Decode(&user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -126,7 +114,7 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
|||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||
err := userCollection.FindOne(ctx, bson.M{"_id": id}).Decode(&user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
|||
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||
_, err := verificationRequestCollection.InsertOne(ctx, verificationRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
|||
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||
err := verificationRequestCollection.FindOne(ctx, bson.M{"token": token}).Decode(&verificationRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
|
||||
return verificationRequest, nil
|
||||
|
@ -49,7 +49,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
|||
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||
err := verificationRequestCollection.FindOne(ctx, bson.M{"email": email, "identifier": identifier}).Decode(&verificationRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return verificationRequest, err
|
||||
}
|
||||
|
||||
return verificationRequest, nil
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package provider_template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
)
|
||||
|
||||
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||
if exists != nil {
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
if authenticators.ID == "" {
|
||||
authenticators.ID = uuid.New().String()
|
||||
}
|
||||
authenticators.CreatedAt = time.Now().Unix()
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||
var authenticators *models.Authenticator
|
||||
return authenticators, nil
|
||||
}
|
|
@ -2,15 +2,12 @@ package provider_template
|
|||
|
||||
import (
|
||||
"context"
|
||||
"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"
|
||||
)
|
||||
|
||||
|
@ -22,19 +19,10 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
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 && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
return user, nil
|
||||
|
|
|
@ -26,7 +26,7 @@ type Provider interface {
|
|||
// If ids set to nil / empty all the users will be updated
|
||||
UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error
|
||||
|
||||
// AddVerificationRequest to save verification request in database
|
||||
// AddVerification to save verification request in database
|
||||
AddVerificationRequest(ctx context.Context, verificationRequest *models.VerificationRequest) (*models.VerificationRequest, error)
|
||||
// GetVerificationRequestByToken to get verification request from database using token
|
||||
GetVerificationRequestByToken(ctx context.Context, token string) (*models.VerificationRequest, error)
|
||||
|
@ -53,7 +53,7 @@ type Provider interface {
|
|||
AddWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error)
|
||||
// UpdateWebhook to update webhook
|
||||
UpdateWebhook(ctx context.Context, webhook *models.Webhook) (*model.Webhook, error)
|
||||
// ListWebhook to list webhook
|
||||
// ListWebhooks to list webhook
|
||||
ListWebhook(ctx context.Context, pagination *model.Pagination) (*model.Webhooks, error)
|
||||
// GetWebhookByID to get webhook by id
|
||||
GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error)
|
||||
|
@ -71,7 +71,7 @@ type Provider interface {
|
|||
AddEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error)
|
||||
// UpdateEmailTemplate to update EmailTemplate
|
||||
UpdateEmailTemplate(ctx context.Context, emailTemplate *models.EmailTemplate) (*model.EmailTemplate, error)
|
||||
// ListEmailTemplate to list EmailTemplate
|
||||
// ListEmailTemplates to list EmailTemplate
|
||||
ListEmailTemplate(ctx context.Context, pagination *model.Pagination) (*model.EmailTemplates, error)
|
||||
// GetEmailTemplateByID to get EmailTemplate by id
|
||||
GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error)
|
||||
|
@ -88,15 +88,4 @@ type Provider interface {
|
|||
GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error)
|
||||
// DeleteOTP to delete otp
|
||||
DeleteOTP(ctx context.Context, otp *models.OTP) error
|
||||
|
||||
// AddAuthenticator adds a new authenticator document to the database.
|
||||
// If the authenticator doesn't have an ID, a new one is generated.
|
||||
// The created document is returned, or an error if the operation fails.
|
||||
AddAuthenticator(ctx context.Context, totp *models.Authenticator) (*models.Authenticator, error)
|
||||
// UpdateAuthenticator updates an existing authenticator document in the database.
|
||||
// The updated document is returned, or an error if the operation fails.
|
||||
UpdateAuthenticator(ctx context.Context, totp *models.Authenticator) (*models.Authenticator, error)
|
||||
// GetAuthenticatorDetailsByUserId retrieves details of an authenticator document based on user ID and authenticator type.
|
||||
// If found, the authenticator document is returned, or an error if not found or an error occurs during the retrieval.
|
||||
GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error)
|
||||
}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
)
|
||||
|
||||
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||
if exists != nil {
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
if authenticators.ID == "" {
|
||||
authenticators.ID = uuid.New().String()
|
||||
}
|
||||
authenticators.Key = authenticators.ID
|
||||
authenticators.CreatedAt = time.Now().Unix()
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
res := p.db.Clauses(
|
||||
clause.OnConflict{
|
||||
UpdateAll: true,
|
||||
Columns: []clause.Column{{Name: "id"}},
|
||||
}).Create(&authenticators)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
result := p.db.Save(&authenticators)
|
||||
if result.Error != nil {
|
||||
return authenticators, result.Error
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||
var authenticators models.Authenticator
|
||||
result := p.db.Where("user_id = ?", userId).Where("method = ?", authenticatorType).First(&authenticators)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
return &authenticators, nil
|
||||
}
|
|
@ -7,56 +7,33 @@ import (
|
|||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// UpsertOTP to add or update otp
|
||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||
if otpParam.ID == "" {
|
||||
otpParam.ID = uuid.New().String()
|
||||
func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, error) {
|
||||
if otp.ID == "" {
|
||||
otp.ID = uuid.New().String()
|
||||
}
|
||||
// check if email or phone number is present
|
||||
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||
if otp.Email == "" && otp.PhoneNumber == "" {
|
||||
return nil, errors.New("email or phone_number is required")
|
||||
}
|
||||
uniqueField := models.FieldNameEmail
|
||||
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||
if otp.Email == "" && otp.PhoneNumber != "" {
|
||||
uniqueField = models.FieldNamePhoneNumber
|
||||
}
|
||||
var otp *models.OTP
|
||||
if uniqueField == models.FieldNameEmail {
|
||||
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||
} else {
|
||||
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||
}
|
||||
shouldCreate := false
|
||||
if otp == nil {
|
||||
id := uuid.NewString()
|
||||
otp = &models.OTP{
|
||||
ID: id,
|
||||
Key: id,
|
||||
Otp: otpParam.Otp,
|
||||
Email: otpParam.Email,
|
||||
PhoneNumber: otpParam.PhoneNumber,
|
||||
ExpiresAt: otpParam.ExpiresAt,
|
||||
CreatedAt: time.Now().Unix(),
|
||||
}
|
||||
shouldCreate = true
|
||||
} else {
|
||||
otp.Otp = otpParam.Otp
|
||||
otp.ExpiresAt = otpParam.ExpiresAt
|
||||
}
|
||||
otp.Key = otp.ID
|
||||
otp.CreatedAt = time.Now().Unix()
|
||||
otp.UpdatedAt = time.Now().Unix()
|
||||
if shouldCreate {
|
||||
result := p.db.Create(&otp)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
} else {
|
||||
result := p.db.Save(&otp)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
res := p.db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: uniqueField}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"otp", "expires_at", "updated_at"}),
|
||||
}).Create(&otp)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
|
||||
return otp, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
libsql "github.com/ekristen/gorm-libsql"
|
||||
"github.com/glebarez/sqlite"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gorm.io/driver/mysql"
|
||||
|
@ -61,8 +60,6 @@ func NewProvider() (*provider, error) {
|
|||
sqlDB, err = gorm.Open(postgres.Open(dbURL), ormConfig)
|
||||
case constants.DbTypeSqlite:
|
||||
sqlDB, err = gorm.Open(sqlite.Open(dbURL+"?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)"), ormConfig)
|
||||
case constants.DbTypeLibSQL:
|
||||
sqlDB, err = gorm.Open(libsql.Open(dbURL), ormConfig)
|
||||
case constants.DbTypeMysql, constants.DbTypeMariaDB, constants.DbTypePlanetScaleDB:
|
||||
sqlDB, err = gorm.Open(mysql.Open(dbURL), ormConfig)
|
||||
case constants.DbTypeSqlserver:
|
||||
|
@ -80,7 +77,7 @@ func NewProvider() (*provider, error) {
|
|||
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{}, &models.Authenticator{})
|
||||
err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}, &models.Webhook{}, &models.WebhookLog{}, &models.EmailTemplate{}, &models.OTP{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// AddUser to save user information in database
|
||||
|
@ -24,25 +25,25 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
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 && u.ID != user.ID {
|
||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
user.Key = user.ID
|
||||
result := p.db.Create(&user)
|
||||
result := p.db.Clauses(
|
||||
clause.OnConflict{
|
||||
UpdateAll: true,
|
||||
Columns: []clause.Column{{Name: "email"}},
|
||||
}).Create(&user)
|
||||
|
||||
if result.Error != nil {
|
||||
return user, result.Error
|
||||
|
@ -112,7 +113,7 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
|||
var user *models.User
|
||||
result := p.db.Where("email = ?", email).First(&user)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
return user, result.Error
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -122,7 +123,7 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
|||
var user *models.User
|
||||
result := p.db.Where("id = ?", id).First(&user)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
return user, result.Error
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
@ -73,6 +72,7 @@ func getEmailTemplate(event string, data map[string]interface{}) (*model.EmailTe
|
|||
return nil, err
|
||||
}
|
||||
subjectString := buf.String()
|
||||
|
||||
return &model.EmailTemplate{
|
||||
Template: templateString,
|
||||
Subject: subjectString,
|
||||
|
@ -92,16 +92,10 @@ func SendEmail(to []string, event string, data map[string]interface{}) error {
|
|||
|
||||
tmp, err := getEmailTemplate(event, data)
|
||||
if err != nil {
|
||||
log.Error("Failed to get event template: ", err)
|
||||
log.Errorf("Failed to get event template: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
mailgunAPIKey := os.Getenv("MAILGUN_API_KEY")
|
||||
|
||||
if len(mailgunAPIKey) > 0 {
|
||||
return SendMailgun(to, event, data)
|
||||
}
|
||||
|
||||
m := gomail.NewMessage()
|
||||
senderEmail, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySenderEmail)
|
||||
if err != nil {
|
||||
|
|
|
@ -53,13 +53,13 @@ const (
|
|||
<table width="100%%" cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.organization.logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
||||
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.org_logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
||||
</tr>
|
||||
|
||||
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
|
||||
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
|
||||
<p>Hey there 👋</p>
|
||||
<p>We have received request to verify email for <b>{{.organization.name}}</b>. If this is correct, please confirm your email address by clicking the button below.</p> <br/>
|
||||
<p>We have received request to verify email for <b>{{.org_name}}</b>. If this is correct, please confirm your email address by clicking the button below.</p> <br/>
|
||||
<a
|
||||
clicktracking="off" href="{{.verification_url}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Confirm Email</a>
|
||||
</td>
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
package email
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
mailgun "github.com/mailgun/mailgun-go/v4"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
)
|
||||
|
||||
const apiURL = "https://api.mailgun.net/v3/%s/messages"
|
||||
|
||||
func MailgunRest(to string, data map[string]interface{}, subject string, template string) error {
|
||||
var mailgunAPIKey = os.Getenv("MAILGUN_API_KEY")
|
||||
var mailgunDomain = os.Getenv("MAILGUN_DOMAIN")
|
||||
sender := mailgunDomain + "<noreply@" + mailgunDomain + ">"
|
||||
log.Printf("%r", data)
|
||||
mg := mailgun.NewMailgun(mailgunDomain, mailgunAPIKey)
|
||||
m := mg.NewMessage(sender, subject, "", to)
|
||||
m.SetTemplate(template)
|
||||
m.AddTemplateVariable("verification_url", data["verification_url"])
|
||||
userMap, ok := data["user"].(map[string]interface{})
|
||||
if !ok {
|
||||
log.Println("Error: Unable to retrieve user information from the data map.")
|
||||
}
|
||||
userName, ok := userMap["GivenName"].(string)
|
||||
if ok {
|
||||
m.AddTemplateVariable("username", userName)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
||||
defer cancel()
|
||||
|
||||
resp, id, err := mg.Send(ctx, m)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("ID: %s Resp: %s\n", id, resp)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// SendMailgun function to send
|
||||
func SendMailgun(to []string, event string, data map[string]interface{}) error {
|
||||
template := "authorizer_email_confirmation"
|
||||
|
||||
switch event {
|
||||
case constants.VerificationTypeBasicAuthSignup:
|
||||
template = "authorizer_email_confirmation"
|
||||
case constants.VerificationTypeForgotPassword:
|
||||
template = "authorizer_password_reset"
|
||||
case constants.VerificationTypeInviteMember:
|
||||
template = "author_invited"
|
||||
case constants.VerificationTypeMagicLinkLogin:
|
||||
template = "magic_link_login"
|
||||
case constants.VerificationTypeOTP:
|
||||
template = "one_time_password"
|
||||
case constants.VerificationTypeUpdateEmail:
|
||||
template = "email_update"
|
||||
}
|
||||
|
||||
subject := "Подтверждение почты"
|
||||
|
||||
// TODO: language selection logic here
|
||||
|
||||
err := MailgunRest(to[0], data, subject, template)
|
||||
|
||||
// Log the response
|
||||
if err != nil {
|
||||
log.Printf("Error sending email: %v", err)
|
||||
} else {
|
||||
log.Println("Email sent successfully")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
85
server/env/env.go
vendored
85
server/env/env.go
vendored
|
@ -79,10 +79,6 @@ func InitAllEnv() error {
|
|||
osMicrosoftClientID := os.Getenv(constants.EnvKeyMicrosoftClientID)
|
||||
osMicrosoftClientSecret := os.Getenv(constants.EnvKeyMicrosoftClientSecret)
|
||||
osMicrosoftActiveDirectoryTenantID := os.Getenv(constants.EnvKeyMicrosoftActiveDirectoryTenantID)
|
||||
osTwitchClientID := os.Getenv(constants.EnvKeyTwitchClientID)
|
||||
osTwitchClientSecret := os.Getenv(constants.EnvKeyTwitchClientSecret)
|
||||
osRobloxClientID := os.Getenv(constants.EnvKeyTwitchClientID)
|
||||
osRobloxClientSecret := os.Getenv(constants.EnvKeyTwitchClientSecret)
|
||||
osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL)
|
||||
osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName)
|
||||
osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo)
|
||||
|
@ -108,12 +104,8 @@ func InitAllEnv() error {
|
|||
osDisableStrongPassword := os.Getenv(constants.EnvKeyDisableStrongPassword)
|
||||
osEnforceMultiFactorAuthentication := os.Getenv(constants.EnvKeyEnforceMultiFactorAuthentication)
|
||||
osDisableMultiFactorAuthentication := os.Getenv(constants.EnvKeyDisableMultiFactorAuthentication)
|
||||
osDisableTOTPLogin := os.Getenv(constants.EnvKeyDisableTOTPLogin)
|
||||
osDisableMailOTPLogin := os.Getenv(constants.EnvKeyDisableMailOTPLogin)
|
||||
// phone verification var
|
||||
osDisablePhoneVerification := os.Getenv(constants.EnvKeyDisablePhoneVerification)
|
||||
osDisablePlayground := os.Getenv(constants.EnvKeyDisablePlayGround)
|
||||
|
||||
// twilio vars
|
||||
osTwilioApiKey := os.Getenv(constants.EnvKeyTwilioAPIKey)
|
||||
osTwilioApiSecret := os.Getenv(constants.EnvKeyTwilioAPISecret)
|
||||
|
@ -505,34 +497,6 @@ func InitAllEnv() error {
|
|||
envData[constants.EnvKeyMicrosoftActiveDirectoryTenantID] = osMicrosoftActiveDirectoryTenantID
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyTwitchClientID]; !ok || val == "" {
|
||||
envData[constants.EnvKeyTwitchClientID] = osTwitchClientID
|
||||
}
|
||||
if osTwitchClientID != "" && envData[constants.EnvKeyTwitchClientID] != osTwitchClientID {
|
||||
envData[constants.EnvKeyTwitchClientID] = osTwitchClientID
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyTwitchClientSecret]; !ok || val == "" {
|
||||
envData[constants.EnvKeyTwitchClientSecret] = osTwitchClientSecret
|
||||
}
|
||||
if osTwitchClientSecret != "" && envData[constants.EnvKeyTwitchClientSecret] != osTwitchClientSecret {
|
||||
envData[constants.EnvKeyTwitchClientSecret] = osTwitchClientSecret
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyRobloxClientID]; !ok || val == "" {
|
||||
envData[constants.EnvKeyRobloxClientID] = osRobloxClientID
|
||||
}
|
||||
if osRobloxClientID != "" && envData[constants.EnvKeyRobloxClientID] != osRobloxClientID {
|
||||
envData[constants.EnvKeyRobloxClientID] = osRobloxClientID
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyRobloxClientSecret]; !ok || val == "" {
|
||||
envData[constants.EnvKeyRobloxClientSecret] = osRobloxClientSecret
|
||||
}
|
||||
if osRobloxClientSecret != "" && envData[constants.EnvKeyRobloxClientSecret] != osRobloxClientSecret {
|
||||
envData[constants.EnvKeyRobloxClientSecret] = osRobloxClientSecret
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" {
|
||||
envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/")
|
||||
}
|
||||
|
@ -723,13 +687,20 @@ func InitAllEnv() error {
|
|||
envData[constants.EnvKeyDisableEmailVerification] = true
|
||||
envData[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||
envData[constants.EnvKeyIsEmailServiceEnabled] = false
|
||||
envData[constants.EnvKeyDisableMailOTPLogin] = true
|
||||
}
|
||||
|
||||
if envData[constants.EnvKeySmtpHost] != "" && envData[constants.EnvKeySmtpUsername] != "" && envData[constants.EnvKeySmtpPassword] != "" && envData[constants.EnvKeySenderEmail] != "" && envData[constants.EnvKeySmtpPort] != "" {
|
||||
envData[constants.EnvKeyIsEmailServiceEnabled] = true
|
||||
}
|
||||
|
||||
if envData[constants.EnvKeyEnforceMultiFactorAuthentication].(bool) && !envData[constants.EnvKeyIsEmailServiceEnabled].(bool) && !envData[constants.EnvKeyIsSMSServiceEnabled].(bool) {
|
||||
return errors.New("to enable multi factor authentication, please enable email service")
|
||||
}
|
||||
|
||||
if !envData[constants.EnvKeyIsEmailServiceEnabled].(bool) {
|
||||
envData[constants.EnvKeyDisableMultiFactorAuthentication] = true
|
||||
}
|
||||
|
||||
if envData[constants.EnvKeyDisableEmailVerification].(bool) {
|
||||
envData[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||
}
|
||||
|
@ -854,46 +825,6 @@ func InitAllEnv() error {
|
|||
envData[constants.EnvKeyIsSMSServiceEnabled] = true
|
||||
}
|
||||
|
||||
if _, ok := envData[constants.EnvKeyDisablePlayGround]; !ok {
|
||||
envData[constants.EnvKeyDisablePlayGround] = osDisablePlayground == "true"
|
||||
}
|
||||
if osDisablePlayground != "" {
|
||||
boolValue, err := strconv.ParseBool(osDisablePlayground)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if boolValue != envData[constants.EnvKeyDisablePlayGround].(bool) {
|
||||
envData[constants.EnvKeyDisablePlayGround] = boolValue
|
||||
}
|
||||
}
|
||||
// TODO: remove after beta launch
|
||||
envData[constants.EnvKeyDisableTOTPLogin] = true
|
||||
if _, ok := envData[constants.EnvKeyDisableTOTPLogin]; !ok {
|
||||
envData[constants.EnvKeyDisableTOTPLogin] = osDisableTOTPLogin == "true"
|
||||
}
|
||||
if osDisableTOTPLogin != "" {
|
||||
boolValue, err := strconv.ParseBool(osDisableTOTPLogin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if boolValue != envData[constants.EnvKeyDisableTOTPLogin].(bool) {
|
||||
envData[constants.EnvKeyDisableTOTPLogin] = boolValue
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := envData[constants.EnvKeyDisableMailOTPLogin]; !ok {
|
||||
envData[constants.EnvKeyDisableMailOTPLogin] = osDisableMailOTPLogin == "true"
|
||||
}
|
||||
if osDisableMailOTPLogin != "" {
|
||||
boolValue, err := strconv.ParseBool(osDisableMailOTPLogin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if boolValue != envData[constants.EnvKeyDisableMailOTPLogin].(bool) {
|
||||
envData[constants.EnvKeyDisableMailOTPLogin] = boolValue
|
||||
}
|
||||
}
|
||||
|
||||
err = memorystore.Provider.UpdateEnvStore(envData)
|
||||
if err != nil {
|
||||
log.Debug("Error while updating env store: ", err)
|
||||
|
|
11
server/env/persist_env.go
vendored
11
server/env/persist_env.go
vendored
|
@ -196,7 +196,7 @@ func PersistEnv() error {
|
|||
envValue := strings.TrimSpace(os.Getenv(key))
|
||||
if envValue != "" {
|
||||
switch key {
|
||||
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyIsSMSServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure, constants.EnvKeyDisablePhoneVerification, constants.EnvKeyDisablePlayGround, constants.EnvKeyDisableTOTPLogin, constants.EnvKeyDisableMailOTPLogin:
|
||||
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyIsSMSServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure, constants.EnvKeyDisablePhoneVerification:
|
||||
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
||||
if value.(bool) != envValueBool {
|
||||
storeData[key] = envValueBool
|
||||
|
@ -218,20 +218,15 @@ func PersistEnv() error {
|
|||
if storeData[constants.EnvKeySmtpHost] == "" || storeData[constants.EnvKeySmtpUsername] == "" || storeData[constants.EnvKeySmtpPassword] == "" || storeData[constants.EnvKeySenderEmail] == "" && storeData[constants.EnvKeySmtpPort] == "" {
|
||||
storeData[constants.EnvKeyIsEmailServiceEnabled] = false
|
||||
|
||||
if val, ok := storeData[constants.EnvKeyDisableEmailVerification]; ok && val != nil && !val.(bool) {
|
||||
if !storeData[constants.EnvKeyDisableEmailVerification].(bool) {
|
||||
storeData[constants.EnvKeyDisableEmailVerification] = true
|
||||
hasChanged = true
|
||||
}
|
||||
|
||||
if val, ok := storeData[constants.EnvKeyDisableMagicLinkLogin]; ok && val != nil && !val.(bool) {
|
||||
if !storeData[constants.EnvKeyDisableMagicLinkLogin].(bool) {
|
||||
storeData[constants.EnvKeyDisableMagicLinkLogin] = true
|
||||
hasChanged = true
|
||||
}
|
||||
|
||||
if val, ok := storeData[constants.EnvKeyDisableMailOTPLogin]; ok && val != nil && !val.(bool) {
|
||||
storeData[constants.EnvKeyDisableMailOTPLogin] = true
|
||||
hasChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
err = memorystore.Provider.UpdateEnvStore(storeData)
|
||||
|
|
154
server/go.mod
154
server/go.mod
|
@ -1,128 +1,42 @@
|
|||
module github.com/authorizerdev/authorizer/server
|
||||
|
||||
go 1.21
|
||||
|
||||
toolchain go1.21.4
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/99designs/gqlgen v0.17.45
|
||||
github.com/arangodb/go-driver v1.6.0
|
||||
github.com/aws/aws-sdk-go v1.47.4
|
||||
github.com/coreos/go-oidc/v3 v3.6.0
|
||||
github.com/couchbase/gocb/v2 v2.6.4
|
||||
github.com/ekristen/gorm-libsql v0.0.0-20231101204708-6e113112bcc2
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/glebarez/sqlite v1.10.0
|
||||
github.com/gocql/gocql v1.6.0
|
||||
github.com/gokyle/twofactor v1.0.1
|
||||
github.com/99designs/gqlgen v0.17.20
|
||||
github.com/arangodb/go-driver v1.2.1
|
||||
github.com/aws/aws-sdk-go v1.44.298
|
||||
github.com/coreos/go-oidc/v3 v3.1.0
|
||||
github.com/couchbase/gocb/v2 v2.6.0
|
||||
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/goccy/go-json v0.9.11 // indirect
|
||||
github.com/gocql/gocql v1.2.0
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/guregu/dynamo v1.20.2
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/mailgun/mailgun-go/v4 v4.12.0
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/redis/go-redis/v9 v9.2.1
|
||||
github.com/robertkrimen/otto v0.2.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d
|
||||
github.com/twilio/twilio-go v1.14.1
|
||||
github.com/vektah/gqlparser/v2 v2.5.11
|
||||
go.mongodb.org/mongo-driver v1.12.1
|
||||
golang.org/x/crypto v0.21.0
|
||||
golang.org/x/oauth2 v0.13.0
|
||||
google.golang.org/appengine v1.6.8
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/go-cmp v0.5.6 // indirect
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/guregu/dynamo v1.20.0
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||
github.com/redis/go-redis/v9 v9.0.3
|
||||
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/twilio/twilio-go v1.7.2
|
||||
github.com/vektah/gqlparser/v2 v2.5.1
|
||||
go.mongodb.org/mongo-driver v1.8.1
|
||||
golang.org/x/crypto v0.4.0
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/mail.v2 v2.3.1
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
gorm.io/driver/mysql v1.5.2
|
||||
gorm.io/driver/postgres v1.5.4
|
||||
gorm.io/driver/sqlserver v1.5.2
|
||||
gorm.io/gorm v1.25.5
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/agnivade/levenshtein v1.1.1 // indirect
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 // indirect
|
||||
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/couchbase/gocbcore/v10 v10.2.8 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.8 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.15.15 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/libsql/libsql-client-go v0.0.0-20231026052543-fce76c0f39a7 // indirect
|
||||
github.com/libsql/sqlite-antlr4-parser v0.0.0-20230802215326-5cb5bb604475 // indirect
|
||||
github.com/maruel/rs v1.1.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/microsoft/go-mssqldb v1.6.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/montanaflynn/stats v0.7.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sosodev/duration v1.2.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/urfave/cli/v2 v2.27.1 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/mod v0.16.0 // indirect
|
||||
golang.org/x/net v0.22.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.19.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.22.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/sqlite v1.23.1 // indirect
|
||||
nhooyr.io/websocket v1.8.7 // indirect
|
||||
rsc.io/qr v0.2.0 // indirect
|
||||
gorm.io/driver/mysql v1.4.3
|
||||
gorm.io/driver/postgres v1.4.7
|
||||
gorm.io/driver/sqlserver v1.4.1
|
||||
gorm.io/gorm v1.24.2
|
||||
)
|
||||
|
|
835
server/go.sum
835
server/go.sum
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -6,15 +6,15 @@ type AddEmailTemplateRequest struct {
|
|||
EventName string `json:"event_name"`
|
||||
Subject string `json:"subject"`
|
||||
Template string `json:"template"`
|
||||
Design *string `json:"design,omitempty"`
|
||||
Design *string `json:"design"`
|
||||
}
|
||||
|
||||
type AddWebhookRequest struct {
|
||||
EventName string `json:"event_name"`
|
||||
EventDescription *string `json:"event_description,omitempty"`
|
||||
EventDescription *string `json:"event_description"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Headers map[string]interface{} `json:"headers,omitempty"`
|
||||
Headers map[string]interface{} `json:"headers"`
|
||||
}
|
||||
|
||||
type AdminLoginInput struct {
|
||||
|
@ -26,18 +26,14 @@ type AdminSignupInput struct {
|
|||
}
|
||||
|
||||
type AuthResponse struct {
|
||||
Message string `json:"message"`
|
||||
ShouldShowEmailOtpScreen *bool `json:"should_show_email_otp_screen,omitempty"`
|
||||
ShouldShowMobileOtpScreen *bool `json:"should_show_mobile_otp_screen,omitempty"`
|
||||
ShouldShowTotpScreen *bool `json:"should_show_totp_screen,omitempty"`
|
||||
AccessToken *string `json:"access_token,omitempty"`
|
||||
IDToken *string `json:"id_token,omitempty"`
|
||||
RefreshToken *string `json:"refresh_token,omitempty"`
|
||||
ExpiresIn *int64 `json:"expires_in,omitempty"`
|
||||
User *User `json:"user,omitempty"`
|
||||
AuthenticatorScannerImage *string `json:"authenticator_scanner_image,omitempty"`
|
||||
AuthenticatorSecret *string `json:"authenticator_secret,omitempty"`
|
||||
AuthenticatorRecoveryCodes []*string `json:"authenticator_recovery_codes,omitempty"`
|
||||
Message string `json:"message"`
|
||||
ShouldShowEmailOtpScreen *bool `json:"should_show_email_otp_screen"`
|
||||
ShouldShowMobileOtpScreen *bool `json:"should_show_mobile_otp_screen"`
|
||||
AccessToken *string `json:"access_token"`
|
||||
IDToken *string `json:"id_token"`
|
||||
RefreshToken *string `json:"refresh_token"`
|
||||
ExpiresIn *int64 `json:"expires_in"`
|
||||
User *User `json:"user"`
|
||||
}
|
||||
|
||||
type DeleteEmailTemplateRequest struct {
|
||||
|
@ -54,8 +50,8 @@ type EmailTemplate struct {
|
|||
Template string `json:"template"`
|
||||
Design string `json:"design"`
|
||||
Subject string `json:"subject"`
|
||||
CreatedAt *int64 `json:"created_at,omitempty"`
|
||||
UpdatedAt *int64 `json:"updated_at,omitempty"`
|
||||
CreatedAt *int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
type EmailTemplates struct {
|
||||
|
@ -64,36 +60,35 @@ type EmailTemplates struct {
|
|||
}
|
||||
|
||||
type Env struct {
|
||||
AccessTokenExpiryTime *string `json:"ACCESS_TOKEN_EXPIRY_TIME,omitempty"`
|
||||
AdminSecret *string `json:"ADMIN_SECRET,omitempty"`
|
||||
DatabaseName *string `json:"DATABASE_NAME,omitempty"`
|
||||
DatabaseURL *string `json:"DATABASE_URL,omitempty"`
|
||||
DatabaseType *string `json:"DATABASE_TYPE,omitempty"`
|
||||
DatabaseUsername *string `json:"DATABASE_USERNAME,omitempty"`
|
||||
DatabasePassword *string `json:"DATABASE_PASSWORD,omitempty"`
|
||||
DatabaseHost *string `json:"DATABASE_HOST,omitempty"`
|
||||
DatabasePort *string `json:"DATABASE_PORT,omitempty"`
|
||||
AccessTokenExpiryTime *string `json:"ACCESS_TOKEN_EXPIRY_TIME"`
|
||||
AdminSecret *string `json:"ADMIN_SECRET"`
|
||||
DatabaseName *string `json:"DATABASE_NAME"`
|
||||
DatabaseURL *string `json:"DATABASE_URL"`
|
||||
DatabaseType *string `json:"DATABASE_TYPE"`
|
||||
DatabaseUsername *string `json:"DATABASE_USERNAME"`
|
||||
DatabasePassword *string `json:"DATABASE_PASSWORD"`
|
||||
DatabaseHost *string `json:"DATABASE_HOST"`
|
||||
DatabasePort *string `json:"DATABASE_PORT"`
|
||||
ClientID string `json:"CLIENT_ID"`
|
||||
ClientSecret string `json:"CLIENT_SECRET"`
|
||||
CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT,omitempty"`
|
||||
SMTPHost *string `json:"SMTP_HOST,omitempty"`
|
||||
SMTPPort *string `json:"SMTP_PORT,omitempty"`
|
||||
SMTPUsername *string `json:"SMTP_USERNAME,omitempty"`
|
||||
SMTPPassword *string `json:"SMTP_PASSWORD,omitempty"`
|
||||
SMTPLocalName *string `json:"SMTP_LOCAL_NAME,omitempty"`
|
||||
SenderEmail *string `json:"SENDER_EMAIL,omitempty"`
|
||||
SenderName *string `json:"SENDER_NAME,omitempty"`
|
||||
JwtType *string `json:"JWT_TYPE,omitempty"`
|
||||
JwtSecret *string `json:"JWT_SECRET,omitempty"`
|
||||
JwtPrivateKey *string `json:"JWT_PRIVATE_KEY,omitempty"`
|
||||
JwtPublicKey *string `json:"JWT_PUBLIC_KEY,omitempty"`
|
||||
AllowedOrigins []string `json:"ALLOWED_ORIGINS,omitempty"`
|
||||
AppURL *string `json:"APP_URL,omitempty"`
|
||||
RedisURL *string `json:"REDIS_URL,omitempty"`
|
||||
ResetPasswordURL *string `json:"RESET_PASSWORD_URL,omitempty"`
|
||||
CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT"`
|
||||
SMTPHost *string `json:"SMTP_HOST"`
|
||||
SMTPPort *string `json:"SMTP_PORT"`
|
||||
SMTPUsername *string `json:"SMTP_USERNAME"`
|
||||
SMTPPassword *string `json:"SMTP_PASSWORD"`
|
||||
SMTPLocalName *string `json:"SMTP_LOCAL_NAME"`
|
||||
SenderEmail *string `json:"SENDER_EMAIL"`
|
||||
SenderName *string `json:"SENDER_NAME"`
|
||||
JwtType *string `json:"JWT_TYPE"`
|
||||
JwtSecret *string `json:"JWT_SECRET"`
|
||||
JwtPrivateKey *string `json:"JWT_PRIVATE_KEY"`
|
||||
JwtPublicKey *string `json:"JWT_PUBLIC_KEY"`
|
||||
AllowedOrigins []string `json:"ALLOWED_ORIGINS"`
|
||||
AppURL *string `json:"APP_URL"`
|
||||
RedisURL *string `json:"REDIS_URL"`
|
||||
ResetPasswordURL *string `json:"RESET_PASSWORD_URL"`
|
||||
DisableEmailVerification bool `json:"DISABLE_EMAIL_VERIFICATION"`
|
||||
DisableBasicAuthentication bool `json:"DISABLE_BASIC_AUTHENTICATION"`
|
||||
DisableMobileBasicAuthentication bool `json:"DISABLE_MOBILE_BASIC_AUTHENTICATION"`
|
||||
DisableMagicLinkLogin bool `json:"DISABLE_MAGIC_LINK_LOGIN"`
|
||||
DisableLoginPage bool `json:"DISABLE_LOGIN_PAGE"`
|
||||
DisableSignUp bool `json:"DISABLE_SIGN_UP"`
|
||||
|
@ -101,40 +96,31 @@ type Env struct {
|
|||
DisableStrongPassword bool `json:"DISABLE_STRONG_PASSWORD"`
|
||||
DisableMultiFactorAuthentication bool `json:"DISABLE_MULTI_FACTOR_AUTHENTICATION"`
|
||||
EnforceMultiFactorAuthentication bool `json:"ENFORCE_MULTI_FACTOR_AUTHENTICATION"`
|
||||
Roles []string `json:"ROLES,omitempty"`
|
||||
ProtectedRoles []string `json:"PROTECTED_ROLES,omitempty"`
|
||||
DefaultRoles []string `json:"DEFAULT_ROLES,omitempty"`
|
||||
JwtRoleClaim *string `json:"JWT_ROLE_CLAIM,omitempty"`
|
||||
GoogleClientID *string `json:"GOOGLE_CLIENT_ID,omitempty"`
|
||||
GoogleClientSecret *string `json:"GOOGLE_CLIENT_SECRET,omitempty"`
|
||||
GithubClientID *string `json:"GITHUB_CLIENT_ID,omitempty"`
|
||||
GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET,omitempty"`
|
||||
FacebookClientID *string `json:"FACEBOOK_CLIENT_ID,omitempty"`
|
||||
FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET,omitempty"`
|
||||
LinkedinClientID *string `json:"LINKEDIN_CLIENT_ID,omitempty"`
|
||||
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET,omitempty"`
|
||||
AppleClientID *string `json:"APPLE_CLIENT_ID,omitempty"`
|
||||
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET,omitempty"`
|
||||
DiscordClientID *string `json:"DISCORD_CLIENT_ID,omitempty"`
|
||||
DiscordClientSecret *string `json:"DISCORD_CLIENT_SECRET,omitempty"`
|
||||
TwitterClientID *string `json:"TWITTER_CLIENT_ID,omitempty"`
|
||||
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET,omitempty"`
|
||||
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID,omitempty"`
|
||||
MicrosoftClientSecret *string `json:"MICROSOFT_CLIENT_SECRET,omitempty"`
|
||||
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID,omitempty"`
|
||||
TwitchClientID *string `json:"TWITCH_CLIENT_ID,omitempty"`
|
||||
TwitchClientSecret *string `json:"TWITCH_CLIENT_SECRET,omitempty"`
|
||||
RobloxClientID *string `json:"ROBLOX_CLIENT_ID,omitempty"`
|
||||
RobloxClientSecret *string `json:"ROBLOX_CLIENT_SECRET,omitempty"`
|
||||
OrganizationName *string `json:"ORGANIZATION_NAME,omitempty"`
|
||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO,omitempty"`
|
||||
Roles []string `json:"ROLES"`
|
||||
ProtectedRoles []string `json:"PROTECTED_ROLES"`
|
||||
DefaultRoles []string `json:"DEFAULT_ROLES"`
|
||||
JwtRoleClaim *string `json:"JWT_ROLE_CLAIM"`
|
||||
GoogleClientID *string `json:"GOOGLE_CLIENT_ID"`
|
||||
GoogleClientSecret *string `json:"GOOGLE_CLIENT_SECRET"`
|
||||
GithubClientID *string `json:"GITHUB_CLIENT_ID"`
|
||||
GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"`
|
||||
FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"`
|
||||
FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"`
|
||||
LinkedinClientID *string `json:"LINKEDIN_CLIENT_ID"`
|
||||
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET"`
|
||||
AppleClientID *string `json:"APPLE_CLIENT_ID"`
|
||||
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
|
||||
TwitterClientID *string `json:"TWITTER_CLIENT_ID"`
|
||||
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET"`
|
||||
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID"`
|
||||
MicrosoftClientSecret *string `json:"MICROSOFT_CLIENT_SECRET"`
|
||||
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID"`
|
||||
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
||||
AppCookieSecure bool `json:"APP_COOKIE_SECURE"`
|
||||
AdminCookieSecure bool `json:"ADMIN_COOKIE_SECURE"`
|
||||
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE,omitempty"`
|
||||
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE,omitempty"`
|
||||
DisablePlayground bool `json:"DISABLE_PLAYGROUND"`
|
||||
DisableMailOtpLogin bool `json:"DISABLE_MAIL_OTP_LOGIN"`
|
||||
DisableTotpLogin bool `json:"DISABLE_TOTP_LOGIN"`
|
||||
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE"`
|
||||
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE"`
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
|
@ -143,15 +129,9 @@ type Error struct {
|
|||
}
|
||||
|
||||
type ForgotPasswordInput struct {
|
||||
Email *string `json:"email,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
State *string `json:"state,omitempty"`
|
||||
RedirectURI *string `json:"redirect_uri,omitempty"`
|
||||
}
|
||||
|
||||
type ForgotPasswordResponse struct {
|
||||
Message string `json:"message"`
|
||||
ShouldShowMobileOtpScreen *bool `json:"should_show_mobile_otp_screen,omitempty"`
|
||||
Email string `json:"email"`
|
||||
State *string `json:"state"`
|
||||
RedirectURI *string `json:"redirect_uri"`
|
||||
}
|
||||
|
||||
type GenerateJWTKeysInput struct {
|
||||
|
@ -159,19 +139,19 @@ type GenerateJWTKeysInput struct {
|
|||
}
|
||||
|
||||
type GenerateJWTKeysResponse struct {
|
||||
Secret *string `json:"secret,omitempty"`
|
||||
PublicKey *string `json:"public_key,omitempty"`
|
||||
PrivateKey *string `json:"private_key,omitempty"`
|
||||
Secret *string `json:"secret"`
|
||||
PublicKey *string `json:"public_key"`
|
||||
PrivateKey *string `json:"private_key"`
|
||||
}
|
||||
|
||||
type GetUserRequest struct {
|
||||
ID *string `json:"id,omitempty"`
|
||||
Email *string `json:"email,omitempty"`
|
||||
ID *string `json:"id"`
|
||||
Email *string `json:"email"`
|
||||
}
|
||||
|
||||
type InviteMemberInput struct {
|
||||
Emails []string `json:"emails"`
|
||||
RedirectURI *string `json:"redirect_uri,omitempty"`
|
||||
RedirectURI *string `json:"redirect_uri"`
|
||||
}
|
||||
|
||||
type InviteMembersResponse struct {
|
||||
|
@ -180,79 +160,69 @@ type InviteMembersResponse struct {
|
|||
}
|
||||
|
||||
type ListWebhookLogRequest struct {
|
||||
Pagination *PaginationInput `json:"pagination,omitempty"`
|
||||
WebhookID *string `json:"webhook_id,omitempty"`
|
||||
Pagination *PaginationInput `json:"pagination"`
|
||||
WebhookID *string `json:"webhook_id"`
|
||||
}
|
||||
|
||||
type LoginInput struct {
|
||||
Email *string `json:"email,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
Password string `json:"password"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
Scope []string `json:"scope,omitempty"`
|
||||
State *string `json:"state,omitempty"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Roles []string `json:"roles"`
|
||||
Scope []string `json:"scope"`
|
||||
State *string `json:"state"`
|
||||
}
|
||||
|
||||
type MagicLinkLoginInput struct {
|
||||
Email string `json:"email"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
Scope []string `json:"scope,omitempty"`
|
||||
State *string `json:"state,omitempty"`
|
||||
RedirectURI *string `json:"redirect_uri,omitempty"`
|
||||
Roles []string `json:"roles"`
|
||||
Scope []string `json:"scope"`
|
||||
State *string `json:"state"`
|
||||
RedirectURI *string `json:"redirect_uri"`
|
||||
}
|
||||
|
||||
type Meta struct {
|
||||
Version string `json:"version"`
|
||||
ClientID string `json:"client_id"`
|
||||
IsGoogleLoginEnabled bool `json:"is_google_login_enabled"`
|
||||
IsFacebookLoginEnabled bool `json:"is_facebook_login_enabled"`
|
||||
IsGithubLoginEnabled bool `json:"is_github_login_enabled"`
|
||||
IsLinkedinLoginEnabled bool `json:"is_linkedin_login_enabled"`
|
||||
IsAppleLoginEnabled bool `json:"is_apple_login_enabled"`
|
||||
IsDiscordLoginEnabled bool `json:"is_discord_login_enabled"`
|
||||
IsTwitterLoginEnabled bool `json:"is_twitter_login_enabled"`
|
||||
IsMicrosoftLoginEnabled bool `json:"is_microsoft_login_enabled"`
|
||||
IsTwitchLoginEnabled bool `json:"is_twitch_login_enabled"`
|
||||
IsRobloxLoginEnabled bool `json:"is_roblox_login_enabled"`
|
||||
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
||||
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
||||
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
||||
IsSignUpEnabled bool `json:"is_sign_up_enabled"`
|
||||
IsStrongPasswordEnabled bool `json:"is_strong_password_enabled"`
|
||||
IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"`
|
||||
IsMobileBasicAuthenticationEnabled bool `json:"is_mobile_basic_authentication_enabled"`
|
||||
IsPhoneVerificationEnabled bool `json:"is_phone_verification_enabled"`
|
||||
Version string `json:"version"`
|
||||
ClientID string `json:"client_id"`
|
||||
IsGoogleLoginEnabled bool `json:"is_google_login_enabled"`
|
||||
IsFacebookLoginEnabled bool `json:"is_facebook_login_enabled"`
|
||||
IsGithubLoginEnabled bool `json:"is_github_login_enabled"`
|
||||
IsLinkedinLoginEnabled bool `json:"is_linkedin_login_enabled"`
|
||||
IsAppleLoginEnabled bool `json:"is_apple_login_enabled"`
|
||||
IsTwitterLoginEnabled bool `json:"is_twitter_login_enabled"`
|
||||
IsMicrosoftLoginEnabled bool `json:"is_microsoft_login_enabled"`
|
||||
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
||||
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
||||
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
||||
IsSignUpEnabled bool `json:"is_sign_up_enabled"`
|
||||
IsStrongPasswordEnabled bool `json:"is_strong_password_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,omitempty"`
|
||||
Scope []string `json:"scope,omitempty"`
|
||||
State *string `json:"state,omitempty"`
|
||||
Roles []string `json:"roles"`
|
||||
Scope []string `json:"scope"`
|
||||
State *string `json:"state"`
|
||||
}
|
||||
|
||||
type MobileSignUpInput struct {
|
||||
Email *string `json:"email,omitempty"`
|
||||
GivenName *string `json:"given_name,omitempty"`
|
||||
FamilyName *string `json:"family_name,omitempty"`
|
||||
MiddleName *string `json:"middle_name,omitempty"`
|
||||
Nickname *string `json:"nickname,omitempty"`
|
||||
Gender *string `json:"gender,omitempty"`
|
||||
Birthdate *string `json:"birthdate,omitempty"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
Picture *string `json:"picture,omitempty"`
|
||||
Password string `json:"password"`
|
||||
ConfirmPassword string `json:"confirm_password"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
Scope []string `json:"scope,omitempty"`
|
||||
RedirectURI *string `json:"redirect_uri,omitempty"`
|
||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"`
|
||||
State *string `json:"state,omitempty"`
|
||||
AppData map[string]interface{} `json:"app_data,omitempty"`
|
||||
}
|
||||
|
||||
type Mutation 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 {
|
||||
|
@ -260,7 +230,7 @@ type OAuthRevokeInput struct {
|
|||
}
|
||||
|
||||
type PaginatedInput struct {
|
||||
Pagination *PaginationInput `json:"pagination,omitempty"`
|
||||
Pagination *PaginationInput `json:"pagination"`
|
||||
}
|
||||
|
||||
type Pagination struct {
|
||||
|
@ -271,31 +241,26 @@ type Pagination struct {
|
|||
}
|
||||
|
||||
type PaginationInput struct {
|
||||
Limit *int64 `json:"limit,omitempty"`
|
||||
Page *int64 `json:"page,omitempty"`
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
Limit *int64 `json:"limit"`
|
||||
Page *int64 `json:"page"`
|
||||
}
|
||||
|
||||
type ResendOTPRequest struct {
|
||||
Email *string `json:"email,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
State *string `json:"state,omitempty"`
|
||||
Email *string `json:"email"`
|
||||
PhoneNumber *string `json:"phone_number"`
|
||||
State *string `json:"state"`
|
||||
}
|
||||
|
||||
type ResendVerifyEmailInput struct {
|
||||
Email string `json:"email"`
|
||||
Identifier string `json:"identifier"`
|
||||
State *string `json:"state,omitempty"`
|
||||
State *string `json:"state"`
|
||||
}
|
||||
|
||||
type ResetPasswordInput struct {
|
||||
Token *string `json:"token,omitempty"`
|
||||
Otp *string `json:"otp,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
Password string `json:"password"`
|
||||
ConfirmPassword string `json:"confirm_password"`
|
||||
Token string `json:"token"`
|
||||
Password string `json:"password"`
|
||||
ConfirmPassword string `json:"confirm_password"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
|
@ -308,44 +273,43 @@ type SMSVerificationRequests struct {
|
|||
CodeExpiresAt int64 `json:"code_expires_at"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at,omitempty"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
type SessionQueryInput struct {
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
Scope []string `json:"scope,omitempty"`
|
||||
Roles []string `json:"roles"`
|
||||
Scope []string `json:"scope"`
|
||||
}
|
||||
|
||||
type SignUpInput struct {
|
||||
Email *string `json:"email,omitempty"`
|
||||
GivenName *string `json:"given_name,omitempty"`
|
||||
FamilyName *string `json:"family_name,omitempty"`
|
||||
MiddleName *string `json:"middle_name,omitempty"`
|
||||
Nickname *string `json:"nickname,omitempty"`
|
||||
Gender *string `json:"gender,omitempty"`
|
||||
Birthdate *string `json:"birthdate,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
Picture *string `json:"picture,omitempty"`
|
||||
Password string `json:"password"`
|
||||
ConfirmPassword string `json:"confirm_password"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
Scope []string `json:"scope,omitempty"`
|
||||
RedirectURI *string `json:"redirect_uri,omitempty"`
|
||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"`
|
||||
State *string `json:"state,omitempty"`
|
||||
AppData map[string]interface{} `json:"app_data,omitempty"`
|
||||
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 TestEndpointRequest struct {
|
||||
Endpoint string `json:"endpoint"`
|
||||
EventName string `json:"event_name"`
|
||||
EventDescription *string `json:"event_description,omitempty"`
|
||||
Headers map[string]interface{} `json:"headers,omitempty"`
|
||||
EventDescription *string `json:"event_description"`
|
||||
Headers map[string]interface{} `json:"headers"`
|
||||
}
|
||||
|
||||
type TestEndpointResponse struct {
|
||||
HTTPStatus *int64 `json:"http_status,omitempty"`
|
||||
Response *string `json:"response,omitempty"`
|
||||
HTTPStatus *int64 `json:"http_status"`
|
||||
Response *string `json:"response"`
|
||||
}
|
||||
|
||||
type UpdateAccessInput struct {
|
||||
|
@ -354,142 +318,128 @@ type UpdateAccessInput struct {
|
|||
|
||||
type UpdateEmailTemplateRequest struct {
|
||||
ID string `json:"id"`
|
||||
EventName *string `json:"event_name,omitempty"`
|
||||
Template *string `json:"template,omitempty"`
|
||||
Subject *string `json:"subject,omitempty"`
|
||||
Design *string `json:"design,omitempty"`
|
||||
EventName *string `json:"event_name"`
|
||||
Template *string `json:"template"`
|
||||
Subject *string `json:"subject"`
|
||||
Design *string `json:"design"`
|
||||
}
|
||||
|
||||
type UpdateEnvInput struct {
|
||||
AccessTokenExpiryTime *string `json:"ACCESS_TOKEN_EXPIRY_TIME,omitempty"`
|
||||
AdminSecret *string `json:"ADMIN_SECRET,omitempty"`
|
||||
CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT,omitempty"`
|
||||
OldAdminSecret *string `json:"OLD_ADMIN_SECRET,omitempty"`
|
||||
SMTPHost *string `json:"SMTP_HOST,omitempty"`
|
||||
SMTPPort *string `json:"SMTP_PORT,omitempty"`
|
||||
SMTPUsername *string `json:"SMTP_USERNAME,omitempty"`
|
||||
SMTPPassword *string `json:"SMTP_PASSWORD,omitempty"`
|
||||
SMTPLocalName *string `json:"SMTP_LOCAL_NAME,omitempty"`
|
||||
SenderEmail *string `json:"SENDER_EMAIL,omitempty"`
|
||||
SenderName *string `json:"SENDER_NAME,omitempty"`
|
||||
JwtType *string `json:"JWT_TYPE,omitempty"`
|
||||
JwtSecret *string `json:"JWT_SECRET,omitempty"`
|
||||
JwtPrivateKey *string `json:"JWT_PRIVATE_KEY,omitempty"`
|
||||
JwtPublicKey *string `json:"JWT_PUBLIC_KEY,omitempty"`
|
||||
AllowedOrigins []string `json:"ALLOWED_ORIGINS,omitempty"`
|
||||
AppURL *string `json:"APP_URL,omitempty"`
|
||||
ResetPasswordURL *string `json:"RESET_PASSWORD_URL,omitempty"`
|
||||
AppCookieSecure *bool `json:"APP_COOKIE_SECURE,omitempty"`
|
||||
AdminCookieSecure *bool `json:"ADMIN_COOKIE_SECURE,omitempty"`
|
||||
DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION,omitempty"`
|
||||
DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION,omitempty"`
|
||||
DisableMobileBasicAuthentication *bool `json:"DISABLE_MOBILE_BASIC_AUTHENTICATION,omitempty"`
|
||||
DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN,omitempty"`
|
||||
DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE,omitempty"`
|
||||
DisableSignUp *bool `json:"DISABLE_SIGN_UP,omitempty"`
|
||||
DisableRedisForEnv *bool `json:"DISABLE_REDIS_FOR_ENV,omitempty"`
|
||||
DisableStrongPassword *bool `json:"DISABLE_STRONG_PASSWORD,omitempty"`
|
||||
DisableMultiFactorAuthentication *bool `json:"DISABLE_MULTI_FACTOR_AUTHENTICATION,omitempty"`
|
||||
EnforceMultiFactorAuthentication *bool `json:"ENFORCE_MULTI_FACTOR_AUTHENTICATION,omitempty"`
|
||||
Roles []string `json:"ROLES,omitempty"`
|
||||
ProtectedRoles []string `json:"PROTECTED_ROLES,omitempty"`
|
||||
DefaultRoles []string `json:"DEFAULT_ROLES,omitempty"`
|
||||
JwtRoleClaim *string `json:"JWT_ROLE_CLAIM,omitempty"`
|
||||
GoogleClientID *string `json:"GOOGLE_CLIENT_ID,omitempty"`
|
||||
GoogleClientSecret *string `json:"GOOGLE_CLIENT_SECRET,omitempty"`
|
||||
GithubClientID *string `json:"GITHUB_CLIENT_ID,omitempty"`
|
||||
GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET,omitempty"`
|
||||
FacebookClientID *string `json:"FACEBOOK_CLIENT_ID,omitempty"`
|
||||
FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET,omitempty"`
|
||||
LinkedinClientID *string `json:"LINKEDIN_CLIENT_ID,omitempty"`
|
||||
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET,omitempty"`
|
||||
AppleClientID *string `json:"APPLE_CLIENT_ID,omitempty"`
|
||||
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET,omitempty"`
|
||||
DiscordClientID *string `json:"DISCORD_CLIENT_ID,omitempty"`
|
||||
DiscordClientSecret *string `json:"DISCORD_CLIENT_SECRET,omitempty"`
|
||||
TwitterClientID *string `json:"TWITTER_CLIENT_ID,omitempty"`
|
||||
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET,omitempty"`
|
||||
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID,omitempty"`
|
||||
MicrosoftClientSecret *string `json:"MICROSOFT_CLIENT_SECRET,omitempty"`
|
||||
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID,omitempty"`
|
||||
TwitchClientID *string `json:"TWITCH_CLIENT_ID,omitempty"`
|
||||
TwitchClientSecret *string `json:"TWITCH_CLIENT_SECRET,omitempty"`
|
||||
RobloxClientID *string `json:"ROBLOX_CLIENT_ID,omitempty"`
|
||||
RobloxClientSecret *string `json:"ROBLOX_CLIENT_SECRET,omitempty"`
|
||||
OrganizationName *string `json:"ORGANIZATION_NAME,omitempty"`
|
||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO,omitempty"`
|
||||
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE,omitempty"`
|
||||
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE,omitempty"`
|
||||
DisablePlayground *bool `json:"DISABLE_PLAYGROUND,omitempty"`
|
||||
DisableMailOtpLogin *bool `json:"DISABLE_MAIL_OTP_LOGIN,omitempty"`
|
||||
DisableTotpLogin *bool `json:"DISABLE_TOTP_LOGIN,omitempty"`
|
||||
AccessTokenExpiryTime *string `json:"ACCESS_TOKEN_EXPIRY_TIME"`
|
||||
AdminSecret *string `json:"ADMIN_SECRET"`
|
||||
CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT"`
|
||||
OldAdminSecret *string `json:"OLD_ADMIN_SECRET"`
|
||||
SMTPHost *string `json:"SMTP_HOST"`
|
||||
SMTPPort *string `json:"SMTP_PORT"`
|
||||
SMTPUsername *string `json:"SMTP_USERNAME"`
|
||||
SMTPPassword *string `json:"SMTP_PASSWORD"`
|
||||
SMTPLocalName *string `json:"SMTP_LOCAL_NAME"`
|
||||
SenderEmail *string `json:"SENDER_EMAIL"`
|
||||
SenderName *string `json:"SENDER_NAME"`
|
||||
JwtType *string `json:"JWT_TYPE"`
|
||||
JwtSecret *string `json:"JWT_SECRET"`
|
||||
JwtPrivateKey *string `json:"JWT_PRIVATE_KEY"`
|
||||
JwtPublicKey *string `json:"JWT_PUBLIC_KEY"`
|
||||
AllowedOrigins []string `json:"ALLOWED_ORIGINS"`
|
||||
AppURL *string `json:"APP_URL"`
|
||||
ResetPasswordURL *string `json:"RESET_PASSWORD_URL"`
|
||||
AppCookieSecure *bool `json:"APP_COOKIE_SECURE"`
|
||||
AdminCookieSecure *bool `json:"ADMIN_COOKIE_SECURE"`
|
||||
DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION"`
|
||||
DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION"`
|
||||
DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN"`
|
||||
DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE"`
|
||||
DisableSignUp *bool `json:"DISABLE_SIGN_UP"`
|
||||
DisableRedisForEnv *bool `json:"DISABLE_REDIS_FOR_ENV"`
|
||||
DisableStrongPassword *bool `json:"DISABLE_STRONG_PASSWORD"`
|
||||
DisableMultiFactorAuthentication *bool `json:"DISABLE_MULTI_FACTOR_AUTHENTICATION"`
|
||||
EnforceMultiFactorAuthentication *bool `json:"ENFORCE_MULTI_FACTOR_AUTHENTICATION"`
|
||||
Roles []string `json:"ROLES"`
|
||||
ProtectedRoles []string `json:"PROTECTED_ROLES"`
|
||||
DefaultRoles []string `json:"DEFAULT_ROLES"`
|
||||
JwtRoleClaim *string `json:"JWT_ROLE_CLAIM"`
|
||||
GoogleClientID *string `json:"GOOGLE_CLIENT_ID"`
|
||||
GoogleClientSecret *string `json:"GOOGLE_CLIENT_SECRET"`
|
||||
GithubClientID *string `json:"GITHUB_CLIENT_ID"`
|
||||
GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"`
|
||||
FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"`
|
||||
FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"`
|
||||
LinkedinClientID *string `json:"LINKEDIN_CLIENT_ID"`
|
||||
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET"`
|
||||
AppleClientID *string `json:"APPLE_CLIENT_ID"`
|
||||
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
|
||||
TwitterClientID *string `json:"TWITTER_CLIENT_ID"`
|
||||
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET"`
|
||||
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID"`
|
||||
MicrosoftClientSecret *string `json:"MICROSOFT_CLIENT_SECRET"`
|
||||
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID"`
|
||||
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
||||
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE"`
|
||||
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE"`
|
||||
}
|
||||
|
||||
type UpdateProfileInput struct {
|
||||
OldPassword *string `json:"old_password,omitempty"`
|
||||
NewPassword *string `json:"new_password,omitempty"`
|
||||
ConfirmNewPassword *string `json:"confirm_new_password,omitempty"`
|
||||
Email *string `json:"email,omitempty"`
|
||||
GivenName *string `json:"given_name,omitempty"`
|
||||
FamilyName *string `json:"family_name,omitempty"`
|
||||
MiddleName *string `json:"middle_name,omitempty"`
|
||||
Nickname *string `json:"nickname,omitempty"`
|
||||
Gender *string `json:"gender,omitempty"`
|
||||
Birthdate *string `json:"birthdate,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
Picture *string `json:"picture,omitempty"`
|
||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"`
|
||||
AppData map[string]interface{} `json:"app_data,omitempty"`
|
||||
OldPassword *string `json:"old_password"`
|
||||
NewPassword *string `json:"new_password"`
|
||||
ConfirmNewPassword *string `json:"confirm_new_password"`
|
||||
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"`
|
||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
|
||||
}
|
||||
|
||||
type UpdateUserInput struct {
|
||||
ID string `json:"id"`
|
||||
Email *string `json:"email,omitempty"`
|
||||
EmailVerified *bool `json:"email_verified,omitempty"`
|
||||
GivenName *string `json:"given_name,omitempty"`
|
||||
FamilyName *string `json:"family_name,omitempty"`
|
||||
MiddleName *string `json:"middle_name,omitempty"`
|
||||
Nickname *string `json:"nickname,omitempty"`
|
||||
Gender *string `json:"gender,omitempty"`
|
||||
Birthdate *string `json:"birthdate,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
PhoneNumberVerified *bool `json:"phone_number_verified,omitempty"`
|
||||
Picture *string `json:"picture,omitempty"`
|
||||
Roles []*string `json:"roles,omitempty"`
|
||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"`
|
||||
AppData map[string]interface{} `json:"app_data,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Email *string `json:"email"`
|
||||
EmailVerified *bool `json:"email_verified"`
|
||||
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"`
|
||||
Roles []*string `json:"roles"`
|
||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
|
||||
}
|
||||
|
||||
type UpdateWebhookRequest struct {
|
||||
ID string `json:"id"`
|
||||
EventName *string `json:"event_name,omitempty"`
|
||||
EventDescription *string `json:"event_description,omitempty"`
|
||||
Endpoint *string `json:"endpoint,omitempty"`
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
Headers map[string]interface{} `json:"headers,omitempty"`
|
||||
EventName *string `json:"event_name"`
|
||||
EventDescription *string `json:"event_description"`
|
||||
Endpoint *string `json:"endpoint"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
Headers map[string]interface{} `json:"headers"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Email *string `json:"email,omitempty"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
SignupMethods string `json:"signup_methods"`
|
||||
GivenName *string `json:"given_name,omitempty"`
|
||||
FamilyName *string `json:"family_name,omitempty"`
|
||||
MiddleName *string `json:"middle_name,omitempty"`
|
||||
Nickname *string `json:"nickname,omitempty"`
|
||||
PreferredUsername *string `json:"preferred_username,omitempty"`
|
||||
Gender *string `json:"gender,omitempty"`
|
||||
Birthdate *string `json:"birthdate,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
PhoneNumberVerified *bool `json:"phone_number_verified,omitempty"`
|
||||
Picture *string `json:"picture,omitempty"`
|
||||
Roles []string `json:"roles"`
|
||||
CreatedAt *int64 `json:"created_at,omitempty"`
|
||||
UpdatedAt *int64 `json:"updated_at,omitempty"`
|
||||
RevokedTimestamp *int64 `json:"revoked_timestamp,omitempty"`
|
||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"`
|
||||
AppData map[string]interface{} `json:"app_data,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
SignupMethods string `json:"signup_methods"`
|
||||
GivenName *string `json:"given_name"`
|
||||
FamilyName *string `json:"family_name"`
|
||||
MiddleName *string `json:"middle_name"`
|
||||
Nickname *string `json:"nickname"`
|
||||
PreferredUsername *string `json:"preferred_username"`
|
||||
Gender *string `json:"gender"`
|
||||
Birthdate *string `json:"birthdate"`
|
||||
PhoneNumber *string `json:"phone_number"`
|
||||
PhoneNumberVerified *bool `json:"phone_number_verified"`
|
||||
Picture *string `json:"picture"`
|
||||
Roles []string `json:"roles"`
|
||||
CreatedAt *int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
RevokedTimestamp *int64 `json:"revoked_timestamp"`
|
||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
|
||||
}
|
||||
|
||||
type Users struct {
|
||||
|
@ -500,34 +450,33 @@ type Users struct {
|
|||
type ValidateJWTTokenInput struct {
|
||||
TokenType string `json:"token_type"`
|
||||
Token string `json:"token"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
Roles []string `json:"roles"`
|
||||
}
|
||||
|
||||
type ValidateJWTTokenResponse struct {
|
||||
IsValid bool `json:"is_valid"`
|
||||
Claims map[string]interface{} `json:"claims,omitempty"`
|
||||
Claims map[string]interface{} `json:"claims"`
|
||||
}
|
||||
|
||||
type ValidateSessionInput struct {
|
||||
Cookie string `json:"cookie"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
Roles []string `json:"roles"`
|
||||
}
|
||||
|
||||
type ValidateSessionResponse struct {
|
||||
IsValid bool `json:"is_valid"`
|
||||
User *User `json:"user"`
|
||||
IsValid bool `json:"is_valid"`
|
||||
}
|
||||
|
||||
type VerificationRequest struct {
|
||||
ID string `json:"id"`
|
||||
Identifier *string `json:"identifier,omitempty"`
|
||||
Token *string `json:"token,omitempty"`
|
||||
Email *string `json:"email,omitempty"`
|
||||
Expires *int64 `json:"expires,omitempty"`
|
||||
CreatedAt *int64 `json:"created_at,omitempty"`
|
||||
UpdatedAt *int64 `json:"updated_at,omitempty"`
|
||||
Nonce *string `json:"nonce,omitempty"`
|
||||
RedirectURI *string `json:"redirect_uri,omitempty"`
|
||||
Identifier *string `json:"identifier"`
|
||||
Token *string `json:"token"`
|
||||
Email *string `json:"email"`
|
||||
Expires *int64 `json:"expires"`
|
||||
CreatedAt *int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
Nonce *string `json:"nonce"`
|
||||
RedirectURI *string `json:"redirect_uri"`
|
||||
}
|
||||
|
||||
type VerificationRequests struct {
|
||||
|
@ -537,36 +486,35 @@ type VerificationRequests struct {
|
|||
|
||||
type VerifyEmailInput struct {
|
||||
Token string `json:"token"`
|
||||
State *string `json:"state,omitempty"`
|
||||
State *string `json:"state"`
|
||||
}
|
||||
|
||||
type VerifyOTPRequest struct {
|
||||
Email *string `json:"email,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
Email *string `json:"email"`
|
||||
PhoneNumber *string `json:"phone_number"`
|
||||
Otp string `json:"otp"`
|
||||
IsTotp *bool `json:"is_totp,omitempty"`
|
||||
State *string `json:"state,omitempty"`
|
||||
State *string `json:"state"`
|
||||
}
|
||||
|
||||
type Webhook struct {
|
||||
ID string `json:"id"`
|
||||
EventName *string `json:"event_name,omitempty"`
|
||||
EventDescription *string `json:"event_description,omitempty"`
|
||||
Endpoint *string `json:"endpoint,omitempty"`
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
Headers map[string]interface{} `json:"headers,omitempty"`
|
||||
CreatedAt *int64 `json:"created_at,omitempty"`
|
||||
UpdatedAt *int64 `json:"updated_at,omitempty"`
|
||||
EventName *string `json:"event_name"`
|
||||
EventDescription *string `json:"event_description"`
|
||||
Endpoint *string `json:"endpoint"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
Headers map[string]interface{} `json:"headers"`
|
||||
CreatedAt *int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
type WebhookLog struct {
|
||||
ID string `json:"id"`
|
||||
HTTPStatus *int64 `json:"http_status,omitempty"`
|
||||
Response *string `json:"response,omitempty"`
|
||||
Request *string `json:"request,omitempty"`
|
||||
WebhookID *string `json:"webhook_id,omitempty"`
|
||||
CreatedAt *int64 `json:"created_at,omitempty"`
|
||||
UpdatedAt *int64 `json:"updated_at,omitempty"`
|
||||
HTTPStatus *int64 `json:"http_status"`
|
||||
Response *string `json:"response"`
|
||||
Request *string `json:"request"`
|
||||
WebhookID *string `json:"webhook_id"`
|
||||
CreatedAt *int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
type WebhookLogs struct {
|
||||
|
|
|
@ -20,25 +20,19 @@ type Meta {
|
|||
is_github_login_enabled: Boolean!
|
||||
is_linkedin_login_enabled: Boolean!
|
||||
is_apple_login_enabled: Boolean!
|
||||
is_discord_login_enabled: Boolean!
|
||||
is_twitter_login_enabled: Boolean!
|
||||
is_microsoft_login_enabled: Boolean!
|
||||
is_twitch_login_enabled: Boolean!
|
||||
is_roblox_login_enabled: Boolean!
|
||||
is_email_verification_enabled: Boolean!
|
||||
is_basic_authentication_enabled: Boolean!
|
||||
is_magic_link_login_enabled: Boolean!
|
||||
is_sign_up_enabled: Boolean!
|
||||
is_strong_password_enabled: Boolean!
|
||||
is_multi_factor_auth_enabled: Boolean!
|
||||
is_mobile_basic_authentication_enabled: Boolean!
|
||||
is_phone_verification_enabled: Boolean!
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
# email or phone_number is always present
|
||||
email: String
|
||||
email: String!
|
||||
email_verified: Boolean!
|
||||
signup_methods: String!
|
||||
given_name: String
|
||||
|
@ -57,7 +51,6 @@ type User {
|
|||
updated_at: Int64
|
||||
revoked_timestamp: Int64
|
||||
is_multi_factor_auth_enabled: Boolean
|
||||
app_data: Map
|
||||
}
|
||||
|
||||
type Users {
|
||||
|
@ -100,30 +93,17 @@ type AuthResponse {
|
|||
message: String!
|
||||
should_show_email_otp_screen: Boolean
|
||||
should_show_mobile_otp_screen: Boolean
|
||||
should_show_totp_screen: Boolean
|
||||
access_token: String
|
||||
id_token: String
|
||||
refresh_token: String
|
||||
expires_in: Int64
|
||||
user: User
|
||||
# key for totp login
|
||||
# it is a base64 image url
|
||||
authenticator_scanner_image: String
|
||||
# string which can be used instead of scanner image
|
||||
authenticator_secret: String
|
||||
# recovery codes for totp login shared with user only once
|
||||
authenticator_recovery_codes: [String]
|
||||
}
|
||||
|
||||
type Response {
|
||||
message: String!
|
||||
}
|
||||
|
||||
type ForgotPasswordResponse {
|
||||
message: String!
|
||||
should_show_mobile_otp_screen: Boolean
|
||||
}
|
||||
|
||||
type InviteMembersResponse {
|
||||
message: String!
|
||||
Users: [User!]!
|
||||
|
@ -159,7 +139,6 @@ type Env {
|
|||
RESET_PASSWORD_URL: String
|
||||
DISABLE_EMAIL_VERIFICATION: Boolean!
|
||||
DISABLE_BASIC_AUTHENTICATION: Boolean!
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: Boolean!
|
||||
DISABLE_MAGIC_LINK_LOGIN: Boolean!
|
||||
DISABLE_LOGIN_PAGE: Boolean!
|
||||
DISABLE_SIGN_UP: Boolean!
|
||||
|
@ -181,26 +160,17 @@ type Env {
|
|||
LINKEDIN_CLIENT_SECRET: String
|
||||
APPLE_CLIENT_ID: String
|
||||
APPLE_CLIENT_SECRET: String
|
||||
DISCORD_CLIENT_ID: String
|
||||
DISCORD_CLIENT_SECRET: String
|
||||
TWITTER_CLIENT_ID: String
|
||||
TWITTER_CLIENT_SECRET: String
|
||||
MICROSOFT_CLIENT_ID: String
|
||||
MICROSOFT_CLIENT_SECRET: String
|
||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
||||
TWITCH_CLIENT_ID: String
|
||||
TWITCH_CLIENT_SECRET: String
|
||||
ROBLOX_CLIENT_ID: String
|
||||
ROBLOX_CLIENT_SECRET: String
|
||||
ORGANIZATION_NAME: String
|
||||
ORGANIZATION_LOGO: String
|
||||
APP_COOKIE_SECURE: Boolean!
|
||||
ADMIN_COOKIE_SECURE: Boolean!
|
||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
||||
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
||||
DISABLE_PLAYGROUND: Boolean!
|
||||
DISABLE_MAIL_OTP_LOGIN: Boolean!
|
||||
DISABLE_TOTP_LOGIN: Boolean!
|
||||
}
|
||||
|
||||
type ValidateJWTTokenResponse {
|
||||
|
@ -210,7 +180,6 @@ type ValidateJWTTokenResponse {
|
|||
|
||||
type ValidateSessionResponse {
|
||||
is_valid: Boolean!
|
||||
user: User!
|
||||
}
|
||||
|
||||
type GenerateJWTKeysResponse {
|
||||
|
@ -293,7 +262,6 @@ input UpdateEnvInput {
|
|||
ADMIN_COOKIE_SECURE: Boolean
|
||||
DISABLE_EMAIL_VERIFICATION: Boolean
|
||||
DISABLE_BASIC_AUTHENTICATION: Boolean
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: Boolean
|
||||
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
||||
DISABLE_LOGIN_PAGE: Boolean
|
||||
DISABLE_SIGN_UP: Boolean
|
||||
|
@ -315,24 +283,15 @@ input UpdateEnvInput {
|
|||
LINKEDIN_CLIENT_SECRET: String
|
||||
APPLE_CLIENT_ID: String
|
||||
APPLE_CLIENT_SECRET: String
|
||||
DISCORD_CLIENT_ID: String
|
||||
DISCORD_CLIENT_SECRET: String
|
||||
TWITTER_CLIENT_ID: String
|
||||
TWITTER_CLIENT_SECRET: String
|
||||
MICROSOFT_CLIENT_ID: String
|
||||
MICROSOFT_CLIENT_SECRET: String
|
||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
||||
TWITCH_CLIENT_ID: String
|
||||
TWITCH_CLIENT_SECRET: String
|
||||
ROBLOX_CLIENT_ID: String
|
||||
ROBLOX_CLIENT_SECRET: String
|
||||
ORGANIZATION_NAME: String
|
||||
ORGANIZATION_LOGO: String
|
||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
||||
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
|
||||
DISABLE_PLAYGROUND: Boolean
|
||||
DISABLE_MAIL_OTP_LOGIN: Boolean
|
||||
DISABLE_TOTP_LOGIN: Boolean
|
||||
}
|
||||
|
||||
input AdminLoginInput {
|
||||
|
@ -343,7 +302,6 @@ input AdminSignupInput {
|
|||
admin_secret: String!
|
||||
}
|
||||
|
||||
# Deprecated from v1.2.0
|
||||
input MobileSignUpInput {
|
||||
email: String
|
||||
given_name: String
|
||||
|
@ -364,11 +322,10 @@ input MobileSignUpInput {
|
|||
# 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
|
||||
app_data: Map
|
||||
}
|
||||
|
||||
input SignUpInput {
|
||||
email: String
|
||||
email: String!
|
||||
given_name: String
|
||||
family_name: String
|
||||
middle_name: String
|
||||
|
@ -387,12 +344,10 @@ input SignUpInput {
|
|||
# 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
|
||||
app_data: Map
|
||||
}
|
||||
|
||||
input LoginInput {
|
||||
email: String
|
||||
phone_number: String
|
||||
email: String!
|
||||
password: String!
|
||||
roles: [String!]
|
||||
scope: [String!]
|
||||
|
@ -402,7 +357,6 @@ input LoginInput {
|
|||
state: String
|
||||
}
|
||||
|
||||
# Deprecated from v1.2.0
|
||||
input MobileLoginInput {
|
||||
phone_number: String!
|
||||
password: String!
|
||||
|
@ -445,7 +399,6 @@ input UpdateProfileInput {
|
|||
phone_number: String
|
||||
picture: String
|
||||
is_multi_factor_auth_enabled: Boolean
|
||||
app_data: Map
|
||||
}
|
||||
|
||||
input UpdateUserInput {
|
||||
|
@ -459,24 +412,19 @@ input UpdateUserInput {
|
|||
gender: String
|
||||
birthdate: String
|
||||
phone_number: String
|
||||
phone_number_verified: Boolean
|
||||
picture: String
|
||||
roles: [String]
|
||||
is_multi_factor_auth_enabled: Boolean
|
||||
app_data: Map
|
||||
}
|
||||
|
||||
input ForgotPasswordInput {
|
||||
email: String
|
||||
phone_number: String
|
||||
email: String!
|
||||
state: String
|
||||
redirect_uri: String
|
||||
}
|
||||
|
||||
input ResetPasswordInput {
|
||||
token: String
|
||||
otp: String
|
||||
phone_number: String
|
||||
token: String!
|
||||
password: String!
|
||||
confirm_password: String!
|
||||
}
|
||||
|
@ -592,11 +540,10 @@ input DeleteEmailTemplateRequest {
|
|||
}
|
||||
|
||||
input VerifyOTPRequest {
|
||||
# either email, phone_number or totp_token is required
|
||||
# either email or phone_number is required
|
||||
email: String
|
||||
phone_number: String
|
||||
otp: String!
|
||||
is_totp: 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
|
||||
|
@ -619,22 +566,19 @@ input GetUserRequest {
|
|||
|
||||
type Mutation {
|
||||
signup(params: SignUpInput!): AuthResponse!
|
||||
# Deprecated from v1.2.0
|
||||
mobile_signup(params: MobileSignUpInput): AuthResponse!
|
||||
login(params: LoginInput!): AuthResponse!
|
||||
# Deprecated from v1.2.0
|
||||
mobile_login(params: MobileLoginInput!): AuthResponse!
|
||||
magic_link_login(params: MagicLinkLoginInput!): Response!
|
||||
logout: Response!
|
||||
update_profile(params: UpdateProfileInput!): Response!
|
||||
verify_email(params: VerifyEmailInput!): AuthResponse!
|
||||
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
||||
forgot_password(params: ForgotPasswordInput!): ForgotPasswordResponse!
|
||||
forgot_password(params: ForgotPasswordInput!): Response!
|
||||
reset_password(params: ResetPasswordInput!): Response!
|
||||
revoke(params: OAuthRevokeInput!): Response!
|
||||
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
||||
resend_otp(params: ResendOTPRequest!): Response!
|
||||
deactivate_account: Response!
|
||||
# admin only apis
|
||||
_delete_user(params: DeleteUserInput!): Response!
|
||||
_update_user(params: UpdateUserInput!): User!
|
||||
|
@ -659,7 +603,6 @@ type Query {
|
|||
meta: Meta!
|
||||
session(params: SessionQueryInput): AuthResponse!
|
||||
profile: User!
|
||||
is_registered(email: String!): Response! # custom api
|
||||
validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse!
|
||||
validate_session(params: ValidateSessionInput): ValidateSessionResponse!
|
||||
# admin only apis
|
||||
|
|
|
@ -2,7 +2,6 @@ package graph
|
|||
|
||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.45
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -58,7 +57,7 @@ func (r *mutationResolver) ResendVerifyEmail(ctx context.Context, params model.R
|
|||
}
|
||||
|
||||
// ForgotPassword is the resolver for the forgot_password field.
|
||||
func (r *mutationResolver) ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.ForgotPasswordResponse, error) {
|
||||
func (r *mutationResolver) ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) {
|
||||
return resolvers.ForgotPasswordResolver(ctx, params)
|
||||
}
|
||||
|
||||
|
@ -82,11 +81,6 @@ func (r *mutationResolver) ResendOtp(ctx context.Context, params model.ResendOTP
|
|||
return resolvers.ResendOTPResolver(ctx, params)
|
||||
}
|
||||
|
||||
// DeactivateAccount is the resolver for the deactivate_account field.
|
||||
func (r *mutationResolver) DeactivateAccount(ctx context.Context) (*model.Response, error) {
|
||||
return resolvers.DeactivateAccountResolver(ctx)
|
||||
}
|
||||
|
||||
// DeleteUser is the resolver for the _delete_user field.
|
||||
func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) {
|
||||
return resolvers.DeleteUserResolver(ctx, params)
|
||||
|
@ -187,11 +181,6 @@ func (r *queryResolver) Profile(ctx context.Context) (*model.User, error) {
|
|||
return resolvers.ProfileResolver(ctx)
|
||||
}
|
||||
|
||||
// IsRegistered is the resolver for the signup field.
|
||||
func (r *queryResolver) IsRegistered(ctx context.Context, email string) (*model.Response, error) {
|
||||
return resolvers.IsRegisteredResolver(ctx, email)
|
||||
}
|
||||
|
||||
// ValidateJwtToken is the resolver for the validate_jwt_token field.
|
||||
func (r *queryResolver) ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) {
|
||||
return resolvers.ValidateJwtTokenResolver(ctx, params)
|
||||
|
|
|
@ -55,8 +55,6 @@ import (
|
|||
const (
|
||||
authorizeWebMessageTemplate = "authorize_web_message.tmpl"
|
||||
authorizeFormPostTemplate = "authorize_form_post.tmpl"
|
||||
baseAppPath = "/app"
|
||||
signupPath = "/app/signup"
|
||||
)
|
||||
|
||||
// AuthorizeHandler is the handler for the /authorize route
|
||||
|
@ -76,7 +74,6 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||
clientID := strings.TrimSpace(gc.Query("client_id"))
|
||||
responseMode := strings.TrimSpace(gc.Query("response_mode"))
|
||||
nonce := strings.TrimSpace(gc.Query("nonce"))
|
||||
screenHint := strings.TrimSpace(gc.Query("screen_hint"))
|
||||
|
||||
var scope []string
|
||||
if scopeString == "" {
|
||||
|
@ -123,33 +120,27 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||
|
||||
// TODO add state with timeout
|
||||
// used for response mode query or fragment
|
||||
authState := "state=" + state + "&scope=" + scopeString + "&redirect_uri=" + redirectURI
|
||||
loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI
|
||||
if responseType == constants.ResponseTypeCode {
|
||||
authState += "&code=" + code
|
||||
loginState += "&code=" + code
|
||||
if err := memorystore.Provider.SetState(state, code+"@@"+codeChallenge); err != nil {
|
||||
log.Debug("Error setting temp code", err)
|
||||
}
|
||||
} else {
|
||||
authState += "&nonce=" + nonce
|
||||
loginState += "&nonce=" + nonce
|
||||
if err := memorystore.Provider.SetState(state, nonce); err != nil {
|
||||
log.Debug("Error setting temp code", err)
|
||||
}
|
||||
}
|
||||
|
||||
authURL := baseAppPath + "?" + authState
|
||||
loginURL := "/app?" + loginState
|
||||
|
||||
if screenHint == constants.ScreenHintSignUp {
|
||||
authURL = signupPath + "?" + authState
|
||||
}
|
||||
|
||||
if responseMode == constants.ResponseModeFragment && screenHint == constants.ScreenHintSignUp {
|
||||
authURL = signupPath + "#" + authState
|
||||
} else if responseMode == constants.ResponseModeFragment {
|
||||
authURL = baseAppPath + "#" + authState
|
||||
if responseMode == constants.ResponseModeFragment {
|
||||
loginURL = "/app#" + loginState
|
||||
}
|
||||
|
||||
if responseType == constants.ResponseTypeCode && codeChallenge == "" {
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, map[string]interface{}{
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]interface{}{
|
||||
"error": "code_challenge_required",
|
||||
|
@ -169,7 +160,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||
sessionToken, err := cookie.GetSession(gc)
|
||||
if err != nil {
|
||||
log.Debug("GetSession failed: ", err)
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -177,7 +168,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||
claims, err := token.ValidateBrowserSession(gc, sessionToken)
|
||||
if err != nil {
|
||||
log.Debug("ValidateBrowserSession failed: ", err)
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -185,7 +176,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||
user, err := db.Provider.GetUserByID(gc, userID)
|
||||
if err != nil {
|
||||
log.Debug("GetUserByID failed: ", err)
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, map[string]interface{}{
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]interface{}{
|
||||
"error": "signup_required",
|
||||
|
@ -206,27 +197,27 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||
newSessionTokenData, newSessionToken, newSessionExpiresAt, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod)
|
||||
if err != nil {
|
||||
log.Debug("CreateSessionToken failed: ", err)
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: add state with timeout
|
||||
// if err := memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken); err != nil {
|
||||
// log.Debug("SetState failed: ", err)
|
||||
// handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
|
||||
// handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
// return
|
||||
// }
|
||||
|
||||
// TODO: add state with timeout
|
||||
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+newSessionToken); err != nil {
|
||||
log.Debug("SetState failed: ", err)
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken, newSessionExpiresAt); err != nil {
|
||||
log.Debug("SetUserSession failed: ", err)
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -260,7 +251,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, map[string]interface{}{
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]interface{}{
|
||||
"code": code,
|
||||
|
@ -276,19 +267,19 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||
authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod, nonce, "")
|
||||
if err != nil {
|
||||
log.Debug("CreateAuthToken failed: ", err)
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+nonce, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt); err != nil {
|
||||
log.Debug("SetUserSession failed: ", err)
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt); err != nil {
|
||||
log.Debug("SetUserSession failed: ", err)
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -331,14 +322,14 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, map[string]interface{}{
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": res,
|
||||
}, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,14 +352,14 @@ func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeC
|
|||
return nil
|
||||
}
|
||||
|
||||
func handleResponse(gc *gin.Context, responseMode, authURI, redirectURI string, data map[string]interface{}, httpStatusCode int) {
|
||||
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, authURI)
|
||||
gc.Redirect(http.StatusFound, loginURI)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -7,16 +7,15 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/cookie"
|
||||
|
@ -24,7 +23,6 @@ import (
|
|||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/oauth"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
"github.com/authorizerdev/authorizer/server/token"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
)
|
||||
|
@ -34,11 +32,11 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||
return func(ctx *gin.Context) {
|
||||
provider := ctx.Param("oauth_provider")
|
||||
state := ctx.Request.FormValue("state")
|
||||
|
||||
sessionState, err := memorystore.Provider.GetState(state)
|
||||
if sessionState == "" || err != nil {
|
||||
log.Debug("Invalid oauth state: ", state)
|
||||
ctx.JSON(400, gin.H{"error": "invalid oauth state"})
|
||||
return
|
||||
}
|
||||
// contains random token, redirect url, role
|
||||
sessionSplit := strings.Split(state, "___")
|
||||
|
@ -48,49 +46,32 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||
ctx.JSON(400, gin.H{"error": "invalid redirect url"})
|
||||
return
|
||||
}
|
||||
|
||||
// remove state from store
|
||||
go memorystore.Provider.RemoveState(state)
|
||||
|
||||
stateValue := sessionSplit[0]
|
||||
redirectURL := sessionSplit[1]
|
||||
inputRoles := strings.Split(sessionSplit[2], ",")
|
||||
scopeString := sessionSplit[3]
|
||||
scopes := []string{}
|
||||
if scopeString != "" {
|
||||
if strings.Contains(scopeString, ",") {
|
||||
scopes = strings.Split(scopeString, ",")
|
||||
}
|
||||
if strings.Contains(scopeString, " ") {
|
||||
scopes = strings.Split(scopeString, " ")
|
||||
}
|
||||
}
|
||||
scopes := strings.Split(sessionSplit[3], ",")
|
||||
|
||||
var user *models.User
|
||||
oauthCode := ctx.Request.FormValue("code")
|
||||
if oauthCode == "" {
|
||||
log.Debug("Invalid oauth code: ", oauthCode)
|
||||
ctx.JSON(400, gin.H{"error": "invalid oauth code"})
|
||||
return
|
||||
}
|
||||
switch provider {
|
||||
case constants.AuthRecipeMethodGoogle:
|
||||
user, err = processGoogleUserInfo(ctx, oauthCode)
|
||||
user, err = processGoogleUserInfo(oauthCode)
|
||||
case constants.AuthRecipeMethodGithub:
|
||||
user, err = processGithubUserInfo(ctx, oauthCode)
|
||||
user, err = processGithubUserInfo(oauthCode)
|
||||
case constants.AuthRecipeMethodFacebook:
|
||||
user, err = processFacebookUserInfo(ctx, oauthCode)
|
||||
user, err = processFacebookUserInfo(oauthCode)
|
||||
case constants.AuthRecipeMethodLinkedIn:
|
||||
user, err = processLinkedInUserInfo(ctx, oauthCode)
|
||||
user, err = processLinkedInUserInfo(oauthCode)
|
||||
case constants.AuthRecipeMethodApple:
|
||||
user, err = processAppleUserInfo(ctx, oauthCode)
|
||||
case constants.AuthRecipeMethodDiscord:
|
||||
user, err = processDiscordUserInfo(ctx, oauthCode)
|
||||
user, err = processAppleUserInfo(oauthCode)
|
||||
case constants.AuthRecipeMethodTwitter:
|
||||
user, err = processTwitterUserInfo(ctx, oauthCode, sessionState)
|
||||
user, err = processTwitterUserInfo(oauthCode, sessionState)
|
||||
case constants.AuthRecipeMethodMicrosoft:
|
||||
user, err = processMicrosoftUserInfo(ctx, oauthCode)
|
||||
case constants.AuthRecipeMethodTwitch:
|
||||
user, err = processTwitchUserInfo(ctx, oauthCode)
|
||||
case constants.AuthRecipeMethodRoblox:
|
||||
user, err = processRobloxUserInfo(ctx, oauthCode, sessionState)
|
||||
user, err = processMicrosoftUserInfo(oauthCode)
|
||||
default:
|
||||
log.Info("Invalid oauth provider")
|
||||
err = fmt.Errorf(`invalid oauth provider`)
|
||||
|
@ -102,7 +83,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
existingUser, err := db.Provider.GetUserByEmail(ctx, refs.StringValue(user.Email))
|
||||
existingUser, err := db.Provider.GetUserByEmail(ctx, user.Email)
|
||||
log := log.WithField("user", user.Email)
|
||||
isSignUp := false
|
||||
|
||||
|
@ -260,9 +241,8 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||
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
|
||||
// Note: If OIDC breaks in the future, use the above params
|
||||
params := "state=" + stateValue + "&nonce=" + nonce
|
||||
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token + "&nonce=" + nonce
|
||||
|
||||
if code != "" {
|
||||
params += "&code=" + code
|
||||
}
|
||||
|
@ -280,8 +260,6 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||
go func() {
|
||||
if isSignUp {
|
||||
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, provider, user)
|
||||
// User is also logged in with signup
|
||||
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, provider, user)
|
||||
} else {
|
||||
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, provider, user)
|
||||
}
|
||||
|
@ -301,11 +279,13 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func processGoogleUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||
func processGoogleUserInfo(code string) (*models.User, error) {
|
||||
var user *models.User
|
||||
ctx := context.Background()
|
||||
oauth2Token, err := oauth.OAuthProviders.GoogleConfig.Exchange(ctx, code)
|
||||
if err != nil {
|
||||
log.Debug("Failed to exchange code for token: ", err)
|
||||
return nil, fmt.Errorf("invalid google exchange code: %s", err.Error())
|
||||
return user, fmt.Errorf("invalid google exchange code: %s", err.Error())
|
||||
}
|
||||
verifier := oauth.OIDCProviders.GoogleOIDC.Verifier(&oidc.Config{ClientID: oauth.OAuthProviders.GoogleConfig.ClientID})
|
||||
|
||||
|
@ -313,35 +293,36 @@ func processGoogleUserInfo(ctx context.Context, code string) (*models.User, erro
|
|||
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||
if !ok {
|
||||
log.Debug("Failed to extract ID Token from OAuth2 token")
|
||||
return nil, fmt.Errorf("unable to extract id_token")
|
||||
return user, fmt.Errorf("unable to extract id_token")
|
||||
}
|
||||
|
||||
// Parse and verify ID Token payload.
|
||||
idToken, err := verifier.Verify(ctx, rawIDToken)
|
||||
if err != nil {
|
||||
log.Debug("Failed to verify ID Token: ", err)
|
||||
return nil, fmt.Errorf("unable to verify id_token: %s", err.Error())
|
||||
return user, fmt.Errorf("unable to verify id_token: %s", err.Error())
|
||||
}
|
||||
user := &models.User{}
|
||||
|
||||
if err := idToken.Claims(&user); err != nil {
|
||||
log.Debug("Failed to parse ID Token claims: ", err)
|
||||
return nil, fmt.Errorf("unable to extract claims")
|
||||
return user, fmt.Errorf("unable to extract claims")
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func processGithubUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||
oauth2Token, err := oauth.OAuthProviders.GithubConfig.Exchange(ctx, code)
|
||||
func processGithubUserInfo(code string) (*models.User, error) {
|
||||
var user *models.User
|
||||
oauth2Token, err := oauth.OAuthProviders.GithubConfig.Exchange(context.TODO(), code)
|
||||
if err != nil {
|
||||
log.Debug("Failed to exchange code for token: ", err)
|
||||
return nil, fmt.Errorf("invalid github exchange code: %s", err.Error())
|
||||
return user, fmt.Errorf("invalid github exchange code: %s", err.Error())
|
||||
}
|
||||
client := http.Client{}
|
||||
req, err := http.NewRequest("GET", constants.GithubUserInfoURL, nil)
|
||||
if err != nil {
|
||||
log.Debug("Failed to create github user info request: ", err)
|
||||
return nil, fmt.Errorf("error creating github user info request: %s", err.Error())
|
||||
return user, fmt.Errorf("error creating github user info request: %s", err.Error())
|
||||
}
|
||||
req.Header.Set(
|
||||
"Authorization", fmt.Sprintf("token %s", oauth2Token.AccessToken),
|
||||
|
@ -350,18 +331,18 @@ func processGithubUserInfo(ctx context.Context, code string) (*models.User, erro
|
|||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Debug("Failed to request github user info: ", err)
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Debug("Failed to read github user info response body: ", err)
|
||||
return nil, fmt.Errorf("failed to read github response body: %s", err.Error())
|
||||
return user, fmt.Errorf("failed to read github response body: %s", err.Error())
|
||||
}
|
||||
if response.StatusCode >= 400 {
|
||||
log.Debug("Failed to request github user info: ", string(body))
|
||||
return nil, fmt.Errorf("failed to request github user info: %s", string(body))
|
||||
return user, fmt.Errorf("failed to request github user info: %s", string(body))
|
||||
}
|
||||
|
||||
userRawData := make(map[string]string)
|
||||
|
@ -390,7 +371,7 @@ func processGithubUserInfo(ctx context.Context, code string) (*models.User, erro
|
|||
req, err := http.NewRequest(http.MethodGet, constants.GithubUserEmails, nil)
|
||||
if err != nil {
|
||||
log.Debug("Failed to create github emails request: ", err)
|
||||
return nil, fmt.Errorf("error creating github user info request: %s", err.Error())
|
||||
return user, fmt.Errorf("error creating github user info request: %s", err.Error())
|
||||
}
|
||||
req.Header.Set(
|
||||
"Authorization", fmt.Sprintf("token %s", oauth2Token.AccessToken),
|
||||
|
@ -399,25 +380,24 @@ func processGithubUserInfo(ctx context.Context, code string) (*models.User, erro
|
|||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Debug("Failed to request github user email: ", err)
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Debug("Failed to read github user email response body: ", err)
|
||||
return nil, fmt.Errorf("failed to read github response body: %s", err.Error())
|
||||
return user, fmt.Errorf("failed to read github response body: %s", err.Error())
|
||||
}
|
||||
if response.StatusCode >= 400 {
|
||||
log.Debug("Failed to request github user email: ", string(body))
|
||||
return nil, fmt.Errorf("failed to request github user info: %s", string(body))
|
||||
return user, fmt.Errorf("failed to request github user info: %s", string(body))
|
||||
}
|
||||
|
||||
emailData := []GithubUserEmails{}
|
||||
err = json.Unmarshal(body, &emailData)
|
||||
if err != nil {
|
||||
log.Debug("Failed to parse github user email: ", err)
|
||||
return nil, fmt.Errorf("failed to parse github user email: %s", err.Error())
|
||||
}
|
||||
|
||||
for _, userEmail := range emailData {
|
||||
|
@ -428,44 +408,45 @@ func processGithubUserInfo(ctx context.Context, code string) (*models.User, erro
|
|||
}
|
||||
}
|
||||
|
||||
user := &models.User{
|
||||
user = &models.User{
|
||||
GivenName: &firstName,
|
||||
FamilyName: &lastName,
|
||||
Picture: &picture,
|
||||
Email: &email,
|
||||
Email: email,
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func processFacebookUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||
oauth2Token, err := oauth.OAuthProviders.FacebookConfig.Exchange(ctx, code)
|
||||
func processFacebookUserInfo(code string) (*models.User, error) {
|
||||
var user *models.User
|
||||
oauth2Token, err := oauth.OAuthProviders.FacebookConfig.Exchange(context.TODO(), code)
|
||||
if err != nil {
|
||||
log.Debug("Invalid facebook exchange code: ", err)
|
||||
return nil, fmt.Errorf("invalid facebook exchange code: %s", err.Error())
|
||||
return user, fmt.Errorf("invalid facebook exchange code: %s", err.Error())
|
||||
}
|
||||
client := http.Client{}
|
||||
req, err := http.NewRequest("GET", constants.FacebookUserInfoURL+oauth2Token.AccessToken, nil)
|
||||
if err != nil {
|
||||
log.Debug("Error creating facebook user info request: ", err)
|
||||
return nil, fmt.Errorf("error creating facebook user info request: %s", err.Error())
|
||||
return user, fmt.Errorf("error creating facebook user info request: %s", err.Error())
|
||||
}
|
||||
|
||||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Debug("Failed to process facebook user: ", err)
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Debug("Failed to read facebook response: ", err)
|
||||
return nil, fmt.Errorf("failed to read facebook response body: %s", err.Error())
|
||||
return user, fmt.Errorf("failed to read facebook response body: %s", err.Error())
|
||||
}
|
||||
if response.StatusCode >= 400 {
|
||||
log.Debug("Failed to request facebook user info: ", string(body))
|
||||
return nil, fmt.Errorf("failed to request facebook user info: %s", string(body))
|
||||
return user, fmt.Errorf("failed to request facebook user info: %s", string(body))
|
||||
}
|
||||
userRawData := make(map[string]interface{})
|
||||
json.Unmarshal(body, &userRawData)
|
||||
|
@ -478,28 +459,29 @@ func processFacebookUserInfo(ctx context.Context, code string) (*models.User, er
|
|||
lastName := fmt.Sprintf("%v", userRawData["last_name"])
|
||||
picture := fmt.Sprintf("%v", picDataObject["url"])
|
||||
|
||||
user := &models.User{
|
||||
user = &models.User{
|
||||
GivenName: &firstName,
|
||||
FamilyName: &lastName,
|
||||
Picture: &picture,
|
||||
Email: &email,
|
||||
Email: email,
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||
oauth2Token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(ctx, code)
|
||||
func processLinkedInUserInfo(code string) (*models.User, error) {
|
||||
var user *models.User
|
||||
oauth2Token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(context.TODO(), code)
|
||||
if err != nil {
|
||||
log.Debug("Failed to exchange code for token: ", err)
|
||||
return nil, fmt.Errorf("invalid linkedin exchange code: %s", err.Error())
|
||||
return user, fmt.Errorf("invalid linkedin exchange code: %s", err.Error())
|
||||
}
|
||||
|
||||
client := http.Client{}
|
||||
req, err := http.NewRequest("GET", constants.LinkedInUserInfoURL, nil)
|
||||
if err != nil {
|
||||
log.Debug("Failed to create linkedin user info request: ", err)
|
||||
return nil, fmt.Errorf("error creating linkedin user info request: %s", err.Error())
|
||||
return user, fmt.Errorf("error creating linkedin user info request: %s", err.Error())
|
||||
}
|
||||
req.Header = http.Header{
|
||||
"Authorization": []string{fmt.Sprintf("Bearer %s", oauth2Token.AccessToken)},
|
||||
|
@ -508,19 +490,19 @@ func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, er
|
|||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Debug("Failed to request linkedin user info: ", err)
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Debug("Failed to read linkedin user info response body: ", err)
|
||||
return nil, fmt.Errorf("failed to read linkedin response body: %s", err.Error())
|
||||
return user, fmt.Errorf("failed to read linkedin response body: %s", err.Error())
|
||||
}
|
||||
|
||||
if response.StatusCode >= 400 {
|
||||
log.Debug("Failed to request linkedin user info: ", string(body))
|
||||
return nil, fmt.Errorf("failed to request linkedin user info: %s", string(body))
|
||||
return user, fmt.Errorf("failed to request linkedin user info: %s", string(body))
|
||||
}
|
||||
|
||||
userRawData := make(map[string]interface{})
|
||||
|
@ -529,7 +511,7 @@ func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, er
|
|||
req, err = http.NewRequest("GET", constants.LinkedInEmailURL, nil)
|
||||
if err != nil {
|
||||
log.Debug("Failed to create linkedin email info request: ", err)
|
||||
return nil, fmt.Errorf("error creating linkedin user info request: %s", err.Error())
|
||||
return user, fmt.Errorf("error creating linkedin user info request: %s", err.Error())
|
||||
}
|
||||
req.Header = http.Header{
|
||||
"Authorization": []string{fmt.Sprintf("Bearer %s", oauth2Token.AccessToken)},
|
||||
|
@ -538,18 +520,18 @@ func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, er
|
|||
response, err = client.Do(req)
|
||||
if err != nil {
|
||||
log.Debug("Failed to request linkedin email info: ", err)
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
body, err = io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Debug("Failed to read linkedin email info response body: ", err)
|
||||
return nil, 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())
|
||||
}
|
||||
if response.StatusCode >= 400 {
|
||||
log.Debug("Failed to request linkedin user info: ", string(body))
|
||||
return nil, fmt.Errorf("failed to request linkedin user info: %s", string(body))
|
||||
return user, fmt.Errorf("failed to request linkedin user info: %s", string(body))
|
||||
}
|
||||
emailRawData := make(map[string]interface{})
|
||||
json.Unmarshal(body, &emailRawData)
|
||||
|
@ -559,19 +541,19 @@ func processLinkedInUserInfo(ctx context.Context, code string) (*models.User, er
|
|||
profilePicture := userRawData["profilePicture"].(map[string]interface{})["displayImage~"].(map[string]interface{})["elements"].([]interface{})[0].(map[string]interface{})["identifiers"].([]interface{})[0].(map[string]interface{})["identifier"].(string)
|
||||
emailAddress := emailRawData["elements"].([]interface{})[0].(map[string]interface{})["handle~"].(map[string]interface{})["emailAddress"].(string)
|
||||
|
||||
user := &models.User{
|
||||
user = &models.User{
|
||||
GivenName: &firstName,
|
||||
FamilyName: &lastName,
|
||||
Picture: &profilePicture,
|
||||
Email: &emailAddress,
|
||||
Email: emailAddress,
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func processAppleUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||
var user = &models.User{}
|
||||
oauth2Token, err := oauth.OAuthProviders.AppleConfig.Exchange(ctx, code)
|
||||
func processAppleUserInfo(code string) (*models.User, error) {
|
||||
var user *models.User
|
||||
oauth2Token, err := oauth.OAuthProviders.AppleConfig.Exchange(context.TODO(), code)
|
||||
if err != nil {
|
||||
log.Debug("Failed to exchange code for token: ", err)
|
||||
return user, fmt.Errorf("invalid apple exchange code: %s", err.Error())
|
||||
|
@ -598,12 +580,12 @@ func processAppleUserInfo(ctx context.Context, code string) (*models.User, error
|
|||
log.Debug("Failed to unmarshal claims data: ", err)
|
||||
return user, fmt.Errorf("failed to unmarshal claims data: %s", err.Error())
|
||||
}
|
||||
if val, ok := claims["email"]; !ok || val == nil {
|
||||
|
||||
if val, ok := claims["email"]; !ok {
|
||||
log.Debug("Failed to extract email from claims.")
|
||||
return user, fmt.Errorf("unable to extract email, please check the scopes enabled for your app. It needs `email`, `name` scopes")
|
||||
} else {
|
||||
email := val.(string)
|
||||
user.Email = &email
|
||||
user.Email = val.(string)
|
||||
}
|
||||
|
||||
if val, ok := claims["name"]; ok {
|
||||
|
@ -619,86 +601,22 @@ func processAppleUserInfo(ctx context.Context, code string) (*models.User, error
|
|||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
func processDiscordUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||
oauth2Token, err := oauth.OAuthProviders.DiscordConfig.Exchange(ctx, code)
|
||||
func processTwitterUserInfo(code, verifier string) (*models.User, error) {
|
||||
var user *models.User
|
||||
oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(context.TODO(), code, oauth2.SetAuthURLParam("code_verifier", verifier))
|
||||
if err != nil {
|
||||
log.Debug("Failed to exchange code for token: ", err)
|
||||
return nil, fmt.Errorf("invalid discord exchange code: %s", err.Error())
|
||||
}
|
||||
|
||||
client := http.Client{}
|
||||
req, err := http.NewRequest("GET", constants.DiscordUserInfoURL, nil)
|
||||
if err != nil {
|
||||
log.Debug("Failed to create Discord user info request: ", err)
|
||||
return nil, fmt.Errorf("error creating Discord user info request: %s", err.Error())
|
||||
}
|
||||
req.Header = http.Header{
|
||||
"Authorization": []string{fmt.Sprintf("Bearer %s", oauth2Token.AccessToken)},
|
||||
}
|
||||
|
||||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Debug("Failed to request Discord user info: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Debug("Failed to read Discord user info response body: ", err)
|
||||
return nil, fmt.Errorf("failed to read Discord response body: %s", err.Error())
|
||||
}
|
||||
|
||||
if response.StatusCode >= 400 {
|
||||
log.Debug("Failed to request Discord user info: ", string(body))
|
||||
return nil, fmt.Errorf("failed to request Discord user info: %s", string(body))
|
||||
}
|
||||
|
||||
// Unmarshal the response body into a map
|
||||
responseRawData := make(map[string]interface{})
|
||||
if err := json.Unmarshal(body, &responseRawData); err != nil {
|
||||
log.Debug("Failed to unmarshal Discord response: ", err)
|
||||
return nil, fmt.Errorf("failed to unmarshal Discord response: %s", err.Error())
|
||||
}
|
||||
|
||||
// Safely extract the user data
|
||||
userRawData, ok := responseRawData["user"].(map[string]interface{})
|
||||
if !ok {
|
||||
log.Debug("User data is not in expected format or missing in response")
|
||||
return nil, fmt.Errorf("user data is not in expected format or missing in response")
|
||||
}
|
||||
|
||||
// Extract the username
|
||||
firstName, ok := userRawData["username"].(string)
|
||||
if !ok {
|
||||
log.Debug("Username is not in expected format or missing in user data")
|
||||
return nil, fmt.Errorf("username is not in expected format or missing in user data")
|
||||
}
|
||||
profilePicture := fmt.Sprintf("https://cdn.discordapp.com/avatars/%s/%s.png", userRawData["id"].(string), userRawData["avatar"].(string))
|
||||
|
||||
user := &models.User{
|
||||
GivenName: &firstName,
|
||||
Picture: &profilePicture,
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func processTwitterUserInfo(ctx context.Context, code, verifier string) (*models.User, error) {
|
||||
oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(ctx, code, oauth2.SetAuthURLParam("code_verifier", verifier))
|
||||
if err != nil {
|
||||
log.Debug("Failed to exchange code for token: ", err)
|
||||
return nil, fmt.Errorf("invalid twitter exchange code: %s", err.Error())
|
||||
return user, fmt.Errorf("invalid twitter exchange code: %s", err.Error())
|
||||
}
|
||||
|
||||
client := http.Client{}
|
||||
req, err := http.NewRequest("GET", constants.TwitterUserInfoURL, nil)
|
||||
if err != nil {
|
||||
log.Debug("Failed to create Twitter user info request: ", err)
|
||||
return nil, fmt.Errorf("error creating Twitter user info request: %s", err.Error())
|
||||
return user, fmt.Errorf("error creating Twitter user info request: %s", err.Error())
|
||||
}
|
||||
req.Header = http.Header{
|
||||
"Authorization": []string{fmt.Sprintf("Bearer %s", oauth2Token.AccessToken)},
|
||||
|
@ -707,19 +625,19 @@ func processTwitterUserInfo(ctx context.Context, code, verifier string) (*models
|
|||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Debug("Failed to request Twitter user info: ", err)
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Debug("Failed to read Twitter user info response body: ", err)
|
||||
return nil, fmt.Errorf("failed to read Twitter response body: %s", err.Error())
|
||||
return user, fmt.Errorf("failed to read Twitter response body: %s", err.Error())
|
||||
}
|
||||
|
||||
if response.StatusCode >= 400 {
|
||||
log.Debug("Failed to request Twitter user info: ", string(body))
|
||||
return nil, fmt.Errorf("failed to request Twitter user info: %s", string(body))
|
||||
return user, fmt.Errorf("failed to request Twitter user info: %s", string(body))
|
||||
}
|
||||
|
||||
responseRawData := make(map[string]interface{})
|
||||
|
@ -743,7 +661,7 @@ func processTwitterUserInfo(ctx context.Context, code, verifier string) (*models
|
|||
nickname := userRawData["username"].(string)
|
||||
profilePicture := userRawData["profile_image_url"].(string)
|
||||
|
||||
user := &models.User{
|
||||
user = &models.User{
|
||||
GivenName: &firstName,
|
||||
FamilyName: &lastName,
|
||||
Picture: &profilePicture,
|
||||
|
@ -754,133 +672,34 @@ func processTwitterUserInfo(ctx context.Context, code, verifier string) (*models
|
|||
}
|
||||
|
||||
// process microsoft user information
|
||||
func processMicrosoftUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||
func processMicrosoftUserInfo(code string) (*models.User, error) {
|
||||
var user *models.User
|
||||
ctx := context.Background()
|
||||
oauth2Token, err := oauth.OAuthProviders.MicrosoftConfig.Exchange(ctx, code)
|
||||
if err != nil {
|
||||
log.Debug("Failed to exchange code for token: ", err)
|
||||
return nil, fmt.Errorf("invalid microsoft exchange code: %s", err.Error())
|
||||
}
|
||||
// we need to skip issuer check because for common tenant it will return internal issuer which does not match
|
||||
verifier := oauth.OIDCProviders.MicrosoftOIDC.Verifier(&oidc.Config{
|
||||
ClientID: oauth.OAuthProviders.MicrosoftConfig.ClientID,
|
||||
SkipIssuerCheck: true,
|
||||
})
|
||||
// Extract the ID Token from OAuth2 token.
|
||||
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||
if !ok {
|
||||
log.Debug("Failed to extract ID Token from OAuth2 token")
|
||||
return nil, fmt.Errorf("unable to extract id_token")
|
||||
}
|
||||
// Parse and verify ID Token payload.
|
||||
idToken, err := verifier.Verify(ctx, rawIDToken)
|
||||
if err != nil {
|
||||
log.Debug("Failed to verify ID Token: ", err)
|
||||
return nil, fmt.Errorf("unable to verify id_token: %s", err.Error())
|
||||
}
|
||||
user := &models.User{}
|
||||
if err := idToken.Claims(&user); err != nil {
|
||||
log.Debug("Failed to parse ID Token claims: ", err)
|
||||
return nil, fmt.Errorf("unable to extract claims")
|
||||
return user, fmt.Errorf("invalid google exchange code: %s", err.Error())
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// process twitch user information
|
||||
func processTwitchUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||
oauth2Token, err := oauth.OAuthProviders.TwitchConfig.Exchange(ctx, code)
|
||||
if err != nil {
|
||||
log.Debug("Failed to exchange code for token: ", err)
|
||||
return nil, fmt.Errorf("invalid twitch exchange code: %s", err.Error())
|
||||
}
|
||||
verifier := oauth.OIDCProviders.MicrosoftOIDC.Verifier(&oidc.Config{ClientID: oauth.OAuthProviders.MicrosoftConfig.ClientID})
|
||||
|
||||
// Extract the ID Token from OAuth2 token.
|
||||
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||
if !ok {
|
||||
log.Debug("Failed to extract ID Token from OAuth2 token")
|
||||
return nil, fmt.Errorf("unable to extract id_token")
|
||||
return user, fmt.Errorf("unable to extract id_token")
|
||||
}
|
||||
verifier := oauth.OIDCProviders.TwitchOIDC.Verifier(&oidc.Config{
|
||||
ClientID: oauth.OAuthProviders.TwitchConfig.ClientID,
|
||||
SkipIssuerCheck: true,
|
||||
})
|
||||
|
||||
// Parse and verify ID Token payload.
|
||||
idToken, err := verifier.Verify(ctx, rawIDToken)
|
||||
if err != nil {
|
||||
log.Debug("Failed to verify ID Token: ", err)
|
||||
return nil, fmt.Errorf("unable to verify id_token: %s", err.Error())
|
||||
return user, fmt.Errorf("unable to verify id_token: %s", err.Error())
|
||||
}
|
||||
|
||||
user := &models.User{}
|
||||
if err := idToken.Claims(&user); err != nil {
|
||||
log.Debug("Failed to parse ID Token claims: ", err)
|
||||
return nil, fmt.Errorf("unable to extract claims")
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// process roblox user information
|
||||
func processRobloxUserInfo(ctx context.Context, code, verifier string) (*models.User, error) {
|
||||
oauth2Token, err := oauth.OAuthProviders.RobloxConfig.Exchange(ctx, code, oauth2.SetAuthURLParam("code_verifier", verifier))
|
||||
if err != nil {
|
||||
log.Debug("Failed to exchange code for token: ", err)
|
||||
return nil, fmt.Errorf("invalid roblox exchange code: %s", err.Error())
|
||||
}
|
||||
|
||||
client := http.Client{}
|
||||
req, err := http.NewRequest("GET", constants.RobloxUserInfoURL, nil)
|
||||
if err != nil {
|
||||
log.Debug("Failed to create roblox user info request: ", err)
|
||||
return nil, fmt.Errorf("error creating roblox user info request: %s", err.Error())
|
||||
}
|
||||
req.Header = http.Header{
|
||||
"Authorization": []string{fmt.Sprintf("Bearer %s", oauth2Token.AccessToken)},
|
||||
}
|
||||
|
||||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Debug("Failed to request roblox user info: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Debug("Failed to read roblox user info response body: ", err)
|
||||
return nil, fmt.Errorf("failed to read roblox response body: %s", err.Error())
|
||||
}
|
||||
|
||||
if response.StatusCode >= 400 {
|
||||
log.Debug("Failed to request roblox user info: ", string(body))
|
||||
return nil, fmt.Errorf("failed to request roblox user info: %s", string(body))
|
||||
}
|
||||
|
||||
userRawData := make(map[string]interface{})
|
||||
json.Unmarshal(body, &userRawData)
|
||||
|
||||
// log.Info(userRawData)
|
||||
nameArr := strings.SplitAfterN(userRawData["name"].(string), " ", 2)
|
||||
firstName := nameArr[0]
|
||||
lastName := ""
|
||||
if len(nameArr) == 2 {
|
||||
lastName = nameArr[1]
|
||||
}
|
||||
nickname := userRawData["nickname"].(string)
|
||||
profilePicture := userRawData["picture"].(string)
|
||||
email := ""
|
||||
if val, ok := userRawData["email"]; ok {
|
||||
email = val.(string)
|
||||
} else {
|
||||
email = userRawData["sub"].(string)
|
||||
}
|
||||
user := &models.User{
|
||||
GivenName: &firstName,
|
||||
FamilyName: &lastName,
|
||||
Picture: &profilePicture,
|
||||
Nickname: &nickname,
|
||||
Email: &email,
|
||||
return user, fmt.Errorf("unable to extract claims")
|
||||
}
|
||||
|
||||
return user, nil
|
||||
|
|
|
@ -4,11 +4,9 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
|
@ -40,8 +38,11 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
|||
}
|
||||
|
||||
if state == "" {
|
||||
log.Debug("state is empty. creating a new state")
|
||||
state = uuid.New().String()
|
||||
log.Debug("state is empty")
|
||||
c.JSON(400, gin.H{
|
||||
"error": "invalid state",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var scope []string
|
||||
|
@ -189,24 +190,6 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
|||
oauth.OAuthProviders.TwitterConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodTwitter
|
||||
url := oauth.OAuthProviders.TwitterConfig.AuthCodeURL(oauthStateString, oauth2.SetAuthURLParam("code_challenge", challenge), oauth2.SetAuthURLParam("code_challenge_method", "S256"))
|
||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||
|
||||
case constants.AuthRecipeMethodDiscord:
|
||||
if oauth.OAuthProviders.DiscordConfig == nil {
|
||||
log.Debug("Discord OAuth provider is not configured")
|
||||
isProviderConfigured = false
|
||||
break
|
||||
}
|
||||
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodDiscord)
|
||||
if err != nil {
|
||||
log.Debug("Error setting state: ", err)
|
||||
c.JSON(500, gin.H{
|
||||
"error": "internal server error",
|
||||
})
|
||||
return
|
||||
}
|
||||
oauth.OAuthProviders.DiscordConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodDiscord
|
||||
url := oauth.OAuthProviders.DiscordConfig.AuthCodeURL(oauthStateString)
|
||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||
case constants.AuthRecipeMethodApple:
|
||||
if oauth.OAuthProviders.AppleConfig == nil {
|
||||
log.Debug("Apple OAuth provider is not configured")
|
||||
|
@ -244,42 +227,6 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
|||
oauth.OAuthProviders.MicrosoftConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodMicrosoft
|
||||
url := oauth.OAuthProviders.MicrosoftConfig.AuthCodeURL(oauthStateString)
|
||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||
case constants.AuthRecipeMethodTwitch:
|
||||
if oauth.OAuthProviders.TwitchConfig == nil {
|
||||
log.Debug("Twitch OAuth provider is not configured")
|
||||
isProviderConfigured = false
|
||||
break
|
||||
}
|
||||
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodTwitch)
|
||||
if err != nil {
|
||||
log.Debug("Error setting state: ", err)
|
||||
c.JSON(500, gin.H{
|
||||
"error": "internal server error",
|
||||
})
|
||||
return
|
||||
}
|
||||
// during the init of OAuthProvider authorizer url might be empty
|
||||
oauth.OAuthProviders.TwitchConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodTwitch
|
||||
url := oauth.OAuthProviders.TwitchConfig.AuthCodeURL(oauthStateString)
|
||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||
case constants.AuthRecipeMethodRoblox:
|
||||
if oauth.OAuthProviders.RobloxConfig == nil {
|
||||
log.Debug("RobloxConfig OAuth provider is not configured")
|
||||
isProviderConfigured = false
|
||||
break
|
||||
}
|
||||
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodRoblox)
|
||||
if err != nil {
|
||||
log.Debug("Error setting state: ", err)
|
||||
c.JSON(500, gin.H{
|
||||
"error": "internal server error",
|
||||
})
|
||||
return
|
||||
}
|
||||
// during the init of OAuthProvider authorizer url might be empty
|
||||
oauth.OAuthProviders.RobloxConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodRoblox
|
||||
url := oauth.OAuthProviders.RobloxConfig.AuthCodeURL(oauthStateString)
|
||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||
default:
|
||||
log.Debug("Invalid oauth provider: ", provider)
|
||||
c.JSON(422, gin.H{
|
||||
|
|
|
@ -24,7 +24,7 @@ func OpenIDConfigurationHandler() gin.HandlerFunc {
|
|||
"response_types_supported": []string{"code", "token", "id_token"},
|
||||
"scopes_supported": []string{"openid", "email", "profile"},
|
||||
"response_modes_supported": []string{"query", "fragment", "form_post", "web_message"},
|
||||
"subject_types_supported": []string{"public"},
|
||||
"subject_types_supported": "public",
|
||||
"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"},
|
||||
})
|
||||
|
|
|
@ -1,44 +1,15 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql/playground"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/token"
|
||||
)
|
||||
|
||||
// PlaygroundHandler is the handler for the /playground route
|
||||
func PlaygroundHandler() gin.HandlerFunc {
|
||||
h := playground.Handler("GraphQL", "/graphql")
|
||||
|
||||
return func(c *gin.Context) {
|
||||
var h http.HandlerFunc
|
||||
|
||||
disablePlayground, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePlayGround)
|
||||
if err != nil {
|
||||
log.Debug("error while getting disable playground value")
|
||||
disablePlayground = false
|
||||
}
|
||||
|
||||
// if env set to false, then check if logged in as super admin, if logged in then return graphql else 401 error
|
||||
// if env set to true, then disabled the playground with 404 error
|
||||
if !disablePlayground {
|
||||
if token.IsSuperAdmin(c) {
|
||||
h = playground.Handler("GraphQL", "/graphql")
|
||||
} else {
|
||||
log.Debug("not logged in as super admin")
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "not logged in as super admin"})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
log.Debug("playground is disabled")
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "playground is disabled"})
|
||||
return
|
||||
}
|
||||
h.ServeHTTP(c.Writer, c.Request)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,13 +24,9 @@ func RevokeRefreshTokenHandler() gin.HandlerFunc {
|
|||
})
|
||||
return
|
||||
}
|
||||
// get client ID
|
||||
clientID := strings.TrimSpace(reqBody["client_id"]) // kept for backward compatibility // else we expect to be present as header
|
||||
if clientID == "" {
|
||||
clientID = gc.Request.Header.Get("x-authorizer-client-id")
|
||||
}
|
||||
// get fingerprint hash
|
||||
refreshToken := strings.TrimSpace(reqBody["refresh_token"])
|
||||
clientID := strings.TrimSpace(reqBody["client_id"])
|
||||
|
||||
if clientID == "" {
|
||||
log.Debug("Client ID is empty")
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user