Compare commits
71 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5758fe1e2c | ||
![]() |
9c27d7fcab | ||
![]() |
282c700431 | ||
acc471e500 | |||
586b2cc3af | |||
6a4b3553af | |||
48e1dbf8aa | |||
55121656a8 | |||
e9f54a74f0 | |||
bfa192d21e | |||
800fc4f8d8 | |||
86453d483e | |||
7d5d31692f | |||
5745a9b3c4 | |||
641c5bc248 | |||
085faf73e7 | |||
3197154fec | |||
b8f5e9ebb9 | |||
76f976937a | |||
693f252ae9 | |||
12af7fc617 | |||
32eaff5c5d | |||
0b823ffc33 | |||
42017035fc | |||
c18209418f | |||
c8ba8c1453 | |||
04a8e292c0 | |||
![]() |
9336d3e003 | ||
![]() |
c6f19a82a4 | ||
![]() |
28390ebbe4 | ||
![]() |
5add964449 | ||
![]() |
4eb8ca0d65 | ||
![]() |
d924e36786 | ||
![]() |
d0e6392f1a | ||
![]() |
b931652769 | ||
fb65fcbad5 | |||
79d2d52fc0 | |||
2a766d587f | |||
5c33b159dc | |||
![]() |
82f639757f | ||
![]() |
28b574c827 | ||
![]() |
67f866a787 | ||
5616186be7 | |||
4351f5cd32 | |||
29026ed6fb | |||
f244330401 | |||
132f965c8b | |||
8deba4849d | |||
3a3407f85e | |||
7a1df30325 | |||
d9fd6c2b36 | |||
11472d5b06 | |||
3502d8b3d1 | |||
7c949417c1 | |||
09e4daf66e | |||
32f903f40a | |||
348a9426cc | |||
9ddbfb5df7 | |||
9fa248ca41 | |||
0b0ab12bf0 | |||
be58bb8c6d | |||
cdad58bd02 | |||
934f433dd2 | |||
d6fec9121c | |||
f9e1316145 | |||
362d410e37 | |||
78930dc8f3 | |||
baeb5a68ea | |||
040f7ead7e | |||
3246d32a23 | |||
ce5b09953e |
|
@ -1,4 +1,4 @@
|
||||||
name: 'deploy'
|
name: "deploy"
|
||||||
on: [push]
|
on: [push]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
@ -18,18 +18,19 @@ jobs:
|
||||||
id: branch_name
|
id: branch_name
|
||||||
run: echo "::set-output name=branch::$(echo ${GITHUB_REF##*/})"
|
run: echo "::set-output name=branch::$(echo ${GITHUB_REF##*/})"
|
||||||
|
|
||||||
- name: Push to dokku for main branch
|
- name: Push branch 'discours-dev' to staging
|
||||||
if: steps.branch_name.outputs.branch == 'mailgun'
|
if: steps.branch_name.outputs.branch == 'discours-dev'
|
||||||
uses: dokku/github-action@master
|
uses: dokku/github-action@master
|
||||||
with:
|
with:
|
||||||
branch: 'main'
|
branch: "main"
|
||||||
git_remote_url: 'ssh://dokku@v2.discours.io:22/authorizer'
|
git_remote_url: "ssh://dokku@staging.discours.io:22/authorizer"
|
||||||
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
|
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
|
||||||
- name: Push to dokku for dev branch
|
- name: Push branch 'discours' to v2.discours.io
|
||||||
if: steps.branch_name.outputs.branch == 'dev'
|
if: steps.branch_name.outputs.branch == 'discours'
|
||||||
uses: dokku/github-action@master
|
uses: dokku/github-action@master
|
||||||
with:
|
with:
|
||||||
branch: 'main'
|
branch: "main"
|
||||||
git_remote_url: 'ssh://dokku@staging.discours.io:22/authorizer'
|
git_remote_url: "ssh://dokku@v2.discours.io:22/authorizer"
|
||||||
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
|
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
git_push_flags: '--force'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM golang:1.21.3-alpine3.18 as go-builder
|
FROM golang:1.21.3-alpine3.18 AS go-builder
|
||||||
WORKDIR /authorizer
|
WORKDIR /authorizer
|
||||||
COPY server server
|
COPY server server
|
||||||
COPY Makefile .
|
COPY Makefile .
|
||||||
|
@ -11,7 +11,7 @@ RUN apk add build-base &&\
|
||||||
make clean && make && \
|
make clean && make && \
|
||||||
chmod 777 build/server
|
chmod 777 build/server
|
||||||
|
|
||||||
FROM node:20-alpine3.18 as node-builder
|
FROM node:20-alpine3.18 AS node-builder
|
||||||
WORKDIR /authorizer
|
WORKDIR /authorizer
|
||||||
COPY app app
|
COPY app app
|
||||||
COPY dashboard dashboard
|
COPY dashboard dashboard
|
||||||
|
|
16
app/package-lock.json
generated
16
app/package-lock.json
generated
|
@ -9,7 +9,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^1.2.0",
|
"@authorizerdev/authorizer-react": "^1.3.2",
|
||||||
"@types/react": "^17.0.15",
|
"@types/react": "^17.0.15",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.9",
|
||||||
"esbuild": "^0.12.17",
|
"esbuild": "^0.12.17",
|
||||||
|
@ -27,9 +27,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@authorizerdev/authorizer-js": {
|
"node_modules/@authorizerdev/authorizer-js": {
|
||||||
"version": "2.0.0-beta.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-2.0.0-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-2.0.3.tgz",
|
||||||
"integrity": "sha512-cEzEVe7AewvOwOwoettiKRCq1e5Y33k9g8fJjqAoe3B/36iNN8wnZ5qgsPPZkqhv+Cvn6huj+YWtRimfVJ6d0w==",
|
"integrity": "sha512-uencwr3Ea8mwfxVKDFf2ITRCRSmzvua+O2voRuiWQORtRQTgZQjkN3M+IEkEj+WP9M1iFIl+NDgzECsp8ptC/A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-fetch": "^3.1.5"
|
"cross-fetch": "^3.1.5"
|
||||||
},
|
},
|
||||||
|
@ -41,11 +41,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@authorizerdev/authorizer-react": {
|
"node_modules/@authorizerdev/authorizer-react": {
|
||||||
"version": "1.2.0",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.3.2.tgz",
|
||||||
"integrity": "sha512-MtunZgh30rzY9jSADVP1DRC4sOBC82zx/yhK8O/1ufOAi7vTDZwPjDHIMrG/xWPNUYTCeFPEKpZlKyB+TH/M1w==",
|
"integrity": "sha512-3kMAygHBCa8Fc9Oo0lz1k88r+Pd6kx1PSn3NMYLwxQXy2jRt4xWn7iuGn+SDGFs3DzofaN71I61gRwQ+6dO1rw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-js": "^2.0.0-beta.3",
|
"@authorizerdev/authorizer-js": "^2.0.3",
|
||||||
"validator": "^13.11.0"
|
"validator": "^13.11.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"author": "Lakhan Samani",
|
"author": "Lakhan Samani",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^1.2.0",
|
"@authorizerdev/authorizer-react": "^1.3.2",
|
||||||
"@types/react": "^17.0.15",
|
"@types/react": "^17.0.15",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.9",
|
||||||
"esbuild": "^0.12.17",
|
"esbuild": "^0.12.17",
|
||||||
|
|
|
@ -33,7 +33,6 @@ export default function App() {
|
||||||
...window['__authorizer__'],
|
...window['__authorizer__'],
|
||||||
...urlProps,
|
...urlProps,
|
||||||
};
|
};
|
||||||
console.log({ globalState });
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|
786
app/yarn.lock
786
app/yarn.lock
File diff suppressed because it is too large
Load Diff
BIN
dashboard/public/roblox.png
Normal file
BIN
dashboard/public/roblox.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
|
@ -53,7 +53,7 @@ const Features = ({ variables, setVariables }: any) => {
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex>
|
<Flex>
|
||||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
<Text fontSize="sm">Basic Authentication:</Text>
|
<Text fontSize="sm">Email Basic Authentication:</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex justifyContent="start">
|
<Flex justifyContent="start">
|
||||||
<InputField
|
<InputField
|
||||||
|
@ -64,6 +64,19 @@ const Features = ({ variables, setVariables }: any) => {
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</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>
|
||||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
<Text fontSize="sm">Sign Up:</Text>
|
<Text fontSize="sm">Sign Up:</Text>
|
||||||
|
|
|
@ -17,7 +17,8 @@ import {
|
||||||
FaApple,
|
FaApple,
|
||||||
FaTwitter,
|
FaTwitter,
|
||||||
FaMicrosoft,
|
FaMicrosoft,
|
||||||
FaTwitch, FaDiscord,
|
FaTwitch,
|
||||||
|
FaDiscord,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import {
|
import {
|
||||||
TextInputType,
|
TextInputType,
|
||||||
|
@ -474,6 +475,47 @@ const OAuthConfig = ({
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||||
|
h="35px"
|
||||||
|
marginRight="1.5%"
|
||||||
|
border="1px solid #3b5998"
|
||||||
|
borderRadius="5px"
|
||||||
|
>
|
||||||
|
<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>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,6 +14,7 @@ export const TextInputType = {
|
||||||
MICROSOFT_CLIENT_ID: 'MICROSOFT_CLIENT_ID',
|
MICROSOFT_CLIENT_ID: 'MICROSOFT_CLIENT_ID',
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: 'MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID',
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: 'MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID',
|
||||||
TWITCH_CLIENT_ID: 'TWITCH_CLIENT_ID',
|
TWITCH_CLIENT_ID: 'TWITCH_CLIENT_ID',
|
||||||
|
ROBLOX_CLIENT_ID: 'ROBLOX_CLIENT_ID',
|
||||||
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
||||||
REDIS_URL: 'REDIS_URL',
|
REDIS_URL: 'REDIS_URL',
|
||||||
SMTP_HOST: 'SMTP_HOST',
|
SMTP_HOST: 'SMTP_HOST',
|
||||||
|
@ -46,6 +47,7 @@ export const HiddenInputType = {
|
||||||
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
||||||
MICROSOFT_CLIENT_SECRET: 'MICROSOFT_CLIENT_SECRET',
|
MICROSOFT_CLIENT_SECRET: 'MICROSOFT_CLIENT_SECRET',
|
||||||
TWITCH_CLIENT_SECRET: 'TWITCH_CLIENT_SECRET',
|
TWITCH_CLIENT_SECRET: 'TWITCH_CLIENT_SECRET',
|
||||||
|
ROBLOX_CLIENT_SECRET: 'ROBLOX_CLIENT_SECRET',
|
||||||
JWT_SECRET: 'JWT_SECRET',
|
JWT_SECRET: 'JWT_SECRET',
|
||||||
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
||||||
ADMIN_SECRET: 'ADMIN_SECRET',
|
ADMIN_SECRET: 'ADMIN_SECRET',
|
||||||
|
@ -83,6 +85,7 @@ export const SwitchInputType = {
|
||||||
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
|
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
|
||||||
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
|
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
|
||||||
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
|
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
|
||||||
|
DISABLE_MOBILE_BASIC_AUTHENTICATION: 'DISABLE_MOBILE_BASIC_AUTHENTICATION',
|
||||||
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
|
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
|
||||||
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
|
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
|
||||||
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
|
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
|
||||||
|
@ -140,6 +143,8 @@ export interface envVarTypes {
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: string;
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: string;
|
||||||
TWITCH_CLIENT_ID: string;
|
TWITCH_CLIENT_ID: string;
|
||||||
TWITCH_CLIENT_SECRET: string;
|
TWITCH_CLIENT_SECRET: string;
|
||||||
|
ROBLOX_CLIENT_ID: string;
|
||||||
|
ROBLOX_CLIENT_SECRET: string;
|
||||||
ROLES: [string] | [];
|
ROLES: [string] | [];
|
||||||
DEFAULT_ROLES: [string] | [];
|
DEFAULT_ROLES: [string] | [];
|
||||||
PROTECTED_ROLES: [string] | [];
|
PROTECTED_ROLES: [string] | [];
|
||||||
|
@ -167,6 +172,7 @@ export interface envVarTypes {
|
||||||
DISABLE_MAGIC_LINK_LOGIN: boolean;
|
DISABLE_MAGIC_LINK_LOGIN: boolean;
|
||||||
DISABLE_EMAIL_VERIFICATION: boolean;
|
DISABLE_EMAIL_VERIFICATION: boolean;
|
||||||
DISABLE_BASIC_AUTHENTICATION: boolean;
|
DISABLE_BASIC_AUTHENTICATION: boolean;
|
||||||
|
DISABLE_MOBILE_BASIC_AUTHENTICATION: boolean;
|
||||||
DISABLE_SIGN_UP: boolean;
|
DISABLE_SIGN_UP: boolean;
|
||||||
DISABLE_STRONG_PASSWORD: boolean;
|
DISABLE_STRONG_PASSWORD: boolean;
|
||||||
OLD_ADMIN_SECRET: string;
|
OLD_ADMIN_SECRET: string;
|
||||||
|
|
|
@ -39,6 +39,8 @@ export const EnvVariablesQuery = `
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID
|
||||||
TWITCH_CLIENT_ID
|
TWITCH_CLIENT_ID
|
||||||
TWITCH_CLIENT_SECRET
|
TWITCH_CLIENT_SECRET
|
||||||
|
ROBLOX_CLIENT_ID
|
||||||
|
ROBLOX_CLIENT_SECRET
|
||||||
DEFAULT_ROLES
|
DEFAULT_ROLES
|
||||||
PROTECTED_ROLES
|
PROTECTED_ROLES
|
||||||
ROLES
|
ROLES
|
||||||
|
@ -65,6 +67,7 @@ export const EnvVariablesQuery = `
|
||||||
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_SIGN_UP
|
DISABLE_SIGN_UP
|
||||||
DISABLE_STRONG_PASSWORD
|
DISABLE_STRONG_PASSWORD
|
||||||
DISABLE_REDIS_FOR_ENV
|
DISABLE_REDIS_FOR_ENV
|
||||||
|
@ -97,6 +100,7 @@ export const UserDetailsQuery = `
|
||||||
id
|
id
|
||||||
email
|
email
|
||||||
email_verified
|
email_verified
|
||||||
|
phone_number_verified
|
||||||
given_name
|
given_name
|
||||||
family_name
|
family_name
|
||||||
middle_name
|
middle_name
|
||||||
|
|
|
@ -59,6 +59,8 @@ const Environment = () => {
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: '',
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: '',
|
||||||
TWITCH_CLIENT_ID: '',
|
TWITCH_CLIENT_ID: '',
|
||||||
TWITCH_CLIENT_SECRET: '',
|
TWITCH_CLIENT_SECRET: '',
|
||||||
|
ROBLOX_CLIENT_ID: '',
|
||||||
|
ROBLOX_CLIENT_SECRET: '',
|
||||||
ROLES: [],
|
ROLES: [],
|
||||||
DEFAULT_ROLES: [],
|
DEFAULT_ROLES: [],
|
||||||
PROTECTED_ROLES: [],
|
PROTECTED_ROLES: [],
|
||||||
|
@ -86,6 +88,7 @@ const Environment = () => {
|
||||||
DISABLE_MAGIC_LINK_LOGIN: false,
|
DISABLE_MAGIC_LINK_LOGIN: false,
|
||||||
DISABLE_EMAIL_VERIFICATION: false,
|
DISABLE_EMAIL_VERIFICATION: false,
|
||||||
DISABLE_BASIC_AUTHENTICATION: false,
|
DISABLE_BASIC_AUTHENTICATION: false,
|
||||||
|
DISABLE_MOBILE_BASIC_AUTHENTICATION: false,
|
||||||
DISABLE_SIGN_UP: false,
|
DISABLE_SIGN_UP: false,
|
||||||
DISABLE_STRONG_PASSWORD: false,
|
DISABLE_STRONG_PASSWORD: false,
|
||||||
OLD_ADMIN_SECRET: '',
|
OLD_ADMIN_SECRET: '',
|
||||||
|
|
|
@ -165,14 +165,25 @@ export default function Users() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const userVerificationHandler = async (user: userDataTypes) => {
|
const userVerificationHandler = async (user: userDataTypes) => {
|
||||||
const { id, email } = user;
|
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 res = await client
|
const res = await client
|
||||||
.mutation(UpdateUser, {
|
.mutation(UpdateUser, {
|
||||||
params: {
|
params,
|
||||||
id,
|
|
||||||
email,
|
|
||||||
email_verified: true,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.toPromise();
|
.toPromise();
|
||||||
if (res.error) {
|
if (res.error) {
|
||||||
|
@ -298,7 +309,7 @@ export default function Users() {
|
||||||
<Table variant="simple">
|
<Table variant="simple">
|
||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr>
|
||||||
<Th>Email</Th>
|
<Th>Email / Phone</Th>
|
||||||
<Th>Created At</Th>
|
<Th>Created At</Th>
|
||||||
<Th>Signup Methods</Th>
|
<Th>Signup Methods</Th>
|
||||||
<Th>Roles</Th>
|
<Th>Roles</Th>
|
||||||
|
@ -314,10 +325,15 @@ export default function Users() {
|
||||||
</Thead>
|
</Thead>
|
||||||
<Tbody>
|
<Tbody>
|
||||||
{userList.map((user: userDataTypes) => {
|
{userList.map((user: userDataTypes) => {
|
||||||
const { email_verified, created_at, ...rest }: any = user;
|
const {
|
||||||
|
email_verified,
|
||||||
|
phone_number_verified,
|
||||||
|
created_at,
|
||||||
|
...rest
|
||||||
|
}: any = user;
|
||||||
return (
|
return (
|
||||||
<Tr key={user.id} style={{ fontSize: 14 }}>
|
<Tr key={user.id} style={{ fontSize: 14 }}>
|
||||||
<Td maxW="300">{user.email}</Td>
|
<Td maxW="300">{user.email || user.phone_number}</Td>
|
||||||
<Td>
|
<Td>
|
||||||
{dayjs(user.created_at * 1000).format('MMM DD, YYYY')}
|
{dayjs(user.created_at * 1000).format('MMM DD, YYYY')}
|
||||||
</Td>
|
</Td>
|
||||||
|
@ -327,9 +343,15 @@ export default function Users() {
|
||||||
<Tag
|
<Tag
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
colorScheme={user.email_verified ? 'green' : 'yellow'}
|
colorScheme={
|
||||||
|
user.email_verified || user.phone_number_verified
|
||||||
|
? 'green'
|
||||||
|
: 'yellow'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{user.email_verified.toString()}
|
{(
|
||||||
|
user.email_verified || user.phone_number_verified
|
||||||
|
).toString()}
|
||||||
</Tag>
|
</Tag>
|
||||||
</Td>
|
</Td>
|
||||||
<Td>
|
<Td>
|
||||||
|
@ -368,13 +390,14 @@ export default function Users() {
|
||||||
</Flex>
|
</Flex>
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
<MenuList>
|
<MenuList>
|
||||||
{!user.email_verified && (
|
{!user.email_verified &&
|
||||||
<MenuItem
|
!user.phone_number_verified && (
|
||||||
onClick={() => userVerificationHandler(user)}
|
<MenuItem
|
||||||
>
|
onClick={() => userVerificationHandler(user)}
|
||||||
Verify User
|
>
|
||||||
</MenuItem>
|
Verify User
|
||||||
)}
|
</MenuItem>
|
||||||
|
)}
|
||||||
<EditUserModal
|
<EditUserModal
|
||||||
user={rest}
|
user={rest}
|
||||||
updateUserList={updateUserList}
|
updateUserList={updateUserList}
|
||||||
|
|
2114
dashboard/yarn.lock
2114
dashboard/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -27,4 +27,6 @@ const (
|
||||||
AuthRecipeMethodMicrosoft = "microsoft"
|
AuthRecipeMethodMicrosoft = "microsoft"
|
||||||
// AuthRecipeMethodTwitch is the twitch auth method
|
// AuthRecipeMethodTwitch is the twitch auth method
|
||||||
AuthRecipeMethodTwitch = "twitch"
|
AuthRecipeMethodTwitch = "twitch"
|
||||||
|
// AuthRecipeMethodRoblox is the roblox auth method
|
||||||
|
AuthRecipeMethodRoblox = "roblox"
|
||||||
)
|
)
|
||||||
|
|
|
@ -126,6 +126,10 @@ const (
|
||||||
EnvKeyTwitchClientID = "TWITCH_CLIENT_ID"
|
EnvKeyTwitchClientID = "TWITCH_CLIENT_ID"
|
||||||
// EnvKeyTwitchClientSecret key for env variable TWITCH_CLIENT_SECRET
|
// EnvKeyTwitchClientSecret key for env variable TWITCH_CLIENT_SECRET
|
||||||
EnvKeyTwitchClientSecret = "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 key for env variable ORGANIZATION_NAME
|
||||||
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
||||||
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
||||||
|
|
|
@ -17,6 +17,9 @@ const (
|
||||||
|
|
||||||
TwitterUserInfoURL = "https://api.twitter.com/2/users/me?user.fields=id,name,profile_image_url,username"
|
TwitterUserInfoURL = "https://api.twitter.com/2/users/me?user.fields=id,name,profile_image_url,username"
|
||||||
|
|
||||||
|
// 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"
|
DiscordUserInfoURL = "https://discord.com/api/oauth2/@me"
|
||||||
// Get microsoft user info.
|
// Get microsoft user info.
|
||||||
// Ref: https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo
|
// Ref: https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo
|
||||||
|
|
|
@ -11,8 +11,8 @@ const (
|
||||||
type OTP struct {
|
type OTP struct {
|
||||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||||
Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
Email string `gorm:"index" 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"`
|
PhoneNumber string `gorm:"index" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number"`
|
||||||
Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"`
|
Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"`
|
||||||
ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"`
|
ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"`
|
||||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" 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
|
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||||
|
|
||||||
Email *string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
Email *string `gorm:"index" 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"`
|
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"`
|
Password *string `json:"password" bson:"password" cql:"password" dynamo:"password"`
|
||||||
SignupMethods string `json:"signup_methods" bson:"signup_methods" cql:"signup_methods" dynamo:"signup_methods"`
|
SignupMethods string `json:"signup_methods" bson:"signup_methods" cql:"signup_methods" dynamo:"signup_methods"`
|
||||||
|
|
|
@ -28,7 +28,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
||||||
authenticatorsCollection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
authenticatorsCollection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
||||||
meta, err := authenticatorsCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), authenticators)
|
meta, err := authenticatorsCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), authenticators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
authenticators.Key = meta.Key
|
authenticators.Key = meta.Key
|
||||||
authenticators.ID = meta.ID.String()
|
authenticators.ID = meta.ID.String()
|
||||||
|
@ -42,7 +42,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
||||||
collection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
collection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
||||||
meta, err := collection.UpdateDocument(ctx, authenticators.Key, authenticators)
|
meta, err := collection.UpdateDocument(ctx, authenticators.Key, authenticators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticators.Key = meta.Key
|
authenticators.Key = meta.Key
|
||||||
|
@ -59,7 +59,7 @@ func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId s
|
||||||
}
|
}
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
for {
|
for {
|
||||||
|
@ -71,7 +71,7 @@ func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId s
|
||||||
}
|
}
|
||||||
_, err := cursor.ReadDocument(ctx, &authenticators)
|
_, err := cursor.ReadDocument(ctx, &authenticators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return authenticators, nil
|
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)
|
configCollection, _ := p.db.Collection(ctx, models.Collections.Env)
|
||||||
meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), env)
|
meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
env.Key = meta.Key
|
env.Key = meta.Key
|
||||||
env.ID = meta.ID.String()
|
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)
|
collection, _ := p.db.Collection(ctx, models.Collections.Env)
|
||||||
meta, err := collection.UpdateDocument(ctx, env.Key, env)
|
meta, err := collection.UpdateDocument(ctx, env.Key, env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
env.Key = meta.Key
|
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)
|
query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.Env)
|
||||||
cursor, err := p.db.Query(ctx, query, nil)
|
cursor, err := p.db.Query(ctx, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
for {
|
for {
|
||||||
|
@ -62,7 +62,7 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
||||||
}
|
}
|
||||||
_, err := cursor.ReadDocument(ctx, &env)
|
_, err := cursor.ReadDocument(ctx, &env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
if user.Roles == "" {
|
if user.Roles == "" {
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,10 @@ 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 {
|
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")
|
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.CreatedAt = time.Now().Unix()
|
||||||
|
@ -43,7 +47,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||||
meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), user)
|
meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Key = meta.Key
|
user.Key = meta.Key
|
||||||
user.ID = meta.ID.String()
|
user.ID = meta.ID.String()
|
||||||
|
@ -58,7 +62,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
||||||
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||||
meta, err := collection.UpdateDocument(ctx, user.Key, user)
|
meta, err := collection.UpdateDocument(ctx, user.Key, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Key = meta.Key
|
user.Key = meta.Key
|
||||||
|
@ -125,19 +129,19 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
||||||
}
|
}
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return user, fmt.Errorf("user not found")
|
return nil, fmt.Errorf("user not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
_, err := cursor.ReadDocument(ctx, &user)
|
_, err := cursor.ReadDocument(ctx, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
|
@ -152,19 +156,19 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
||||||
}
|
}
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return user, fmt.Errorf("user not found")
|
return nil, fmt.Errorf("user not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
_, err := cursor.ReadDocument(ctx, &user)
|
_, err := cursor.ReadDocument(ctx, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
|
|
|
@ -22,7 +22,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
||||||
verificationRequestRequestCollection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
|
verificationRequestRequestCollection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
|
||||||
meta, err := verificationRequestRequestCollection.CreateDocument(ctx, verificationRequest)
|
meta, err := verificationRequestRequestCollection.CreateDocument(ctx, verificationRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
verificationRequest.Key = meta.Key
|
verificationRequest.Key = meta.Key
|
||||||
verificationRequest.ID = meta.ID.String()
|
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)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
for {
|
for {
|
||||||
|
@ -50,7 +50,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
||||||
}
|
}
|
||||||
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
|
@ -66,7 +66,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
||||||
}
|
}
|
||||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close()
|
defer cursor.Close()
|
||||||
for {
|
for {
|
||||||
|
@ -78,7 +78,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
||||||
}
|
}
|
||||||
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
|
|
|
@ -29,7 +29,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
||||||
|
|
||||||
bytes, err := json.Marshal(authenticators)
|
bytes, err := json.Marshal(authenticators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
|
@ -38,7 +38,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
||||||
authenticatorsMap := map[string]interface{}{}
|
authenticatorsMap := map[string]interface{}{}
|
||||||
err = decoder.Decode(&authenticatorsMap)
|
err = decoder.Decode(&authenticatorsMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := "("
|
fields := "("
|
||||||
|
@ -66,7 +66,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
||||||
query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.Authenticators, fields, values)
|
query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.Authenticators, fields, values)
|
||||||
err = p.db.Query(query).Exec()
|
err = p.db.Query(query).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return authenticators, nil
|
return authenticators, nil
|
||||||
|
@ -77,7 +77,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
||||||
|
|
||||||
bytes, err := json.Marshal(authenticators)
|
bytes, err := json.Marshal(authenticators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||||
|
@ -85,7 +85,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
||||||
authenticatorsMap := map[string]interface{}{}
|
authenticatorsMap := map[string]interface{}{}
|
||||||
err = decoder.Decode(&authenticatorsMap)
|
err = decoder.Decode(&authenticatorsMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFields := ""
|
updateFields := ""
|
||||||
|
@ -116,7 +116,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
||||||
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Authenticators, updateFields, authenticators.ID)
|
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Authenticators, updateFields, authenticators.ID)
|
||||||
err = p.db.Query(query).Exec()
|
err = p.db.Query(query).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return authenticators, nil
|
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)
|
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()
|
err := p.db.Query(insertEnvQuery).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return env, nil
|
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)
|
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()
|
err := p.db.Query(updateEnvQuery).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
if user.Roles == "" {
|
if user.Roles == "" {
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,10 @@ 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 {
|
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")
|
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.CreatedAt = time.Now().Unix()
|
||||||
|
@ -42,7 +46,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
|
|
||||||
bytes, err := json.Marshal(user)
|
bytes, err := json.Marshal(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
|
@ -51,7 +55,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
userMap := map[string]interface{}{}
|
userMap := map[string]interface{}{}
|
||||||
err = decoder.Decode(&userMap)
|
err = decoder.Decode(&userMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := "("
|
fields := "("
|
||||||
|
@ -80,7 +84,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
err = p.db.Query(query).Exec()
|
err = p.db.Query(query).Exec()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
|
@ -92,7 +96,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
||||||
|
|
||||||
bytes, err := json.Marshal(user)
|
bytes, err := json.Marshal(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||||
|
@ -100,7 +104,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
||||||
userMap := map[string]interface{}{}
|
userMap := map[string]interface{}{}
|
||||||
err = decoder.Decode(&userMap)
|
err = decoder.Decode(&userMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFields := ""
|
updateFields := ""
|
||||||
|
@ -131,7 +135,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)
|
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, updateFields, user.ID)
|
||||||
err = p.db.Query(query).Exec()
|
err = p.db.Query(query).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
|
|
|
@ -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)
|
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()
|
err := p.db.Query(query).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
||||||
}
|
}
|
||||||
_, err := p.db.Collection(models.Collections.Authenticators).Insert(authenticators.ID, authenticators, &insertOpt)
|
_, err := p.db.Collection(models.Collections.Authenticators).Insert(authenticators.ID, authenticators, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return authenticators, nil
|
return authenticators, nil
|
||||||
}
|
}
|
||||||
|
@ -71,11 +71,11 @@ func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId s
|
||||||
PositionalParameters: []interface{}{userId, authenticatorType},
|
PositionalParameters: []interface{}{userId, authenticatorType},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&authenticators)
|
err = q.One(&authenticators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return authenticators, nil
|
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)
|
_, err := p.db.Collection(models.Collections.Env).Insert(env.ID, env, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
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},
|
PositionalParameters: []interface{}{env.EnvData, env.UpdatedAt, env.UpdatedAt, env.ID},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
@ -55,11 +55,11 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&env)
|
err = q.One(&env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
env.Hash = env.EncryptionKey
|
env.Hash = env.EncryptionKey
|
||||||
return env, nil
|
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)
|
_, err := p.db.Collection(models.Collections.OTP).Insert(otp.ID, otp, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return otp, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
query := fmt.Sprintf(`UPDATE %s.%s SET otp=$1, expires_at=$2, updated_at=$3 WHERE _id=$4`, p.scopeName, models.Collections.OTP)
|
query := fmt.Sprintf(`UPDATE %s.%s SET otp=$1, expires_at=$2, updated_at=$3 WHERE _id=$4`, p.scopeName, 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},
|
PositionalParameters: []interface{}{otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return otp, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return otp, nil
|
return otp, nil
|
||||||
|
|
|
@ -127,7 +127,7 @@ func CreateBucketAndScope(cluster *gocb.Cluster, bucketName string, scopeName st
|
||||||
if scopeName != defaultScope {
|
if scopeName != defaultScope {
|
||||||
err = bucket.Collections().CreateScope(scopeName, nil)
|
err = bucket.Collections().CreateScope(scopeName, nil)
|
||||||
if err != nil && !errors.Is(err, gocb.ErrScopeExists) {
|
if err != nil && !errors.Is(err, gocb.ErrScopeExists) {
|
||||||
return bucket, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bucket, nil
|
return bucket, nil
|
||||||
|
|
|
@ -47,7 +47,7 @@ func (p *provider) GetTotalDocs(ctx context.Context, collection string) (int64,
|
||||||
})
|
})
|
||||||
queryRes.One(&totalDocs)
|
queryRes.One(&totalDocs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return totalDocs.Total, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return totalDocs.Total, nil
|
return totalDocs.Total, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,14 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
"github.com/couchbase/gocb/v2"
|
"github.com/couchbase/gocb/v2"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
@ -23,11 +25,21 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
if user.Roles == "" {
|
if user.Roles == "" {
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
|
}
|
||||||
|
} 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.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
insertOpt := gocb.InsertOptions{
|
insertOpt := gocb.InsertOptions{
|
||||||
|
@ -35,7 +47,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)
|
_, err := p.db.Collection(models.Collections.User).Insert(user.ID, user, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -48,7 +60,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
||||||
}
|
}
|
||||||
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &upsertOpt)
|
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &upsertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -110,11 +122,11 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
||||||
PositionalParameters: []interface{}{email},
|
PositionalParameters: []interface{}{email},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&user)
|
err = q.One(&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -129,11 +141,11 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
||||||
PositionalParameters: []interface{}{id},
|
PositionalParameters: []interface{}{id},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&user)
|
err = q.One(&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -182,11 +194,11 @@ func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string)
|
||||||
PositionalParameters: []interface{}{phoneNumber},
|
PositionalParameters: []interface{}{phoneNumber},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&user)
|
err = q.One(&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
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)
|
_, err := p.db.Collection(models.Collections.VerificationRequest).Insert(verificationRequest.ID, verificationRequest, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
@ -44,12 +44,12 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = queryResult.One(&verificationRequest)
|
err = queryResult.One(&verificationRequest)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
||||||
var verificationRequest *models.VerificationRequest
|
var verificationRequest *models.VerificationRequest
|
||||||
err = queryResult.One(&verificationRequest)
|
err = queryResult.One(&verificationRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
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)
|
_, err := p.db.Collection(models.Collections.Webhook).Insert(webhook.ID, webhook, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return webhook.AsAPIWebhook(), err
|
return nil, err
|
||||||
}
|
}
|
||||||
return webhook.AsAPIWebhook(), nil
|
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)
|
_, err := p.db.Collection(models.Collections.WebhookLog).Insert(webhookLog.ID, webhookLog, &insertOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return webhookLog.AsAPIWebhookLog(), err
|
return nil, err
|
||||||
}
|
}
|
||||||
return webhookLog.AsAPIWebhookLog(), nil
|
return webhookLog.AsAPIWebhookLog(), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
||||||
authenticators.UpdatedAt = time.Now().Unix()
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
err := collection.Put(authenticators).RunWithContext(ctx)
|
err := collection.Put(authenticators).RunWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return authenticators, nil
|
return authenticators, nil
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
||||||
authenticators.UpdatedAt = time.Now().Unix()
|
authenticators.UpdatedAt = time.Now().Unix()
|
||||||
err := UpdateByHashKey(collection, "id", authenticators.ID, authenticators)
|
err := UpdateByHashKey(collection, "id", authenticators.ID, authenticators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return authenticators, nil
|
return authenticators, nil
|
||||||
|
@ -51,7 +51,7 @@ func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId s
|
||||||
}
|
}
|
||||||
err := iter.Err()
|
err := iter.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return authenticators, nil
|
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()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
err := collection.Put(env).RunWithContext(ctx)
|
err := collection.Put(env).RunWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env,
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
err := UpdateByHashKey(collection, "id", env.ID, env)
|
err := UpdateByHashKey(collection, "id", env.ID, env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
||||||
iter := collection.Scan().Limit(1).Iter()
|
iter := collection.Scan().Limit(1).Iter()
|
||||||
for iter.NextWithContext(ctx, &env) {
|
for iter.NextWithContext(ctx, &env) {
|
||||||
if env == nil {
|
if env == nil {
|
||||||
return env, errors.New("no documets found")
|
return nil, errors.New("no documets found")
|
||||||
} else {
|
} else {
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,20 +26,24 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
if user.Roles == "" {
|
if user.Roles == "" {
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
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")
|
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.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
err := collection.Put(user).RunWithContext(ctx)
|
err := collection.Put(user).RunWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -51,7 +55,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
err := UpdateByHashKey(collection, "id", user.ID, user)
|
err := UpdateByHashKey(collection, "id", user.ID, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
|
@ -122,7 +126,7 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
||||||
user = users[0]
|
user = users[0]
|
||||||
return user, nil
|
return user, nil
|
||||||
} else {
|
} else {
|
||||||
return user, errors.New("no record found")
|
return nil, errors.New("no record found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +137,7 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
||||||
err := collection.Get("id", id).OneWithContext(ctx, &user)
|
err := collection.Get("id", id).OneWithContext(ctx, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if refs.StringValue(user.Email) == "" {
|
if refs.StringValue(user.Email) == "" {
|
||||||
return user, errors.New("no documets found")
|
return nil, errors.New("no documets found")
|
||||||
} else {
|
} else {
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
||||||
verificationRequest.UpdatedAt = time.Now().Unix()
|
verificationRequest.UpdatedAt = time.Now().Unix()
|
||||||
err := collection.Put(verificationRequest).RunWithContext(ctx)
|
err := collection.Put(verificationRequest).RunWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
|
@ -35,7 +35,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
||||||
}
|
}
|
||||||
err := iter.Err()
|
err := iter.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
||||||
}
|
}
|
||||||
err := iter.Err()
|
err := iter.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if webhook.ID == "" {
|
if webhook.ID == "" {
|
||||||
return webhook.AsAPIWebhook(), errors.New("no documets found")
|
return nil, errors.New("no documets found")
|
||||||
}
|
}
|
||||||
return webhook.AsAPIWebhook(), nil
|
return webhook.AsAPIWebhook(), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
||||||
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||||
_, err := authenticatorsCollection.InsertOne(ctx, authenticators)
|
_, err := authenticatorsCollection.InsertOne(ctx, authenticators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return authenticators, nil
|
return authenticators, nil
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
||||||
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
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})
|
_, err := authenticatorsCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": authenticators.ID}}, bson.M{"$set": authenticators})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return authenticators, nil
|
return authenticators, nil
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId s
|
||||||
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||||
err := authenticatorsCollection.FindOne(ctx, bson.M{"user_id": userId, "method": authenticatorType}).Decode(&authenticators)
|
err := authenticatorsCollection.FindOne(ctx, bson.M{"user_id": userId, "method": authenticatorType}).Decode(&authenticators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authenticators, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return authenticators, nil
|
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())
|
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||||
_, err := configCollection.InsertOne(ctx, env)
|
_, err := configCollection.InsertOne(ctx, env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
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())
|
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())
|
_, err := configCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return env, nil
|
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())
|
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||||
cursor, err := configCollection.Find(ctx, bson.M{}, options.Find())
|
cursor, err := configCollection.Find(ctx, bson.M{}, options.Find())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer cursor.Close(ctx)
|
defer cursor.Close(ctx)
|
||||||
for cursor.Next(nil) {
|
for cursor.Next(nil) {
|
||||||
err := cursor.Decode(&env)
|
err := cursor.Decode(&env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return env, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if env == nil {
|
if env == nil {
|
||||||
|
|
|
@ -2,12 +2,15 @@ package mongodb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
@ -23,17 +26,26 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
if user.Roles == "" {
|
if user.Roles == "" {
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
|
}
|
||||||
|
} 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.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
user.Key = user.ID
|
user.Key = user.ID
|
||||||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||||
_, err := userCollection.InsertOne(ctx, user)
|
_, err := userCollection.InsertOne(ctx, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -44,7 +56,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
||||||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
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())
|
_, err := userCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -103,7 +115,7 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
||||||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||||
err := userCollection.FindOne(ctx, bson.M{"email": email}).Decode(&user)
|
err := userCollection.FindOne(ctx, bson.M{"email": email}).Decode(&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -114,7 +126,7 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
||||||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||||
err := userCollection.FindOne(ctx, bson.M{"_id": id}).Decode(&user)
|
err := userCollection.FindOne(ctx, bson.M{"_id": id}).Decode(&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
||||||
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||||
_, err := verificationRequestCollection.InsertOne(ctx, verificationRequest)
|
_, err := verificationRequestCollection.InsertOne(ctx, verificationRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
||||||
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||||
err := verificationRequestCollection.FindOne(ctx, bson.M{"token": token}).Decode(&verificationRequest)
|
err := verificationRequestCollection.FindOne(ctx, bson.M{"token": token}).Decode(&verificationRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return verificationRequest, nil
|
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())
|
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||||
err := verificationRequestCollection.FindOne(ctx, bson.M{"email": email, "identifier": identifier}).Decode(&verificationRequest)
|
err := verificationRequestCollection.FindOne(ctx, bson.M{"email": email, "identifier": identifier}).Decode(&verificationRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return verificationRequest, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return verificationRequest, nil
|
return verificationRequest, nil
|
||||||
|
|
|
@ -2,12 +2,15 @@ package provider_template
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,10 +22,19 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
if user.Roles == "" {
|
if user.Roles == "" {
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
|
}
|
||||||
|
} 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.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
return user, nil
|
return user, nil
|
||||||
|
|
|
@ -7,33 +7,56 @@ import (
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"gorm.io/gorm/clause"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// UpsertOTP to add or update otp
|
// UpsertOTP to add or update otp
|
||||||
func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, error) {
|
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
if otp.ID == "" {
|
if otpParam.ID == "" {
|
||||||
otp.ID = uuid.New().String()
|
otpParam.ID = uuid.New().String()
|
||||||
}
|
}
|
||||||
// check if email or phone number is present
|
// check if email or phone number is present
|
||||||
if otp.Email == "" && otp.PhoneNumber == "" {
|
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||||
return nil, errors.New("email or phone_number is required")
|
return nil, errors.New("email or phone_number is required")
|
||||||
}
|
}
|
||||||
uniqueField := models.FieldNameEmail
|
uniqueField := models.FieldNameEmail
|
||||||
if otp.Email == "" && otp.PhoneNumber != "" {
|
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||||
uniqueField = models.FieldNamePhoneNumber
|
uniqueField = models.FieldNamePhoneNumber
|
||||||
}
|
}
|
||||||
otp.Key = otp.ID
|
var otp *models.OTP
|
||||||
otp.CreatedAt = time.Now().Unix()
|
if uniqueField == models.FieldNameEmail {
|
||||||
otp.UpdatedAt = time.Now().Unix()
|
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||||
res := p.db.Clauses(clause.OnConflict{
|
} else {
|
||||||
Columns: []clause.Column{{Name: uniqueField}},
|
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||||
DoUpdates: clause.AssignmentColumns([]string{"otp", "expires_at", "updated_at"}),
|
}
|
||||||
}).Create(&otp)
|
shouldCreate := false
|
||||||
if res.Error != nil {
|
if otp == nil {
|
||||||
return nil, res.Error
|
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.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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return otp, nil
|
return otp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/refs"
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/clause"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddUser to save user information in database
|
// AddUser to save user information in database
|
||||||
|
@ -25,25 +24,25 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||||
if user.Roles == "" {
|
if user.Roles == "" {
|
||||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
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")
|
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.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
user.Key = user.ID
|
user.Key = user.ID
|
||||||
result := p.db.Clauses(
|
result := p.db.Create(&user)
|
||||||
clause.OnConflict{
|
|
||||||
UpdateAll: true,
|
|
||||||
Columns: []clause.Column{{Name: "email"}},
|
|
||||||
}).Create(&user)
|
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return user, result.Error
|
return user, result.Error
|
||||||
|
@ -113,7 +112,7 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
||||||
var user *models.User
|
var user *models.User
|
||||||
result := p.db.Where("email = ?", email).First(&user)
|
result := p.db.Where("email = ?", email).First(&user)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return user, result.Error
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -123,7 +122,7 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
||||||
var user *models.User
|
var user *models.User
|
||||||
result := p.db.Where("id = ?", id).First(&user)
|
result := p.db.Where("id = ?", id).First(&user)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return user, result.Error
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,13 +53,13 @@ const (
|
||||||
<table width="100%%" cellspacing="0" cellpadding="0">
|
<table width="100%%" cellspacing="0" cellpadding="0">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<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="{{.org_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="{{.organization.logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
|
<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;">
|
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
|
||||||
<p>Hey there 👋</p>
|
<p>Hey there 👋</p>
|
||||||
<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/>
|
<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/>
|
||||||
<a
|
<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>
|
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>
|
</td>
|
||||||
|
|
32
server/env/env.go
vendored
32
server/env/env.go
vendored
|
@ -79,6 +79,10 @@ func InitAllEnv() error {
|
||||||
osMicrosoftClientID := os.Getenv(constants.EnvKeyMicrosoftClientID)
|
osMicrosoftClientID := os.Getenv(constants.EnvKeyMicrosoftClientID)
|
||||||
osMicrosoftClientSecret := os.Getenv(constants.EnvKeyMicrosoftClientSecret)
|
osMicrosoftClientSecret := os.Getenv(constants.EnvKeyMicrosoftClientSecret)
|
||||||
osMicrosoftActiveDirectoryTenantID := os.Getenv(constants.EnvKeyMicrosoftActiveDirectoryTenantID)
|
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)
|
osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL)
|
||||||
osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName)
|
osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName)
|
||||||
osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo)
|
osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo)
|
||||||
|
@ -501,6 +505,34 @@ func InitAllEnv() error {
|
||||||
envData[constants.EnvKeyMicrosoftActiveDirectoryTenantID] = osMicrosoftActiveDirectoryTenantID
|
envData[constants.EnvKeyMicrosoftActiveDirectoryTenantID] = osMicrosoftActiveDirectoryTenantID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyTwitchClientID]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyTwitchClientID] = osTwitchClientID
|
||||||
|
}
|
||||||
|
if osTwitchClientID != "" && envData[constants.EnvKeyTwitchClientID] != osTwitchClientID {
|
||||||
|
envData[constants.EnvKeyTwitchClientID] = osTwitchClientID
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyTwitchClientSecret]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyTwitchClientSecret] = osTwitchClientSecret
|
||||||
|
}
|
||||||
|
if osTwitchClientSecret != "" && envData[constants.EnvKeyTwitchClientSecret] != osTwitchClientSecret {
|
||||||
|
envData[constants.EnvKeyTwitchClientSecret] = osTwitchClientSecret
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyRobloxClientID]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyRobloxClientID] = osRobloxClientID
|
||||||
|
}
|
||||||
|
if osRobloxClientID != "" && envData[constants.EnvKeyRobloxClientID] != osRobloxClientID {
|
||||||
|
envData[constants.EnvKeyRobloxClientID] = osRobloxClientID
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyRobloxClientSecret]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyRobloxClientSecret] = osRobloxClientSecret
|
||||||
|
}
|
||||||
|
if osRobloxClientSecret != "" && envData[constants.EnvKeyRobloxClientSecret] != osRobloxClientSecret {
|
||||||
|
envData[constants.EnvKeyRobloxClientSecret] = osRobloxClientSecret
|
||||||
|
}
|
||||||
|
|
||||||
if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" {
|
if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" {
|
||||||
envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/")
|
envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/")
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ go 1.21
|
||||||
toolchain go1.21.4
|
toolchain go1.21.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/99designs/gqlgen v0.17.39
|
github.com/99designs/gqlgen v0.17.45
|
||||||
github.com/arangodb/go-driver v1.6.0
|
github.com/arangodb/go-driver v1.6.0
|
||||||
github.com/aws/aws-sdk-go v1.47.4
|
github.com/aws/aws-sdk-go v1.47.4
|
||||||
github.com/coreos/go-oidc/v3 v3.6.0
|
github.com/coreos/go-oidc/v3 v3.6.0
|
||||||
|
@ -16,7 +16,7 @@ require (
|
||||||
github.com/gocql/gocql v1.6.0
|
github.com/gocql/gocql v1.6.0
|
||||||
github.com/gokyle/twofactor v1.0.1
|
github.com/gokyle/twofactor v1.0.1
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/google/uuid v1.3.1
|
github.com/google/uuid v1.6.0
|
||||||
github.com/guregu/dynamo v1.20.2
|
github.com/guregu/dynamo v1.20.2
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/mailgun/mailgun-go/v4 v4.12.0
|
github.com/mailgun/mailgun-go/v4 v4.12.0
|
||||||
|
@ -24,12 +24,12 @@ require (
|
||||||
github.com/redis/go-redis/v9 v9.2.1
|
github.com/redis/go-redis/v9 v9.2.1
|
||||||
github.com/robertkrimen/otto v0.2.1
|
github.com/robertkrimen/otto v0.2.1
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d
|
github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d
|
||||||
github.com/twilio/twilio-go v1.14.1
|
github.com/twilio/twilio-go v1.14.1
|
||||||
github.com/vektah/gqlparser/v2 v2.5.10
|
github.com/vektah/gqlparser/v2 v2.5.11
|
||||||
go.mongodb.org/mongo-driver v1.12.1
|
go.mongodb.org/mongo-driver v1.12.1
|
||||||
golang.org/x/crypto v0.14.0
|
golang.org/x/crypto v0.21.0
|
||||||
golang.org/x/oauth2 v0.13.0
|
golang.org/x/oauth2 v0.13.0
|
||||||
google.golang.org/appengine v1.6.8
|
google.golang.org/appengine v1.6.8
|
||||||
gopkg.in/mail.v2 v2.3.1
|
gopkg.in/mail.v2 v2.3.1
|
||||||
|
@ -71,7 +71,7 @@ require (
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.3 // indirect
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
||||||
|
@ -85,7 +85,7 @@ require (
|
||||||
github.com/libsql/libsql-client-go v0.0.0-20231026052543-fce76c0f39a7 // 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/libsql/sqlite-antlr4-parser v0.0.0-20230802215326-5cb5bb604475 // indirect
|
||||||
github.com/maruel/rs v1.1.0 // indirect
|
github.com/maruel/rs v1.1.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/microsoft/go-mssqldb v1.6.0 // indirect
|
github.com/microsoft/go-mssqldb v1.6.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.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/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
@ -97,10 +97,10 @@ require (
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/sosodev/duration v1.1.0 // indirect
|
github.com/sosodev/duration v1.2.0 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
github.com/urfave/cli/v2 v2.25.5 // indirect
|
github.com/urfave/cli/v2 v2.27.1 // indirect
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
github.com/xdg-go/scram v1.1.2 // indirect
|
github.com/xdg-go/scram v1.1.2 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
|
@ -108,13 +108,13 @@ require (
|
||||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||||
golang.org/x/mod v0.10.0 // indirect
|
golang.org/x/mod v0.16.0 // indirect
|
||||||
golang.org/x/net v0.17.0 // indirect
|
golang.org/x/net v0.22.0 // indirect
|
||||||
golang.org/x/sync v0.3.0 // indirect
|
golang.org/x/sync v0.6.0 // indirect
|
||||||
golang.org/x/sys v0.13.0 // indirect
|
golang.org/x/sys v0.18.0 // indirect
|
||||||
golang.org/x/text v0.13.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
golang.org/x/tools v0.9.3 // indirect
|
golang.org/x/tools v0.19.0 // indirect
|
||||||
google.golang.org/protobuf v1.31.0 // indirect
|
google.golang.org/protobuf v1.33.0 // indirect
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
github.com/99designs/gqlgen v0.17.39 h1:wPTAyc2fqVjAWT5DsJ21k/lLudgnXzURwbsjVNegFpU=
|
github.com/99designs/gqlgen v0.17.45 h1:bH0AH67vIJo8JKNKPJP+pOPpQhZeuVRQLf53dKIpDik=
|
||||||
github.com/99designs/gqlgen v0.17.39/go.mod h1:b62q1USk82GYIVjC60h02YguAZLqYZtvWml8KkhJps4=
|
github.com/99designs/gqlgen v0.17.45/go.mod h1:Bas0XQ+Jiu/Xm5E33jC8sES3G+iC2esHBMXcq0fUPs0=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||||
|
@ -18,10 +18,14 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o=
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o=
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os=
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os=
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||||
|
github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI=
|
||||||
|
github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY=
|
||||||
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
|
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
|
||||||
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
|
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
|
||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||||
|
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
||||||
|
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk=
|
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
|
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
|
||||||
github.com/arangodb/go-driver v1.6.0 h1:NFWj/idqXZxhFVueihMSI2R9NotNIsgvNfM/xmpekb4=
|
github.com/arangodb/go-driver v1.6.0 h1:NFWj/idqXZxhFVueihMSI2R9NotNIsgvNfM/xmpekb4=
|
||||||
|
@ -160,8 +164,9 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
|
||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
|
||||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
@ -173,8 +178,8 @@ github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.3 h1:kmRrRLlInXvng0SmLxmQpQkpbYAvcXm7NPDrgxJa9mE=
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.3/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
@ -231,8 +236,8 @@ github.com/mailgun/mailgun-go/v4 v4.12.0/go.mod h1:L9s941Lgk7iB3TgywTPz074pK2Ekk
|
||||||
github.com/maruel/rs v1.1.0 h1:dh4OceAF5yD06EASOrb+DS358LI4g0B90YApSdjCP6U=
|
github.com/maruel/rs v1.1.0 h1:dh4OceAF5yD06EASOrb+DS358LI4g0B90YApSdjCP6U=
|
||||||
github.com/maruel/rs v1.1.0/go.mod h1:vzwMjzSJJxLIXmU62qHj6O5QRn5kvCKxFrfaFCxBcUY=
|
github.com/maruel/rs v1.1.0/go.mod h1:vzwMjzSJJxLIXmU62qHj6O5QRn5kvCKxFrfaFCxBcUY=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
||||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc=
|
github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc=
|
||||||
|
@ -276,12 +281,13 @@ github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/sosodev/duration v1.1.0 h1:kQcaiGbJaIsRqgQy7VGlZrVw1giWO+lDoX3MCPnpVO4=
|
github.com/sosodev/duration v1.2.0 h1:pqK/FLSjsAADWY74SyWDCjOcd5l7H8GSnnOGEB9A1Us=
|
||||||
github.com/sosodev/duration v1.1.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
|
github.com/sosodev/duration v1.2.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
@ -292,8 +298,9 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d h1:4x1FeGJRB00cvxnKXnRJDT89fvG/Lzm2ecm0vlr/qDs=
|
github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d h1:4x1FeGJRB00cvxnKXnRJDT89fvG/Lzm2ecm0vlr/qDs=
|
||||||
github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d/go.mod h1:uSELzeIcTceNCgzbKdJuJa0ouCqqtkyzL+6bnA3rM+M=
|
github.com/tuotoo/qrcode v0.0.0-20220425170535-52ccc2bebf5d/go.mod h1:uSELzeIcTceNCgzbKdJuJa0ouCqqtkyzL+6bnA3rM+M=
|
||||||
github.com/twilio/twilio-go v1.14.1 h1:uyMwNe2naFKwxLpVflAHbKEPiW9iHNI8VF6NWLJJ1Kk=
|
github.com/twilio/twilio-go v1.14.1 h1:uyMwNe2naFKwxLpVflAHbKEPiW9iHNI8VF6NWLJJ1Kk=
|
||||||
|
@ -304,10 +311,10 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/urfave/cli/v2 v2.25.5 h1:d0NIAyhh5shGscroL7ek/Ya9QYQE0KNabJgiUinIQkc=
|
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
|
||||||
github.com/urfave/cli/v2 v2.25.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||||
github.com/vektah/gqlparser/v2 v2.5.10 h1:6zSM4azXC9u4Nxy5YmdmGu4uKamfwsdKTwp5zsEealU=
|
github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8=
|
||||||
github.com/vektah/gqlparser/v2 v2.5.10/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc=
|
github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc=
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||||
|
@ -335,15 +342,15 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
@ -358,16 +365,17 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
|
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
|
||||||
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
|
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
|
||||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -387,8 +395,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
@ -407,16 +415,16 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
|
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||||
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -425,8 +433,8 @@ google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAs
|
||||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -93,6 +93,7 @@ type Env struct {
|
||||||
ResetPasswordURL *string `json:"RESET_PASSWORD_URL,omitempty"`
|
ResetPasswordURL *string `json:"RESET_PASSWORD_URL,omitempty"`
|
||||||
DisableEmailVerification bool `json:"DISABLE_EMAIL_VERIFICATION"`
|
DisableEmailVerification bool `json:"DISABLE_EMAIL_VERIFICATION"`
|
||||||
DisableBasicAuthentication bool `json:"DISABLE_BASIC_AUTHENTICATION"`
|
DisableBasicAuthentication bool `json:"DISABLE_BASIC_AUTHENTICATION"`
|
||||||
|
DisableMobileBasicAuthentication bool `json:"DISABLE_MOBILE_BASIC_AUTHENTICATION"`
|
||||||
DisableMagicLinkLogin bool `json:"DISABLE_MAGIC_LINK_LOGIN"`
|
DisableMagicLinkLogin bool `json:"DISABLE_MAGIC_LINK_LOGIN"`
|
||||||
DisableLoginPage bool `json:"DISABLE_LOGIN_PAGE"`
|
DisableLoginPage bool `json:"DISABLE_LOGIN_PAGE"`
|
||||||
DisableSignUp bool `json:"DISABLE_SIGN_UP"`
|
DisableSignUp bool `json:"DISABLE_SIGN_UP"`
|
||||||
|
@ -123,6 +124,8 @@ type Env struct {
|
||||||
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID,omitempty"`
|
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID,omitempty"`
|
||||||
TwitchClientID *string `json:"TWITCH_CLIENT_ID,omitempty"`
|
TwitchClientID *string `json:"TWITCH_CLIENT_ID,omitempty"`
|
||||||
TwitchClientSecret *string `json:"TWITCH_CLIENT_SECRET,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"`
|
OrganizationName *string `json:"ORGANIZATION_NAME,omitempty"`
|
||||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO,omitempty"`
|
OrganizationLogo *string `json:"ORGANIZATION_LOGO,omitempty"`
|
||||||
AppCookieSecure bool `json:"APP_COOKIE_SECURE"`
|
AppCookieSecure bool `json:"APP_COOKIE_SECURE"`
|
||||||
|
@ -210,6 +213,7 @@ type Meta struct {
|
||||||
IsTwitterLoginEnabled bool `json:"is_twitter_login_enabled"`
|
IsTwitterLoginEnabled bool `json:"is_twitter_login_enabled"`
|
||||||
IsMicrosoftLoginEnabled bool `json:"is_microsoft_login_enabled"`
|
IsMicrosoftLoginEnabled bool `json:"is_microsoft_login_enabled"`
|
||||||
IsTwitchLoginEnabled bool `json:"is_twitch_login_enabled"`
|
IsTwitchLoginEnabled bool `json:"is_twitch_login_enabled"`
|
||||||
|
IsRobloxLoginEnabled bool `json:"is_roblox_login_enabled"`
|
||||||
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
||||||
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
||||||
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
||||||
|
@ -248,6 +252,9 @@ type MobileSignUpInput struct {
|
||||||
AppData map[string]interface{} `json:"app_data,omitempty"`
|
AppData map[string]interface{} `json:"app_data,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Mutation struct {
|
||||||
|
}
|
||||||
|
|
||||||
type OAuthRevokeInput struct {
|
type OAuthRevokeInput struct {
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
}
|
}
|
||||||
|
@ -268,6 +275,9 @@ type PaginationInput struct {
|
||||||
Page *int64 `json:"page,omitempty"`
|
Page *int64 `json:"page,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Query struct {
|
||||||
|
}
|
||||||
|
|
||||||
type ResendOTPRequest struct {
|
type ResendOTPRequest struct {
|
||||||
Email *string `json:"email,omitempty"`
|
Email *string `json:"email,omitempty"`
|
||||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||||
|
@ -373,6 +383,7 @@ type UpdateEnvInput struct {
|
||||||
AdminCookieSecure *bool `json:"ADMIN_COOKIE_SECURE,omitempty"`
|
AdminCookieSecure *bool `json:"ADMIN_COOKIE_SECURE,omitempty"`
|
||||||
DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION,omitempty"`
|
DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION,omitempty"`
|
||||||
DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION,omitempty"`
|
DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION,omitempty"`
|
||||||
|
DisableMobileBasicAuthentication *bool `json:"DISABLE_MOBILE_BASIC_AUTHENTICATION,omitempty"`
|
||||||
DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN,omitempty"`
|
DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN,omitempty"`
|
||||||
DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE,omitempty"`
|
DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE,omitempty"`
|
||||||
DisableSignUp *bool `json:"DISABLE_SIGN_UP,omitempty"`
|
DisableSignUp *bool `json:"DISABLE_SIGN_UP,omitempty"`
|
||||||
|
@ -403,6 +414,8 @@ type UpdateEnvInput struct {
|
||||||
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID,omitempty"`
|
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID,omitempty"`
|
||||||
TwitchClientID *string `json:"TWITCH_CLIENT_ID,omitempty"`
|
TwitchClientID *string `json:"TWITCH_CLIENT_ID,omitempty"`
|
||||||
TwitchClientSecret *string `json:"TWITCH_CLIENT_SECRET,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"`
|
OrganizationName *string `json:"ORGANIZATION_NAME,omitempty"`
|
||||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO,omitempty"`
|
OrganizationLogo *string `json:"ORGANIZATION_LOGO,omitempty"`
|
||||||
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE,omitempty"`
|
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE,omitempty"`
|
||||||
|
@ -440,6 +453,7 @@ type UpdateUserInput struct {
|
||||||
Gender *string `json:"gender,omitempty"`
|
Gender *string `json:"gender,omitempty"`
|
||||||
Birthdate *string `json:"birthdate,omitempty"`
|
Birthdate *string `json:"birthdate,omitempty"`
|
||||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||||
|
PhoneNumberVerified *bool `json:"phone_number_verified,omitempty"`
|
||||||
Picture *string `json:"picture,omitempty"`
|
Picture *string `json:"picture,omitempty"`
|
||||||
Roles []*string `json:"roles,omitempty"`
|
Roles []*string `json:"roles,omitempty"`
|
||||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"`
|
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"`
|
||||||
|
|
|
@ -24,6 +24,7 @@ type Meta {
|
||||||
is_twitter_login_enabled: Boolean!
|
is_twitter_login_enabled: Boolean!
|
||||||
is_microsoft_login_enabled: Boolean!
|
is_microsoft_login_enabled: Boolean!
|
||||||
is_twitch_login_enabled: Boolean!
|
is_twitch_login_enabled: Boolean!
|
||||||
|
is_roblox_login_enabled: Boolean!
|
||||||
is_email_verification_enabled: Boolean!
|
is_email_verification_enabled: Boolean!
|
||||||
is_basic_authentication_enabled: Boolean!
|
is_basic_authentication_enabled: Boolean!
|
||||||
is_magic_link_login_enabled: Boolean!
|
is_magic_link_login_enabled: Boolean!
|
||||||
|
@ -158,6 +159,7 @@ type Env {
|
||||||
RESET_PASSWORD_URL: String
|
RESET_PASSWORD_URL: String
|
||||||
DISABLE_EMAIL_VERIFICATION: Boolean!
|
DISABLE_EMAIL_VERIFICATION: Boolean!
|
||||||
DISABLE_BASIC_AUTHENTICATION: Boolean!
|
DISABLE_BASIC_AUTHENTICATION: Boolean!
|
||||||
|
DISABLE_MOBILE_BASIC_AUTHENTICATION: Boolean!
|
||||||
DISABLE_MAGIC_LINK_LOGIN: Boolean!
|
DISABLE_MAGIC_LINK_LOGIN: Boolean!
|
||||||
DISABLE_LOGIN_PAGE: Boolean!
|
DISABLE_LOGIN_PAGE: Boolean!
|
||||||
DISABLE_SIGN_UP: Boolean!
|
DISABLE_SIGN_UP: Boolean!
|
||||||
|
@ -188,6 +190,8 @@ type Env {
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
||||||
TWITCH_CLIENT_ID: String
|
TWITCH_CLIENT_ID: String
|
||||||
TWITCH_CLIENT_SECRET: String
|
TWITCH_CLIENT_SECRET: String
|
||||||
|
ROBLOX_CLIENT_ID: String
|
||||||
|
ROBLOX_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
APP_COOKIE_SECURE: Boolean!
|
APP_COOKIE_SECURE: Boolean!
|
||||||
|
@ -289,6 +293,7 @@ input UpdateEnvInput {
|
||||||
ADMIN_COOKIE_SECURE: Boolean
|
ADMIN_COOKIE_SECURE: Boolean
|
||||||
DISABLE_EMAIL_VERIFICATION: Boolean
|
DISABLE_EMAIL_VERIFICATION: Boolean
|
||||||
DISABLE_BASIC_AUTHENTICATION: Boolean
|
DISABLE_BASIC_AUTHENTICATION: Boolean
|
||||||
|
DISABLE_MOBILE_BASIC_AUTHENTICATION: Boolean
|
||||||
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
||||||
DISABLE_LOGIN_PAGE: Boolean
|
DISABLE_LOGIN_PAGE: Boolean
|
||||||
DISABLE_SIGN_UP: Boolean
|
DISABLE_SIGN_UP: Boolean
|
||||||
|
@ -319,6 +324,8 @@ input UpdateEnvInput {
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
||||||
TWITCH_CLIENT_ID: String
|
TWITCH_CLIENT_ID: String
|
||||||
TWITCH_CLIENT_SECRET: String
|
TWITCH_CLIENT_SECRET: String
|
||||||
|
ROBLOX_CLIENT_ID: String
|
||||||
|
ROBLOX_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
||||||
|
@ -452,6 +459,7 @@ input UpdateUserInput {
|
||||||
gender: String
|
gender: String
|
||||||
birthdate: String
|
birthdate: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
|
phone_number_verified: Boolean
|
||||||
picture: String
|
picture: String
|
||||||
roles: [String]
|
roles: [String]
|
||||||
is_multi_factor_auth_enabled: Boolean
|
is_multi_factor_auth_enabled: Boolean
|
||||||
|
|
|
@ -2,7 +2,7 @@ package graph
|
||||||
|
|
||||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
// 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.
|
// 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.39
|
// Code generated by github.com/99designs/gqlgen version v0.17.45
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
|
@ -89,6 +89,8 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
user, err = processMicrosoftUserInfo(ctx, oauthCode)
|
user, err = processMicrosoftUserInfo(ctx, oauthCode)
|
||||||
case constants.AuthRecipeMethodTwitch:
|
case constants.AuthRecipeMethodTwitch:
|
||||||
user, err = processTwitchUserInfo(ctx, oauthCode)
|
user, err = processTwitchUserInfo(ctx, oauthCode)
|
||||||
|
case constants.AuthRecipeMethodRoblox:
|
||||||
|
user, err = processRobloxUserInfo(ctx, oauthCode, sessionState)
|
||||||
default:
|
default:
|
||||||
log.Info("Invalid oauth provider")
|
log.Info("Invalid oauth provider")
|
||||||
err = fmt.Errorf(`invalid oauth provider`)
|
err = fmt.Errorf(`invalid oauth provider`)
|
||||||
|
@ -617,7 +619,7 @@ func processAppleUserInfo(ctx context.Context, code string) (*models.User, error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func processDiscordUserInfo(ctx context.Context, code string) (*models.User, error) {
|
func processDiscordUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||||
|
@ -818,3 +820,68 @@ func processTwitchUserInfo(ctx context.Context, code string) (*models.User, erro
|
||||||
|
|
||||||
return user, nil
|
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, nil
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
@ -40,11 +40,8 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
if state == "" {
|
if state == "" {
|
||||||
log.Debug("state is empty")
|
log.Debug("state is empty. creating a new state")
|
||||||
c.JSON(400, gin.H{
|
state = uuid.New().String()
|
||||||
"error": "invalid state",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var scope []string
|
var scope []string
|
||||||
|
@ -265,6 +262,24 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
||||||
oauth.OAuthProviders.TwitchConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodTwitch
|
oauth.OAuthProviders.TwitchConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodTwitch
|
||||||
url := oauth.OAuthProviders.TwitchConfig.AuthCodeURL(oauthStateString)
|
url := oauth.OAuthProviders.TwitchConfig.AuthCodeURL(oauthStateString)
|
||||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
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:
|
default:
|
||||||
log.Debug("Invalid oauth provider: ", provider)
|
log.Debug("Invalid oauth provider: ", provider)
|
||||||
c.JSON(422, gin.H{
|
c.JSON(422, gin.H{
|
||||||
|
|
|
@ -24,9 +24,13 @@ func RevokeRefreshTokenHandler() gin.HandlerFunc {
|
||||||
})
|
})
|
||||||
return
|
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
|
// get fingerprint hash
|
||||||
refreshToken := strings.TrimSpace(reqBody["refresh_token"])
|
refreshToken := strings.TrimSpace(reqBody["refresh_token"])
|
||||||
clientID := strings.TrimSpace(reqBody["client_id"])
|
|
||||||
|
|
||||||
if clientID == "" {
|
if clientID == "" {
|
||||||
log.Debug("Client ID is empty")
|
log.Debug("Client ID is empty")
|
||||||
|
|
|
@ -2,17 +2,44 @@ package logs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LogTextFormatter is a custom log formatter for text output
|
|
||||||
type LogTextFormatter struct {
|
type LogTextFormatter struct {
|
||||||
logrus.Formatter
|
logrus.Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format helps fomratting time to UTC
|
|
||||||
func (u LogTextFormatter) Format(e *logrus.Entry) ([]byte, error) {
|
func (u LogTextFormatter) Format(e *logrus.Entry) ([]byte, error) {
|
||||||
return []byte(fmt.Sprintf("[%s] %s", strings.ToUpper(e.Level.String()), e.Message)), nil
|
level := strings.ToUpper(e.Level.String())
|
||||||
|
message := e.Message
|
||||||
|
parts := strings.SplitN(message, " +0000]", 2)
|
||||||
|
if len(parts) >= 2 {
|
||||||
|
message = parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
var color string
|
||||||
|
switch e.Level {
|
||||||
|
case logrus.DebugLevel:
|
||||||
|
color = "\033[36m" // cyan
|
||||||
|
case logrus.InfoLevel:
|
||||||
|
color = "\033[37m" // grey
|
||||||
|
case logrus.WarnLevel:
|
||||||
|
color = "\033[33m" // yellow
|
||||||
|
case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
|
||||||
|
color = "\033[31m" // red
|
||||||
|
default:
|
||||||
|
color = "\033[0m" // reset
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Caller != nil {
|
||||||
|
fmt.Sprintf("%r", e)
|
||||||
|
file := filepath.Base(e.Caller.File)
|
||||||
|
line := e.Caller.Line
|
||||||
|
return []byte(fmt.Sprintf("%s[%s] %s:%d %s%s\033[0m\n", color, level, file, line, message, color)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(fmt.Sprintf("%s[%s] %s%s\033[0m\n", color, level, message, color)), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
log := logs.InitLog(refs.StringValue(cli.ARG_LOG_LEVEL))
|
log := logs.InitLog(refs.StringValue(cli.ARG_LOG_LEVEL))
|
||||||
|
log.SetFormatter(&logs.LogTextFormatter{})
|
||||||
|
|
||||||
// initialize memory store
|
// initialize memory store
|
||||||
err = memorystore.InitMemStore()
|
err = memorystore.InitMemStore()
|
||||||
|
|
|
@ -4,9 +4,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -219,15 +222,106 @@ func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) {
|
||||||
return data == "1", nil
|
return data == "1", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AuthorProfile struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
// Add other fields as necessary
|
||||||
|
}
|
||||||
|
|
||||||
// GetUserAppDataFromRedis retrieves user profile and follows from Redis, combines them into a JSON format,
|
// GetUserAppDataFromRedis retrieves user profile and follows from Redis, combines them into a JSON format,
|
||||||
// and assigns the JSON string to the provided user's ID.
|
// and assigns the JSON string to the provided user's ID.
|
||||||
func (c *provider) GetUserAppDataFromRedis(userId string) (string, error) {
|
func (c *provider) GetUserAppDataFromRedis(userId string) (string, error) {
|
||||||
// Retrieve user data from Redis
|
// Получаем ID автора из Redis
|
||||||
userProfile := c.store.Get(c.ctx, fmt.Sprintf(`user:%s:author`, userId))
|
rkey := fmt.Sprintf("author:user:%s", userId)
|
||||||
userFollows := c.store.Get(c.ctx, fmt.Sprintf(`user:%s:follows`, userId))
|
fmt.Println("get redis cached by key:", rkey)
|
||||||
|
authorIdString, err := c.store.Get(c.ctx, rkey).Result()
|
||||||
|
fmt.Println("redis found string value:", authorIdString)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
// Combine user data into a JSON string
|
// Преобразуем ID автора из строки в int
|
||||||
combinedData := fmt.Sprintf(`{"profile": %s, "follows": %s}`, userProfile, userFollows)
|
var authorIdFloat float64
|
||||||
|
err = json.Unmarshal([]byte(authorIdString), &authorIdFloat)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
authorId := int(authorIdFloat)
|
||||||
|
fmt.Println("recognized author id: ", authorId)
|
||||||
|
|
||||||
return combinedData, nil
|
// Получаем профиль автора из Redis
|
||||||
|
authorProfileString, err := c.store.Get(c.ctx, fmt.Sprintf("author:id:%d", authorId)).Result()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Парсим профиль пользователя в map
|
||||||
|
var authorProfileMap map[string]interface{}
|
||||||
|
err = json.Unmarshal([]byte(authorProfileString), &authorProfileMap)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Начинаем сбор данных в общий JSON
|
||||||
|
combinedData := map[string]interface{}{
|
||||||
|
"profile": authorProfileMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем подписки автора на других авторов
|
||||||
|
if authorsObjectsString, err := c.getFollowedObjectsString(fmt.Sprintf("author:follows-authors:%d", authorId), "author:id:%d"); err == nil {
|
||||||
|
combinedData["authors"] = authorsObjectsString
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем подписки автора на темы
|
||||||
|
if topicsObjectString, err := c.getFollowedObjectsString(fmt.Sprintf("author:follows-topics:%d", authorId), "topic:id:%d"); err == nil {
|
||||||
|
combinedData["topics"] = topicsObjectString
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем подписчиков автора
|
||||||
|
if authorFollowersObjectsString, err := c.getFollowedObjectsString(fmt.Sprintf("author:followers:%d", authorId), "author:id:%d"); err == nil {
|
||||||
|
combinedData["followers"] = authorFollowersObjectsString
|
||||||
|
}
|
||||||
|
|
||||||
|
// Преобразуем собранные данные в JSON строку
|
||||||
|
combinedDataString, err := json.Marshal(combinedData)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(combinedDataString), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Универсальная функция для получения объектов по списку ID из Redis
|
||||||
|
func (c *provider) getFollowedObjectsString(followKey string, objectKeyPattern string) ([]map[string]interface{}, error) {
|
||||||
|
followsString, err := c.store.Get(c.ctx, followKey).Result()
|
||||||
|
if err != nil {
|
||||||
|
if err == redis.Nil {
|
||||||
|
return []map[string]interface{}{}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ids []int
|
||||||
|
err = json.Unmarshal([]byte(followsString), &ids)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
objects := make([]map[string]interface{}, 0, len(ids))
|
||||||
|
for _, id := range ids {
|
||||||
|
objectString, err := c.store.Get(c.ctx, fmt.Sprintf(objectKeyPattern, id)).Result()
|
||||||
|
if err == redis.Nil {
|
||||||
|
continue
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var object map[string]interface{}
|
||||||
|
err = json.Unmarshal([]byte(objectString), &object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
objects = append(objects, object)
|
||||||
|
}
|
||||||
|
|
||||||
|
return objects, nil
|
||||||
}
|
}
|
||||||
|
|
29
server/middlewares/client_check.go
Normal file
29
server/middlewares/client_check.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package middlewares
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientCheckMiddleware is a middleware to verify the client ID
|
||||||
|
// Note: client ID is passed in the header
|
||||||
|
func ClientCheckMiddleware() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
clientID := c.Request.Header.Get("X-Authorizer-Client-ID")
|
||||||
|
if client, _ := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); clientID != "" && client != "" && client != clientID {
|
||||||
|
log.Debug("Client ID is invalid: ", clientID)
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"error": "invalid_client_id",
|
||||||
|
"error_description": "The client id is invalid",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ func CORSMiddleware() gin.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, X-authorizer-url")
|
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, X-authorizer-url, X-Forwarded-Proto, X-authorizer-client-id")
|
||||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
|
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
|
||||||
|
|
||||||
if c.Request.Method == "OPTIONS" {
|
if c.Request.Method == "OPTIONS" {
|
||||||
|
|
|
@ -34,6 +34,7 @@ type OAuthProvider struct {
|
||||||
TwitterConfig *oauth2.Config
|
TwitterConfig *oauth2.Config
|
||||||
MicrosoftConfig *oauth2.Config
|
MicrosoftConfig *oauth2.Config
|
||||||
TwitchConfig *oauth2.Config
|
TwitchConfig *oauth2.Config
|
||||||
|
RobloxConfig *oauth2.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// OIDCProviders is a struct that contains reference all the OpenID providers
|
// OIDCProviders is a struct that contains reference all the OpenID providers
|
||||||
|
@ -251,5 +252,25 @@ func InitOAuth() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
robloxClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRobloxClientID)
|
||||||
|
if err != nil {
|
||||||
|
robloxClientID = ""
|
||||||
|
}
|
||||||
|
robloxClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRobloxClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
robloxClientSecret = ""
|
||||||
|
}
|
||||||
|
if robloxClientID != "" && robloxClientSecret != "" {
|
||||||
|
OAuthProviders.RobloxConfig = &oauth2.Config{
|
||||||
|
ClientID: robloxClientID,
|
||||||
|
ClientSecret: robloxClientSecret,
|
||||||
|
RedirectURL: "/oauth_callback/roblox",
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: "https://apis.roblox.com/oauth/v1/authorize",
|
||||||
|
TokenURL: "https://apis.roblox.com/oauth/v1/token",
|
||||||
|
},
|
||||||
|
Scopes: []string{oidc.ScopeOpenID, "profile"},
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ func DeleteUserResolver(ctx context.Context, params model.DeleteUserInput) (*mod
|
||||||
// delete otp for given email
|
// delete otp for given email
|
||||||
otp, err := db.Provider.GetOTPByEmail(ctx, refs.StringValue(user.Email))
|
otp, err := db.Provider.GetOTPByEmail(ctx, refs.StringValue(user.Email))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Infof("No OTP found for email (%s): %v", user.Email, err)
|
log.Info("No OTP found for email (%s): %v", user.Email, err)
|
||||||
// continue
|
// continue
|
||||||
} else {
|
} else {
|
||||||
err := db.Provider.DeleteOTP(ctx, otp)
|
err := db.Provider.DeleteOTP(ctx, otp)
|
||||||
|
|
|
@ -176,6 +176,12 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
|
||||||
if val, ok := store[constants.EnvKeyTwitchClientSecret]; ok {
|
if val, ok := store[constants.EnvKeyTwitchClientSecret]; ok {
|
||||||
res.TwitchClientSecret = refs.NewStringRef(val.(string))
|
res.TwitchClientSecret = refs.NewStringRef(val.(string))
|
||||||
}
|
}
|
||||||
|
if val, ok := store[constants.EnvKeyRobloxClientID]; ok {
|
||||||
|
res.RobloxClientID = refs.NewStringRef(val.(string))
|
||||||
|
}
|
||||||
|
if val, ok := store[constants.EnvKeyRobloxClientSecret]; ok {
|
||||||
|
res.RobloxClientSecret = refs.NewStringRef(val.(string))
|
||||||
|
}
|
||||||
if val, ok := store[constants.EnvKeyOrganizationName]; ok {
|
if val, ok := store[constants.EnvKeyOrganizationName]; ok {
|
||||||
res.OrganizationName = refs.NewStringRef(val.(string))
|
res.OrganizationName = refs.NewStringRef(val.(string))
|
||||||
}
|
}
|
||||||
|
@ -205,6 +211,7 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
|
||||||
// bool vars
|
// bool vars
|
||||||
res.DisableEmailVerification = store[constants.EnvKeyDisableEmailVerification].(bool)
|
res.DisableEmailVerification = store[constants.EnvKeyDisableEmailVerification].(bool)
|
||||||
res.DisableBasicAuthentication = store[constants.EnvKeyDisableBasicAuthentication].(bool)
|
res.DisableBasicAuthentication = store[constants.EnvKeyDisableBasicAuthentication].(bool)
|
||||||
|
res.DisableMobileBasicAuthentication = store[constants.EnvKeyDisableMobileBasicAuthentication].(bool)
|
||||||
res.DisableMagicLinkLogin = store[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
res.DisableMagicLinkLogin = store[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
||||||
res.DisableLoginPage = store[constants.EnvKeyDisableLoginPage].(bool)
|
res.DisableLoginPage = store[constants.EnvKeyDisableLoginPage].(bool)
|
||||||
res.DisableSignUp = store[constants.EnvKeyDisableSignUp].(bool)
|
res.DisableSignUp = store[constants.EnvKeyDisableSignUp].(bool)
|
||||||
|
|
|
@ -83,6 +83,39 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
log.Debug("User access is revoked")
|
log.Debug("User access is revoked")
|
||||||
return res, fmt.Errorf(`user access has been revoked`)
|
return res, fmt.Errorf(`user access has been revoked`)
|
||||||
}
|
}
|
||||||
|
isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||||
|
if err != nil || !isEmailServiceEnabled {
|
||||||
|
log.Debug("Email service not enabled: ", err)
|
||||||
|
}
|
||||||
|
isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled)
|
||||||
|
if err != nil || !isSMSServiceEnabled {
|
||||||
|
log.Debug("SMS service not enabled: ", err)
|
||||||
|
}
|
||||||
|
// If multi factor authentication is enabled and we need to generate OTP for mail / sms based MFA
|
||||||
|
generateOTP := func(expiresAt int64) (*models.OTP, error) {
|
||||||
|
otp := utils.GenerateOTP()
|
||||||
|
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||||
|
Email: refs.StringValue(user.Email),
|
||||||
|
PhoneNumber: refs.StringValue(user.PhoneNumber),
|
||||||
|
Otp: otp,
|
||||||
|
ExpiresAt: expiresAt,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add otp: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return otpData, nil
|
||||||
|
}
|
||||||
|
setOTPMFaSession := func(expiresAt int64) error {
|
||||||
|
mfaSession := uuid.NewString()
|
||||||
|
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add mfasession: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cookie.SetMfaSession(gc, mfaSession)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if isEmailLogin {
|
if isEmailLogin {
|
||||||
if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodBasicAuth) {
|
if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodBasicAuth) {
|
||||||
log.Debug("User signup method is not basic auth")
|
log.Debug("User signup method is not basic auth")
|
||||||
|
@ -90,8 +123,38 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.EmailVerifiedAt == nil {
|
if user.EmailVerifiedAt == nil {
|
||||||
log.Debug("User email is not verified")
|
// Check if email service is enabled
|
||||||
return res, fmt.Errorf(`email not verified`)
|
// Send email verification via otp
|
||||||
|
if !isEmailServiceEnabled {
|
||||||
|
log.Debug("User email is not verified and email service is not enabled")
|
||||||
|
return res, fmt.Errorf(`email not verified`)
|
||||||
|
} else {
|
||||||
|
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||||
|
otpData, err := generateOTP(expiresAt)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to generate otp: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||||
|
log.Debug("Failed to set mfa session: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
// exec it as go routine so that we can reduce the api latency
|
||||||
|
if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"otp": otpData.Otp,
|
||||||
|
}); err != nil {
|
||||||
|
log.Debug("Failed to send otp email: ", err)
|
||||||
|
}
|
||||||
|
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
|
||||||
|
}()
|
||||||
|
return &model.AuthResponse{
|
||||||
|
Message: "Please check email inbox for the OTP",
|
||||||
|
ShouldShowEmailOtpScreen: refs.NewBoolRef(isMobileLogin),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth) {
|
if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth) {
|
||||||
|
@ -100,8 +163,34 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.PhoneNumberVerifiedAt == nil {
|
if user.PhoneNumberVerifiedAt == nil {
|
||||||
log.Debug("User phone number is not verified")
|
if !isSMSServiceEnabled {
|
||||||
return res, fmt.Errorf(`phone number is not verified`)
|
log.Debug("User phone number is not verified")
|
||||||
|
return res, fmt.Errorf(`phone number is not verified and sms service is not enabled`)
|
||||||
|
} else {
|
||||||
|
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||||
|
otpData, err := generateOTP(expiresAt)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to generate otp: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||||
|
log.Debug("Failed to set mfa session: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
smsBody := strings.Builder{}
|
||||||
|
smsBody.WriteString("Your verification code is: ")
|
||||||
|
smsBody.WriteString(otpData.Otp)
|
||||||
|
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
||||||
|
if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil {
|
||||||
|
log.Debug("Failed to send sms: ", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return &model.AuthResponse{
|
||||||
|
Message: "Please check text message for the OTP",
|
||||||
|
ShouldShowMobileOtpScreen: refs.NewBoolRef(isMobileLogin),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = crypto.VerifyPassword(*user.Password, params.Password)
|
err = crypto.VerifyPassword(*user.Password, params.Password)
|
||||||
|
@ -129,14 +218,6 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
if params.Scope != nil && len(scope) > 0 {
|
if params.Scope != nil && len(scope) > 0 {
|
||||||
scope = params.Scope
|
scope = params.Scope
|
||||||
}
|
}
|
||||||
isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
|
||||||
if err != nil || !isEmailServiceEnabled {
|
|
||||||
log.Debug("Email service not enabled: ", err)
|
|
||||||
}
|
|
||||||
isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled)
|
|
||||||
if err != nil || !isSMSServiceEnabled {
|
|
||||||
log.Debug("SMS service not enabled: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication)
|
isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication)
|
||||||
if err != nil || !isMFADisabled {
|
if err != nil || !isMFADisabled {
|
||||||
|
@ -157,44 +238,20 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
if err != nil || !isSMSOTPDisabled {
|
if err != nil || !isSMSOTPDisabled {
|
||||||
log.Debug("sms OTP service not enabled: ", err)
|
log.Debug("sms OTP service not enabled: ", err)
|
||||||
}
|
}
|
||||||
setOTPMFaSession := func(expiresAt int64) error {
|
|
||||||
mfaSession := uuid.NewString()
|
|
||||||
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to add mfasession: ", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cookie.SetMfaSession(gc, mfaSession)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// If multi factor authentication is enabled and we need to generate OTP for mail / sms based MFA
|
|
||||||
generateOTP := func(expiresAt int64) (*models.OTP, error) {
|
|
||||||
otp := utils.GenerateOTP()
|
|
||||||
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
|
||||||
Email: refs.StringValue(user.Email),
|
|
||||||
PhoneNumber: refs.StringValue(user.PhoneNumber),
|
|
||||||
Otp: otp,
|
|
||||||
ExpiresAt: expiresAt,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to add otp: ", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return otpData, nil
|
|
||||||
}
|
|
||||||
// If multi factor authentication is enabled and is email based login and email otp is enabled
|
// If multi factor authentication is enabled and is email based login and email otp is enabled
|
||||||
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isMailOTPDisabled && isEmailServiceEnabled && isEmailLogin {
|
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isMailOTPDisabled && isEmailServiceEnabled && isEmailLogin {
|
||||||
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||||
otpData, err := generateOTP(expiresAt)
|
otpData, err := generateOTP(expiresAt)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to generate otp: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||||
|
log.Debug("Failed to set mfa session: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
go func() {
|
go func() {
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to generate otp: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := setOTPMFaSession(expiresAt); err != nil {
|
|
||||||
log.Debug("Failed to set mfa session: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// exec it as go routine so that we can reduce the api latency
|
// exec it as go routine so that we can reduce the api latency
|
||||||
if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{
|
if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||||
"user": user.ToMap(),
|
"user": user.ToMap(),
|
||||||
|
@ -214,15 +271,15 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isSMSOTPDisabled && isSMSServiceEnabled && isMobileLogin {
|
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isSMSOTPDisabled && isSMSServiceEnabled && isMobileLogin {
|
||||||
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||||
otpData, err := generateOTP(expiresAt)
|
otpData, err := generateOTP(expiresAt)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to generate otp: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||||
|
log.Debug("Failed to set mfa session: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
go func() {
|
go func() {
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to generate otp: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := setOTPMFaSession(expiresAt); err != nil {
|
|
||||||
log.Debug("Failed to set mfa session: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
smsBody := strings.Builder{}
|
smsBody := strings.Builder{}
|
||||||
smsBody.WriteString("Your verification code is: ")
|
smsBody.WriteString("Your verification code is: ")
|
||||||
smsBody.WriteString(otpData.Otp)
|
smsBody.WriteString(otpData.Otp)
|
||||||
|
@ -320,6 +377,8 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Assign the combined data to the provided pointer
|
// Assign the combined data to the provided pointer
|
||||||
user.AppData = &appData
|
user.AppData = &appData
|
||||||
|
} else {
|
||||||
|
log.Errorf("Error getting author's redis cache: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res = &model.AuthResponse{
|
res = &model.AuthResponse{
|
||||||
|
|
|
@ -101,6 +101,30 @@ func MetaResolver(ctx context.Context) (*model.Meta, error) {
|
||||||
microsoftClientSecret = ""
|
microsoftClientSecret = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
twitchClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitchClientID)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get Twitch Client ID from environment variable", err)
|
||||||
|
microsoftClientID = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
twitchClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitchClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get Twitch Client Secret from environment variable", err)
|
||||||
|
microsoftClientSecret = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
robloxClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRobloxClientID)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get Roblox Client ID from environment variable", err)
|
||||||
|
microsoftClientID = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
robloxClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRobloxClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get Roblox Client Secret from environment variable", err)
|
||||||
|
microsoftClientSecret = ""
|
||||||
|
}
|
||||||
|
|
||||||
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication)
|
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get Disable Basic Authentication from environment variable", err)
|
log.Debug("Failed to get Disable Basic Authentication from environment variable", err)
|
||||||
|
@ -165,6 +189,8 @@ func MetaResolver(ctx context.Context) (*model.Meta, error) {
|
||||||
IsMultiFactorAuthEnabled: !isMultiFactorAuthenticationEnabled,
|
IsMultiFactorAuthEnabled: !isMultiFactorAuthenticationEnabled,
|
||||||
IsMobileBasicAuthenticationEnabled: !isMobileBasicAuthDisabled,
|
IsMobileBasicAuthenticationEnabled: !isMobileBasicAuthDisabled,
|
||||||
IsPhoneVerificationEnabled: !isMobileVerificationDisabled,
|
IsPhoneVerificationEnabled: !isMobileVerificationDisabled,
|
||||||
|
IsTwitchLoginEnabled: twitchClientID != "" && twitchClientSecret != "",
|
||||||
|
IsRobloxLoginEnabled: robloxClientID != "" && robloxClientSecret != "",
|
||||||
}
|
}
|
||||||
return &metaInfo, nil
|
return &metaInfo, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,14 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
emailHelper "github.com/authorizerdev/authorizer/server/email"
|
mailService "github.com/authorizerdev/authorizer/server/email"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/refs"
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
@ -32,44 +34,42 @@ func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*mod
|
||||||
log.Debug("Email or phone number is required")
|
log.Debug("Email or phone number is required")
|
||||||
return nil, errors.New("email or phone number is required")
|
return nil, errors.New("email or phone number is required")
|
||||||
}
|
}
|
||||||
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
var user *models.User
|
var user *models.User
|
||||||
var err error
|
var isEmailServiceEnabled, isSMSServiceEnabled bool
|
||||||
if email != "" {
|
if email != "" {
|
||||||
isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
isEmailServiceEnabled, err = memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||||
if err != nil || !isEmailServiceEnabled {
|
if err != nil || !isEmailServiceEnabled {
|
||||||
log.Debug("Email service not enabled: ", err)
|
log.Debug("Email service not enabled: ", err)
|
||||||
return nil, errors.New("email service not enabled")
|
return nil, errors.New("email service not enabled")
|
||||||
}
|
}
|
||||||
user, err = db.Provider.GetUserByEmail(ctx, email)
|
user, err = db.Provider.GetUserByEmail(ctx, email)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get user by email: ", err)
|
||||||
|
return nil, fmt.Errorf(`user with this email/phone not found`)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
isSMSServiceEnabled, err = memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||||
if err != nil || !isSMSServiceEnabled {
|
if err != nil || !isSMSServiceEnabled {
|
||||||
log.Debug("Email service not enabled: ", err)
|
log.Debug("Email service not enabled: ", err)
|
||||||
return nil, errors.New("email service not enabled")
|
return nil, errors.New("email service not enabled")
|
||||||
}
|
}
|
||||||
user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber)
|
user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get user by phone: ", err)
|
||||||
|
return nil, fmt.Errorf(`user with this email/phone not found`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to get user by email: ", err)
|
|
||||||
return nil, fmt.Errorf(`user with this email/phone not found`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.RevokedTimestamp != nil {
|
if user.RevokedTimestamp != nil {
|
||||||
log.Debug("User access is revoked")
|
log.Debug("User access is revoked")
|
||||||
return nil, fmt.Errorf(`user access has been revoked`)
|
return nil, fmt.Errorf(`user access has been revoked`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if email != "" && user.EmailVerifiedAt == nil {
|
if !refs.BoolValue(user.IsMultiFactorAuthEnabled) && user.EmailVerifiedAt != nil && user.PhoneNumberVerifiedAt != nil {
|
||||||
log.Debug("User email is not verified")
|
|
||||||
return nil, fmt.Errorf(`email not verified`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if phoneNumber != "" && user.PhoneNumberVerifiedAt == nil {
|
|
||||||
log.Debug("User phone number is not verified")
|
|
||||||
return nil, fmt.Errorf(`phone number not verified`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !refs.BoolValue(user.IsMultiFactorAuthEnabled) {
|
|
||||||
log.Debug("User multi factor authentication is not enabled")
|
log.Debug("User multi factor authentication is not enabled")
|
||||||
return nil, fmt.Errorf(`multi factor authentication not enabled`)
|
return nil, fmt.Errorf(`multi factor authentication not enabled`)
|
||||||
}
|
}
|
||||||
|
@ -97,30 +97,63 @@ func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*mod
|
||||||
Message: "Failed to get for given email",
|
Message: "Failed to get for given email",
|
||||||
}, errors.New("failed to get otp for given email")
|
}, errors.New("failed to get otp for given email")
|
||||||
}
|
}
|
||||||
|
// If multi factor authentication is enabled and we need to generate OTP for mail / sms based MFA
|
||||||
otp := utils.GenerateOTP()
|
generateOTP := func(expiresAt int64) (*models.OTP, error) {
|
||||||
if _, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
otp := utils.GenerateOTP()
|
||||||
Email: refs.StringValue(user.Email),
|
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||||
Otp: otp,
|
Email: refs.StringValue(user.Email),
|
||||||
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
|
PhoneNumber: refs.StringValue(user.PhoneNumber),
|
||||||
}); err != nil {
|
Otp: otp,
|
||||||
log.Debug("Error upserting otp: ", err)
|
ExpiresAt: expiresAt,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add otp: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return otpData, nil
|
||||||
|
}
|
||||||
|
setOTPMFaSession := func(expiresAt int64) error {
|
||||||
|
mfaSession := uuid.NewString()
|
||||||
|
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add mfasession: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cookie.SetMfaSession(gc, mfaSession)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||||
|
otpData, err = generateOTP(expiresAt)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to generate otp: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||||
|
log.Debug("Failed to set mfa session: ", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if email != "" {
|
if email != "" {
|
||||||
// exec it as go routine so that we can reduce the api latency
|
go func() {
|
||||||
go emailHelper.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{
|
// exec it as go routine so that we can reduce the api latency
|
||||||
"user": user.ToMap(),
|
if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||||
"organization": utils.GetOrganization(),
|
"user": user.ToMap(),
|
||||||
"otp": otp,
|
"organization": utils.GetOrganization(),
|
||||||
})
|
"otp": otpData.Otp,
|
||||||
|
}); err != nil {
|
||||||
|
log.Debug("Failed to send otp email: ", err)
|
||||||
|
}
|
||||||
|
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
|
||||||
|
}()
|
||||||
} else {
|
} else {
|
||||||
smsBody := strings.Builder{}
|
go func() {
|
||||||
smsBody.WriteString("Your verification code is: ")
|
smsBody := strings.Builder{}
|
||||||
smsBody.WriteString(otp)
|
smsBody.WriteString("Your verification code is: ")
|
||||||
// exec it as go routine so that we can reduce the api latency
|
smsBody.WriteString(otpData.Otp)
|
||||||
go smsproviders.SendSMS(phoneNumber, smsBody.String())
|
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
||||||
|
if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil {
|
||||||
|
log.Debug("Failed to send sms: ", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
log.Info("OTP has been resent")
|
log.Info("OTP has been resent")
|
||||||
return &model.Response{
|
return &model.Response{
|
||||||
|
|
|
@ -94,6 +94,8 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Assign the combined data to the provided pointer
|
// Assign the combined data to the provided pointer
|
||||||
user.AppData = &appData
|
user.AppData = &appData
|
||||||
|
} else {
|
||||||
|
log.Errorf("Error getting author's redis cache: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res = &model.AuthResponse{
|
res = &model.AuthResponse{
|
||||||
|
|
|
@ -290,25 +290,26 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
||||||
} else if !disablePhoneVerification && isSMSServiceEnabled && isMobileSignup {
|
} else if !disablePhoneVerification && isSMSServiceEnabled && isMobileSignup {
|
||||||
duration, _ := time.ParseDuration("10m")
|
duration, _ := time.ParseDuration("10m")
|
||||||
smsCode := utils.GenerateOTP()
|
smsCode := utils.GenerateOTP()
|
||||||
|
|
||||||
smsBody := strings.Builder{}
|
smsBody := strings.Builder{}
|
||||||
smsBody.WriteString("Your verification code is: ")
|
smsBody.WriteString("Your verification code is: ")
|
||||||
smsBody.WriteString(smsCode)
|
smsBody.WriteString(smsCode)
|
||||||
|
expiresAt := time.Now().Add(duration).Unix()
|
||||||
// TODO: For those who enabled the webhook to call their sms vendor separately - sending the otp to their api
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("error while upserting user: ", err.Error())
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, err = db.Provider.UpsertOTP(ctx, &models.OTP{
|
_, err = db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||||
PhoneNumber: phoneNumber,
|
PhoneNumber: phoneNumber,
|
||||||
Otp: smsCode,
|
Otp: smsCode,
|
||||||
ExpiresAt: time.Now().Add(duration).Unix(),
|
ExpiresAt: expiresAt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("error while upserting OTP: ", err.Error())
|
log.Debug("error while upserting OTP: ", err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
mfaSession := uuid.NewString()
|
||||||
|
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add mfasession: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cookie.SetMfaSession(gc, mfaSession)
|
||||||
go func() {
|
go func() {
|
||||||
smsproviders.SendSMS(phoneNumber, smsBody.String())
|
smsproviders.SendSMS(phoneNumber, smsBody.String())
|
||||||
utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ func TestEndpointResolver(ctx context.Context, params model.TestEndpointRequest)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("error reading response: ", err)
|
log.Debug("error reading response: ", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -48,7 +48,18 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||||
"user_id": params.ID,
|
"user_id": params.ID,
|
||||||
})
|
})
|
||||||
|
|
||||||
if params.GivenName == nil && params.FamilyName == nil && params.Picture == nil && params.MiddleName == nil && params.Nickname == nil && params.Email == nil && params.Birthdate == nil && params.Gender == nil && params.PhoneNumber == nil && params.Roles == nil && params.IsMultiFactorAuthEnabled == nil && params.AppData == nil {
|
if params.GivenName == nil &&
|
||||||
|
params.FamilyName == nil &&
|
||||||
|
params.Picture == nil &&
|
||||||
|
params.MiddleName == nil &&
|
||||||
|
params.Nickname == nil &&
|
||||||
|
params.Email == nil &&
|
||||||
|
params.Birthdate == nil &&
|
||||||
|
params.Gender == nil &&
|
||||||
|
params.PhoneNumber == nil &&
|
||||||
|
params.Roles == nil &&
|
||||||
|
params.IsMultiFactorAuthEnabled == nil &&
|
||||||
|
params.AppData == nil {
|
||||||
log.Debug("No params to update")
|
log.Debug("No params to update")
|
||||||
return res, fmt.Errorf("please enter atleast one param to update")
|
return res, fmt.Errorf("please enter atleast one param to update")
|
||||||
}
|
}
|
||||||
|
@ -142,6 +153,15 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||||
user.EmailVerifiedAt = nil
|
user.EmailVerifiedAt = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if params.PhoneNumberVerified != nil {
|
||||||
|
if *params.PhoneNumberVerified {
|
||||||
|
now := time.Now().Unix()
|
||||||
|
user.PhoneNumberVerifiedAt = &now
|
||||||
|
} else {
|
||||||
|
user.PhoneNumberVerifiedAt = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if params.Email != nil && refs.StringValue(user.Email) != refs.StringValue(params.Email) {
|
if params.Email != nil && refs.StringValue(user.Email) != refs.StringValue(params.Email) {
|
||||||
// check if valid email
|
// check if valid email
|
||||||
|
@ -197,6 +217,24 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
|
||||||
|
phone := strings.TrimSpace(refs.StringValue(params.PhoneNumber))
|
||||||
|
if len(phone) < 10 || len(phone) > 15 {
|
||||||
|
log.Debug("Invalid phone number: ", *params.PhoneNumber)
|
||||||
|
return res, fmt.Errorf("invalid phone number")
|
||||||
|
}
|
||||||
|
// check if user with new phone number exists
|
||||||
|
_, err = db.Provider.GetUserByPhoneNumber(ctx, phone)
|
||||||
|
// err = nil means user exists
|
||||||
|
if err == nil {
|
||||||
|
log.Debug("User with phone number already exists: ", phone)
|
||||||
|
return res, fmt.Errorf("user with this phone number already exists")
|
||||||
|
}
|
||||||
|
go memorystore.Provider.DeleteAllUserSessions(user.ID)
|
||||||
|
user.PhoneNumber = &phone
|
||||||
|
user.PhoneNumberVerifiedAt = nil
|
||||||
|
}
|
||||||
|
|
||||||
rolesToSave := ""
|
rolesToSave := ""
|
||||||
if params.Roles != nil && len(params.Roles) > 0 {
|
if params.Roles != nil && len(params.Roles) > 0 {
|
||||||
currentRoles := strings.Split(user.Roles, ",")
|
currentRoles := strings.Split(user.Roles, ",")
|
||||||
|
@ -237,7 +275,6 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||||
if rolesToSave != "" {
|
if rolesToSave != "" {
|
||||||
user.Roles = rolesToSave
|
user.Roles = rolesToSave
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err = db.Provider.UpdateUser(ctx, user)
|
user, err = db.Provider.UpdateUser(ctx, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to update user: ", err)
|
log.Debug("Failed to update user: ", err)
|
||||||
|
|
|
@ -16,6 +16,7 @@ func InitRouter(log *logrus.Logger) *gin.Engine {
|
||||||
router.Use(middlewares.Logger(log), gin.Recovery())
|
router.Use(middlewares.Logger(log), gin.Recovery())
|
||||||
router.Use(middlewares.GinContextToContextMiddleware())
|
router.Use(middlewares.GinContextToContextMiddleware())
|
||||||
router.Use(middlewares.CORSMiddleware())
|
router.Use(middlewares.CORSMiddleware())
|
||||||
|
router.Use(middlewares.ClientCheckMiddleware())
|
||||||
|
|
||||||
router.GET("/", handlers.RootHandler())
|
router.GET("/", handlers.RootHandler())
|
||||||
router.GET("/health", handlers.HealthHandler())
|
router.GET("/health", handlers.HealthHandler())
|
||||||
|
|
|
@ -28,9 +28,11 @@ func loginTests(t *testing.T, s TestSetup) {
|
||||||
Email: refs.NewStringRef(email),
|
Email: refs.NewStringRef(email),
|
||||||
Password: s.TestInfo.Password,
|
Password: s.TestInfo.Password,
|
||||||
})
|
})
|
||||||
|
// access token should be empty as email is not verified
|
||||||
assert.NotNil(t, err, "should fail because email is not verified")
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, res)
|
assert.NotNil(t, res)
|
||||||
|
assert.Nil(t, res.AccessToken)
|
||||||
|
assert.NotEmpty(t, res.Message)
|
||||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, verificationRequest)
|
assert.NotNil(t, verificationRequest)
|
||||||
|
|
|
@ -33,8 +33,12 @@ func mobileLoginTests(t *testing.T, s TestSetup) {
|
||||||
PhoneNumber: refs.NewStringRef(phoneNumber),
|
PhoneNumber: refs.NewStringRef(phoneNumber),
|
||||||
Password: s.TestInfo.Password,
|
Password: s.TestInfo.Password,
|
||||||
})
|
})
|
||||||
assert.NotNil(t, err, "should fail because phone is not verified")
|
// access token should be empty as email is not verified
|
||||||
assert.Nil(t, res)
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, res)
|
||||||
|
assert.Nil(t, res.AccessToken)
|
||||||
|
assert.NotEmpty(t, res.Message)
|
||||||
|
assert.True(t, *res.ShouldShowMobileOtpScreen)
|
||||||
smsRequest, err := db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber)
|
smsRequest, err := db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, smsRequest.Otp)
|
assert.NotEmpty(t, smsRequest.Otp)
|
||||||
|
|
|
@ -35,8 +35,11 @@ func resendOTPTest(t *testing.T, s TestSetup) {
|
||||||
Email: refs.NewStringRef(email),
|
Email: refs.NewStringRef(email),
|
||||||
Password: s.TestInfo.Password,
|
Password: s.TestInfo.Password,
|
||||||
})
|
})
|
||||||
assert.Error(t, err)
|
// access token should be empty as email is not verified
|
||||||
assert.Nil(t, loginRes)
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, loginRes)
|
||||||
|
assert.Nil(t, loginRes.AccessToken)
|
||||||
|
assert.NotEmpty(t, loginRes.Message)
|
||||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, email, verificationRequest.Email)
|
assert.Equal(t, email, verificationRequest.Email)
|
||||||
|
@ -57,13 +60,6 @@ func resendOTPTest(t *testing.T, s TestSetup) {
|
||||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMailOTPLogin, false)
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMailOTPLogin, false)
|
||||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableTOTPLogin, true)
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableTOTPLogin, true)
|
||||||
|
|
||||||
// Resend otp should return error as no initial opt is being sent
|
|
||||||
resendOtpRes, err := resolvers.ResendOTPResolver(ctx, model.ResendOTPRequest{
|
|
||||||
Email: refs.NewStringRef(email),
|
|
||||||
})
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Nil(t, resendOtpRes)
|
|
||||||
|
|
||||||
// Login should not return error but access token should be empty as otp should have been sent
|
// Login should not return error but access token should be empty as otp should have been sent
|
||||||
loginRes, err = resolvers.LoginResolver(ctx, model.LoginInput{
|
loginRes, err = resolvers.LoginResolver(ctx, model.LoginInput{
|
||||||
Email: refs.NewStringRef(email),
|
Email: refs.NewStringRef(email),
|
||||||
|
@ -79,7 +75,7 @@ func resendOTPTest(t *testing.T, s TestSetup) {
|
||||||
assert.NotEmpty(t, otp.Otp)
|
assert.NotEmpty(t, otp.Otp)
|
||||||
|
|
||||||
// resend otp
|
// resend otp
|
||||||
resendOtpRes, err = resolvers.ResendOTPResolver(ctx, model.ResendOTPRequest{
|
resendOtpRes, err := resolvers.ResendOTPResolver(ctx, model.ResendOTPRequest{
|
||||||
Email: refs.NewStringRef(email),
|
Email: refs.NewStringRef(email),
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
|
@ -42,8 +42,11 @@ func totpLoginTest(t *testing.T, s TestSetup) {
|
||||||
Email: &email,
|
Email: &email,
|
||||||
Password: s.TestInfo.Password,
|
Password: s.TestInfo.Password,
|
||||||
})
|
})
|
||||||
assert.Error(t, err)
|
// access token should be empty as email is not verified
|
||||||
assert.Nil(t, loginRes)
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, loginRes)
|
||||||
|
assert.Nil(t, loginRes.AccessToken)
|
||||||
|
assert.NotEmpty(t, loginRes.Message)
|
||||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, email, verificationRequest.Email)
|
assert.Equal(t, email, verificationRequest.Email)
|
||||||
|
|
|
@ -47,8 +47,10 @@ func verifyOTPTest(t *testing.T, s TestSetup) {
|
||||||
Email: refs.NewStringRef(email),
|
Email: refs.NewStringRef(email),
|
||||||
Password: s.TestInfo.Password,
|
Password: s.TestInfo.Password,
|
||||||
})
|
})
|
||||||
assert.NotNil(t, err, "email is not verified")
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, loginRes)
|
assert.NotNil(t, loginRes)
|
||||||
|
assert.Nil(t, loginRes.AccessToken)
|
||||||
|
assert.NotEmpty(t, loginRes.Message)
|
||||||
|
|
||||||
// Verify the email
|
// Verify the email
|
||||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ func RegisterEvent(ctx context.Context, eventName string, authRecipe string, use
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
responseBytes, err := ioutil.ReadAll(resp.Body)
|
responseBytes, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("error reading response: ", err)
|
log.Debug("error reading response: ", err)
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Reference in New Issue
Block a user