Compare commits
34 Commits
1.1.20-bet
...
1.1.21.bet
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a916b8c32c | ||
![]() |
89f08b6d31 | ||
![]() |
cc23784df8 | ||
![]() |
7ff3b3018a | ||
![]() |
2b52932e98 | ||
![]() |
c716638725 | ||
![]() |
252cd1fa2d | ||
![]() |
7c2693b086 | ||
![]() |
eaa10ec5bc | ||
![]() |
253128ca0c | ||
![]() |
cddfe1e088 | ||
![]() |
8e655bcb5b | ||
![]() |
9a411e673c | ||
![]() |
346c8e5a47 | ||
![]() |
3cd99fe5f6 | ||
![]() |
2bd92d6028 | ||
![]() |
ff805e3ef2 | ||
![]() |
0115128ee7 | ||
![]() |
d8eceadd7f | ||
![]() |
e6c4fdff26 | ||
![]() |
e760a5598e | ||
![]() |
f62a22619b | ||
![]() |
c32a7fa1e4 | ||
![]() |
399b97079d | ||
![]() |
fe687cb0ca | ||
![]() |
9cb011e921 | ||
![]() |
4e1bba2ba8 | ||
![]() |
f1509f90f0 | ||
![]() |
bd4d48c7c5 | ||
![]() |
0e3242372b | ||
![]() |
89cea39c41 | ||
![]() |
570a0b9531 | ||
![]() |
686b3a4666 | ||
![]() |
b266a14108 |
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.17-alpine as go-builder
|
||||
FROM golang:1.19.1-alpine as go-builder
|
||||
WORKDIR /authorizer
|
||||
COPY server server
|
||||
COPY Makefile .
|
||||
|
6
app/.prettierrc.json
Normal file
6
app/.prettierrc.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"useTabs": false
|
||||
}
|
24
app/package-lock.json
generated
24
app/package-lock.json
generated
@@ -22,7 +22,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
"@types/styled-components": "^5.1.11"
|
||||
"@types/styled-components": "^5.1.11",
|
||||
"prettier": "2.7.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@authorizerdev/authorizer-js": {
|
||||
@@ -617,6 +618,21 @@
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
|
||||
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
@@ -1329,6 +1345,12 @@
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
|
||||
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
|
||||
"dev": true
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
|
@@ -5,7 +5,8 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "rm -rf build && NODE_ENV=production node ./esbuild.config.js",
|
||||
"start": "NODE_ENV=development node ./esbuild.config.js"
|
||||
"start": "NODE_ENV=development node ./esbuild.config.js",
|
||||
"format": "prettier --write --use-tabs 'src/**/*.(ts|tsx|js|jsx)'"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Lakhan Samani",
|
||||
@@ -19,11 +20,12 @@
|
||||
"react-dom": "^17.0.2",
|
||||
"react-is": "^17.0.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"typescript": "^4.3.5",
|
||||
"styled-components": "^5.3.0"
|
||||
"styled-components": "^5.3.0",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
"@types/styled-components": "^5.1.11"
|
||||
"@types/styled-components": "^5.1.11",
|
||||
"prettier": "2.7.1"
|
||||
}
|
||||
}
|
||||
|
@@ -5,9 +5,9 @@ import Root from './Root';
|
||||
import { createRandomString } from './utils/common';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__authorizer__: any;
|
||||
}
|
||||
interface Window {
|
||||
__authorizer__: any;
|
||||
}
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
|
@@ -32,12 +32,14 @@ export default function Root({
|
||||
const { token, loading, config } = useAuthorizer();
|
||||
|
||||
const searchParams = new URLSearchParams(
|
||||
hasWindow() ? window.location.search : ``
|
||||
hasWindow() ? window.location.search : ``,
|
||||
);
|
||||
const state = searchParams.get('state') || createRandomString();
|
||||
const scope = searchParams.get('scope')
|
||||
? searchParams.get('scope')?.toString().split(' ')
|
||||
: ['openid', 'profile', 'email'];
|
||||
const code = searchParams.get('code') || ''
|
||||
const nonce = searchParams.get('nonce') || ''
|
||||
|
||||
const urlProps: Record<string, any> = {
|
||||
state,
|
||||
@@ -57,10 +59,18 @@ export default function Root({
|
||||
useEffect(() => {
|
||||
if (token) {
|
||||
let redirectURL = config.redirectURL || '/app';
|
||||
let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}`;
|
||||
let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}&code=`+code;
|
||||
|
||||
if (code !== '') {
|
||||
params += `&code=${code}`
|
||||
}
|
||||
if (nonce !== '') {
|
||||
params += `&nonce=${nonce}`
|
||||
}
|
||||
if (token.refresh_token) {
|
||||
params += `&refresh_token=${token.refresh_token}`;
|
||||
}
|
||||
|
||||
const url = new URL(redirectURL);
|
||||
if (redirectURL.includes('?')) {
|
||||
redirectURL = `${redirectURL}&${params}`;
|
||||
|
@@ -1,28 +1,28 @@
|
||||
// colors: https://tailwindcss.com/docs/customizing-colors
|
||||
|
||||
export const theme = {
|
||||
colors: {
|
||||
primary: '#3B82F6',
|
||||
primaryDisabled: '#60A5FA',
|
||||
gray: '#D1D5DB',
|
||||
danger: '#DC2626',
|
||||
success: '#10B981',
|
||||
textColor: '#374151',
|
||||
},
|
||||
fonts: {
|
||||
// typography
|
||||
fontStack: '-apple-system, system-ui, sans-serif',
|
||||
colors: {
|
||||
primary: '#3B82F6',
|
||||
primaryDisabled: '#60A5FA',
|
||||
gray: '#D1D5DB',
|
||||
danger: '#DC2626',
|
||||
success: '#10B981',
|
||||
textColor: '#374151',
|
||||
},
|
||||
fonts: {
|
||||
// typography
|
||||
fontStack: '-apple-system, system-ui, sans-serif',
|
||||
|
||||
// font sizes
|
||||
largeText: '18px',
|
||||
mediumText: '14px',
|
||||
smallText: '12px',
|
||||
tinyText: '10px',
|
||||
},
|
||||
// font sizes
|
||||
largeText: '18px',
|
||||
mediumText: '14px',
|
||||
smallText: '12px',
|
||||
tinyText: '10px',
|
||||
},
|
||||
|
||||
radius: {
|
||||
card: '5px',
|
||||
button: '5px',
|
||||
input: '5px',
|
||||
},
|
||||
radius: {
|
||||
card: '5px',
|
||||
button: '5px',
|
||||
input: '5px',
|
||||
},
|
||||
};
|
||||
|
@@ -8,7 +8,7 @@ export const createRandomString = () => {
|
||||
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_~.';
|
||||
let random = '';
|
||||
const randomValues = Array.from(
|
||||
getCrypto().getRandomValues(new Uint8Array(43))
|
||||
getCrypto().getRandomValues(new Uint8Array(43)),
|
||||
);
|
||||
randomValues.forEach((v) => (random += charset[v % charset.length]));
|
||||
return random;
|
||||
|
6
dashboard/.prettierrc.json
Normal file
6
dashboard/.prettierrc.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"useTabs": false
|
||||
}
|
1191
dashboard/package-lock.json
generated
1191
dashboard/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,8 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "rm -rf build && NODE_ENV=production node ./esbuild.config.js",
|
||||
"start": "NODE_ENV=development node ./esbuild.config.js"
|
||||
"start": "NODE_ENV=development node ./esbuild.config.js",
|
||||
"format": "prettier --write --use-tabs 'src/**/*.(ts|tsx|js|jsx)'"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Lakhan Samani",
|
||||
@@ -35,6 +36,7 @@
|
||||
"urql": "^2.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-email-editor": "^1.1.7"
|
||||
"@types/react-email-editor": "^1.1.7",
|
||||
"prettier": "2.7.1"
|
||||
}
|
||||
}
|
||||
|
@@ -82,7 +82,7 @@ const EditUserModal = ({
|
||||
// @ts-ignore
|
||||
[property]: userData[property],
|
||||
}),
|
||||
{}
|
||||
{},
|
||||
);
|
||||
const res = await client
|
||||
.mutation(UpdateUser, { params: { ...updatedUserData, id: userData.id } })
|
||||
|
@@ -1,65 +1,65 @@
|
||||
import React from "react";
|
||||
import { Flex, Stack, Text, useMediaQuery } from "@chakra-ui/react";
|
||||
import InputField from "../../components/InputField";
|
||||
import { TextInputType, TextAreaInputType } from "../../constants";
|
||||
import React from 'react';
|
||||
import { Flex, Stack, Text, useMediaQuery } from '@chakra-ui/react';
|
||||
import InputField from '../../components/InputField';
|
||||
import { TextInputType, TextAreaInputType } from '../../constants';
|
||||
|
||||
const AccessToken = ({ variables, setVariables }: any) => {
|
||||
const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)");
|
||||
return (
|
||||
<div>
|
||||
{" "}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||
Access Token
|
||||
</Text>
|
||||
<Stack spacing={6} padding="2% 0%">
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "30%" : "50%"}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">Access Token Expiry Time:</Text>
|
||||
</Flex>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.ACCESS_TOKEN_EXPIRY_TIME}
|
||||
placeholder="0h15m0s"
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "30%" : "60%"}
|
||||
justifyContent="start"
|
||||
direction="column"
|
||||
>
|
||||
<Text fontSize="sm">Custom Scripts:</Text>
|
||||
<Text fontSize="xs" color="blackAlpha.500">
|
||||
(Used to add custom fields in ID token)
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextAreaInputType.CUSTOM_ACCESS_TOKEN_SCRIPT}
|
||||
placeholder="Add script here"
|
||||
minH="25vh"
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)');
|
||||
return (
|
||||
<div>
|
||||
{' '}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||
Access Token
|
||||
</Text>
|
||||
<Stack spacing={6} padding="2% 0%">
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? '30%' : '50%'}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">Access Token Expiry Time:</Text>
|
||||
</Flex>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.ACCESS_TOKEN_EXPIRY_TIME}
|
||||
placeholder="0h15m0s"
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? '30%' : '60%'}
|
||||
justifyContent="start"
|
||||
direction="column"
|
||||
>
|
||||
<Text fontSize="sm">Custom Scripts:</Text>
|
||||
<Text fontSize="xs" color="blackAlpha.500">
|
||||
(Used to add custom fields in ID token)
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextAreaInputType.CUSTOM_ACCESS_TOKEN_SCRIPT}
|
||||
placeholder="Add script here"
|
||||
minH="25vh"
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessToken;
|
||||
export default AccessToken;
|
||||
|
@@ -1,35 +1,35 @@
|
||||
import React from "react";
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react";
|
||||
import InputField from "../../components/InputField";
|
||||
import { ArrayInputType} from "../../constants";
|
||||
import React from 'react';
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from '@chakra-ui/react';
|
||||
import InputField from '../../components/InputField';
|
||||
import { ArrayInputType } from '../../constants';
|
||||
|
||||
const DomainWhiteListing = ({ variables, setVariables }: any) => {
|
||||
const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)");
|
||||
return (
|
||||
<div>
|
||||
{" "}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||
Domain White Listing
|
||||
</Text>
|
||||
<Stack spacing={6} padding="2% 0%">
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Allowed Origins:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={ArrayInputType.ALLOWED_ORIGINS}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)');
|
||||
return (
|
||||
<div>
|
||||
{' '}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||
Domain White Listing
|
||||
</Text>
|
||||
<Stack spacing={6} padding="2% 0%">
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Allowed Origins:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={ArrayInputType.ALLOWED_ORIGINS}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DomainWhiteListing;
|
||||
export default DomainWhiteListing;
|
||||
|
@@ -1,114 +1,114 @@
|
||||
import React from "react";
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react";
|
||||
import InputField from "../../components/InputField";
|
||||
import { TextInputType, HiddenInputType} from "../../constants";
|
||||
import React from 'react';
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from '@chakra-ui/react';
|
||||
import InputField from '../../components/InputField';
|
||||
import { TextInputType, HiddenInputType } from '../../constants';
|
||||
const EmailConfigurations = ({
|
||||
variables,
|
||||
setVariables,
|
||||
fieldVisibility,
|
||||
setFieldVisibility,
|
||||
variables,
|
||||
setVariables,
|
||||
fieldVisibility,
|
||||
setFieldVisibility,
|
||||
}: any) => {
|
||||
const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)");
|
||||
return (
|
||||
<div>
|
||||
{" "}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||
Email Configurations
|
||||
</Text>
|
||||
<Stack spacing={6} padding="2% 0%">
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">SMTP Host:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.SMTP_HOST}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">SMTP Port:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.SMTP_PORT}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "30%" : "40%"}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">SMTP Username:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.SMTP_USERNAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "30%" : "40%"}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">SMTP Password:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
fieldVisibility={fieldVisibility}
|
||||
setFieldVisibility={setFieldVisibility}
|
||||
inputType={HiddenInputType.SMTP_PASSWORD}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">From Email:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.SENDER_EMAIL}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)');
|
||||
return (
|
||||
<div>
|
||||
{' '}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||
Email Configurations
|
||||
</Text>
|
||||
<Stack spacing={6} padding="2% 0%">
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">SMTP Host:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.SMTP_HOST}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">SMTP Port:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.SMTP_PORT}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? '30%' : '40%'}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">SMTP Username:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.SMTP_USERNAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? '30%' : '40%'}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">SMTP Password:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
fieldVisibility={fieldVisibility}
|
||||
setFieldVisibility={setFieldVisibility}
|
||||
inputType={HiddenInputType.SMTP_PASSWORD}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">From Email:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.SENDER_EMAIL}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmailConfigurations;
|
||||
export default EmailConfigurations;
|
||||
|
@@ -126,6 +126,40 @@ const Features = ({ variables, setVariables }: any) => {
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Stack>
|
||||
<Divider paddingY={5} />
|
||||
<Text fontSize="md" paddingTop={5} fontWeight="bold" mb={5}>
|
||||
Cookie Security Features
|
||||
</Text>
|
||||
<Stack spacing={6}>
|
||||
<Flex>
|
||||
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||
<Text fontSize="sm">Use Secure App Cookie:</Text>
|
||||
<Text fontSize="x-small">
|
||||
Note: If you set this to insecure, it will set{' '}
|
||||
<code>sameSite</code> property of cookie to <code>lax</code> mode
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex justifyContent="start">
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={SwitchInputType.APP_COOKIE_SECURE}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="100%" alignItems="baseline" flexDir="column">
|
||||
<Text fontSize="sm">Use Secure Admin Cookie:</Text>
|
||||
</Flex>
|
||||
<Flex justifyContent="start">
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={SwitchInputType.ADMIN_COOKIE_SECURE}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@@ -37,7 +37,7 @@ const JSTConfigurations = ({
|
||||
JSON.stringify({
|
||||
type: variables.JWT_TYPE,
|
||||
key: variables.JWT_PUBLIC_KEY || variables.JWT_SECRET,
|
||||
})
|
||||
}),
|
||||
);
|
||||
toast({
|
||||
title: `JWT config copied successfully`,
|
||||
|
@@ -1,60 +1,60 @@
|
||||
import React from "react";
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react";
|
||||
import InputField from "../InputField";
|
||||
import { TextInputType } from "../../constants";
|
||||
import React from 'react';
|
||||
import { Flex, Stack, Center, Text, useMediaQuery } from '@chakra-ui/react';
|
||||
import InputField from '../InputField';
|
||||
import { TextInputType } from '../../constants';
|
||||
|
||||
const OrganizationInfo = ({ variables, setVariables }: any) => {
|
||||
const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)");
|
||||
return (
|
||||
<div>
|
||||
{" "}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||
Organization Information
|
||||
</Text>
|
||||
<Stack spacing={6} padding="2% 0%">
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "30%" : "40%"}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">Organization Name:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.ORGANIZATION_NAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "30%" : "40%"}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">Organization Logo:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.ORGANIZATION_LOGO}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)');
|
||||
return (
|
||||
<div>
|
||||
{' '}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||
Organization Information
|
||||
</Text>
|
||||
<Stack spacing={6} padding="2% 0%">
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? '30%' : '40%'}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">Organization Name:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.ORGANIZATION_NAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? '30%' : '40%'}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">Organization Logo:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.ORGANIZATION_LOGO}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrganizationInfo;
|
||||
export default OrganizationInfo;
|
||||
|
@@ -1,138 +1,138 @@
|
||||
import React from "react";
|
||||
import React from 'react';
|
||||
import {
|
||||
Flex,
|
||||
Stack,
|
||||
Center,
|
||||
Text,
|
||||
Input,
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
useMediaQuery,
|
||||
} from "@chakra-ui/react";
|
||||
import { FaRegEyeSlash, FaRegEye } from "react-icons/fa";
|
||||
import InputField from "../InputField";
|
||||
import { HiddenInputType } from "../../constants";
|
||||
Flex,
|
||||
Stack,
|
||||
Center,
|
||||
Text,
|
||||
Input,
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
useMediaQuery,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaRegEyeSlash, FaRegEye } from 'react-icons/fa';
|
||||
import InputField from '../InputField';
|
||||
import { HiddenInputType } from '../../constants';
|
||||
const SecurityAdminSecret = ({
|
||||
variables,
|
||||
setVariables,
|
||||
fieldVisibility,
|
||||
setFieldVisibility,
|
||||
validateAdminSecretHandler,
|
||||
adminSecret,
|
||||
variables,
|
||||
setVariables,
|
||||
fieldVisibility,
|
||||
setFieldVisibility,
|
||||
validateAdminSecretHandler,
|
||||
adminSecret,
|
||||
}: any) => {
|
||||
const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)");
|
||||
return (
|
||||
<div>
|
||||
{" "}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold">
|
||||
Security (Admin Secret)
|
||||
</Text>
|
||||
<Stack
|
||||
spacing={6}
|
||||
padding="0 5%"
|
||||
marginTop="3%"
|
||||
border="1px solid #ff7875"
|
||||
borderRadius="5px"
|
||||
>
|
||||
<Flex
|
||||
marginTop={isNotSmallerScreen ? "3%" : "5%"}
|
||||
direction={isNotSmallerScreen ? "row" : "column"}
|
||||
>
|
||||
<Flex
|
||||
mt={3}
|
||||
w={isNotSmallerScreen ? "30%" : "40%"}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">Old Admin Secret:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputGroup size="sm">
|
||||
<Input
|
||||
borderRadius={5}
|
||||
size="sm"
|
||||
placeholder="Enter Old Admin Secret"
|
||||
value={adminSecret.value as string}
|
||||
onChange={(event: any) => validateAdminSecretHandler(event)}
|
||||
type={
|
||||
!fieldVisibility[HiddenInputType.OLD_ADMIN_SECRET]
|
||||
? "password"
|
||||
: "text"
|
||||
}
|
||||
/>
|
||||
<InputRightElement
|
||||
right="5px"
|
||||
children={
|
||||
<Flex>
|
||||
{fieldVisibility[HiddenInputType.OLD_ADMIN_SECRET] ? (
|
||||
<Center
|
||||
w="25px"
|
||||
margin="0 1.5%"
|
||||
cursor="pointer"
|
||||
onClick={() =>
|
||||
setFieldVisibility({
|
||||
...fieldVisibility,
|
||||
[HiddenInputType.OLD_ADMIN_SECRET]: false,
|
||||
})
|
||||
}
|
||||
>
|
||||
<FaRegEyeSlash color="#bfbfbf" />
|
||||
</Center>
|
||||
) : (
|
||||
<Center
|
||||
w="25px"
|
||||
margin="0 1.5%"
|
||||
cursor="pointer"
|
||||
onClick={() =>
|
||||
setFieldVisibility({
|
||||
...fieldVisibility,
|
||||
[HiddenInputType.OLD_ADMIN_SECRET]: true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<FaRegEye color="#bfbfbf" />
|
||||
</Center>
|
||||
)}
|
||||
</Flex>
|
||||
}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex
|
||||
paddingBottom="3%"
|
||||
direction={isNotSmallerScreen ? "row" : "column"}
|
||||
>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? "30%" : "50%"}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">New Admin Secret:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
||||
mt={isNotSmallerScreen ? "0" : "3"}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
mb={3}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={HiddenInputType.ADMIN_SECRET}
|
||||
fieldVisibility={fieldVisibility}
|
||||
setFieldVisibility={setFieldVisibility}
|
||||
isDisabled={adminSecret.disableInputField}
|
||||
placeholder="Enter New Admin Secret"
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)');
|
||||
return (
|
||||
<div>
|
||||
{' '}
|
||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold">
|
||||
Security (Admin Secret)
|
||||
</Text>
|
||||
<Stack
|
||||
spacing={6}
|
||||
padding="0 5%"
|
||||
marginTop="3%"
|
||||
border="1px solid #ff7875"
|
||||
borderRadius="5px"
|
||||
>
|
||||
<Flex
|
||||
marginTop={isNotSmallerScreen ? '3%' : '5%'}
|
||||
direction={isNotSmallerScreen ? 'row' : 'column'}
|
||||
>
|
||||
<Flex
|
||||
mt={3}
|
||||
w={isNotSmallerScreen ? '30%' : '40%'}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">Old Admin Secret:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputGroup size="sm">
|
||||
<Input
|
||||
borderRadius={5}
|
||||
size="sm"
|
||||
placeholder="Enter Old Admin Secret"
|
||||
value={adminSecret.value as string}
|
||||
onChange={(event: any) => validateAdminSecretHandler(event)}
|
||||
type={
|
||||
!fieldVisibility[HiddenInputType.OLD_ADMIN_SECRET]
|
||||
? 'password'
|
||||
: 'text'
|
||||
}
|
||||
/>
|
||||
<InputRightElement
|
||||
right="5px"
|
||||
children={
|
||||
<Flex>
|
||||
{fieldVisibility[HiddenInputType.OLD_ADMIN_SECRET] ? (
|
||||
<Center
|
||||
w="25px"
|
||||
margin="0 1.5%"
|
||||
cursor="pointer"
|
||||
onClick={() =>
|
||||
setFieldVisibility({
|
||||
...fieldVisibility,
|
||||
[HiddenInputType.OLD_ADMIN_SECRET]: false,
|
||||
})
|
||||
}
|
||||
>
|
||||
<FaRegEyeSlash color="#bfbfbf" />
|
||||
</Center>
|
||||
) : (
|
||||
<Center
|
||||
w="25px"
|
||||
margin="0 1.5%"
|
||||
cursor="pointer"
|
||||
onClick={() =>
|
||||
setFieldVisibility({
|
||||
...fieldVisibility,
|
||||
[HiddenInputType.OLD_ADMIN_SECRET]: true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<FaRegEye color="#bfbfbf" />
|
||||
</Center>
|
||||
)}
|
||||
</Flex>
|
||||
}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex
|
||||
paddingBottom="3%"
|
||||
direction={isNotSmallerScreen ? 'row' : 'column'}
|
||||
>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? '30%' : '50%'}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">New Admin Secret:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
mb={3}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={HiddenInputType.ADMIN_SECRET}
|
||||
fieldVisibility={fieldVisibility}
|
||||
setFieldVisibility={setFieldVisibility}
|
||||
isDisabled={adminSecret.disableInputField}
|
||||
placeholder="Enter New Admin Secret"
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SecurityAdminSecret;
|
||||
export default SecurityAdminSecret;
|
||||
|
@@ -167,7 +167,7 @@ const GenerateKeysModal = ({ jwtType, getData }: propTypes) => {
|
||||
) : (
|
||||
<>
|
||||
{Object.values(HMACEncryptionType).includes(
|
||||
stateVariables.JWT_TYPE
|
||||
stateVariables.JWT_TYPE,
|
||||
) ? (
|
||||
<Flex marginTop="8">
|
||||
<Flex w="23%" justifyContent="start" alignItems="center">
|
||||
|
@@ -64,7 +64,7 @@ const InputField = ({
|
||||
const updateInputHandler = (
|
||||
type: string,
|
||||
operation: any,
|
||||
role: string = ''
|
||||
role: string = '',
|
||||
) => {
|
||||
if (operation === ArrayInputOperations.APPEND) {
|
||||
if (inputData[type] !== '') {
|
||||
@@ -78,7 +78,7 @@ const InputField = ({
|
||||
}
|
||||
if (operation === ArrayInputOperations.REMOVE) {
|
||||
let updatedEnvVars = variables[type].filter(
|
||||
(item: string) => item !== role
|
||||
(item: string) => item !== role,
|
||||
);
|
||||
setVariables({
|
||||
...variables,
|
||||
@@ -95,7 +95,7 @@ const InputField = ({
|
||||
onChange={(
|
||||
event: Event & {
|
||||
target: HTMLInputElement;
|
||||
}
|
||||
},
|
||||
) =>
|
||||
setVariables({
|
||||
...variables,
|
||||
@@ -120,7 +120,7 @@ const InputField = ({
|
||||
onChange={(
|
||||
event: Event & {
|
||||
target: HTMLInputElement;
|
||||
}
|
||||
},
|
||||
) =>
|
||||
setVariables({
|
||||
...variables,
|
||||
@@ -207,7 +207,7 @@ const InputField = ({
|
||||
updateInputHandler(
|
||||
inputType,
|
||||
ArrayInputOperations.REMOVE,
|
||||
role
|
||||
role,
|
||||
)
|
||||
}
|
||||
/>
|
||||
@@ -288,7 +288,7 @@ const InputField = ({
|
||||
onChange={(
|
||||
event: Event & {
|
||||
target: HTMLInputElement;
|
||||
}
|
||||
},
|
||||
) =>
|
||||
setVariables({
|
||||
...variables,
|
||||
|
@@ -304,7 +304,7 @@ const InviteMembersModal = ({
|
||||
onClick={() =>
|
||||
updateEmailListHandler(
|
||||
ArrayInputOperations.REMOVE,
|
||||
index
|
||||
index,
|
||||
)
|
||||
}
|
||||
>
|
||||
|
@@ -218,7 +218,7 @@ export const Sidebar = ({ onClose, ...rest }: SidebarProps) => {
|
||||
</NavItem>{' '}
|
||||
</Text>
|
||||
</NavLink>
|
||||
)
|
||||
),
|
||||
)}
|
||||
<Link
|
||||
href="/playground"
|
||||
|
@@ -185,7 +185,7 @@ const UpdateEmailTemplate = ({
|
||||
toast({
|
||||
title: capitalizeFirstLetter(
|
||||
res.data?._add_email_template?.message ||
|
||||
res.data?._update_email_template?.message
|
||||
res.data?._update_email_template?.message,
|
||||
),
|
||||
isClosable: true,
|
||||
status: 'success',
|
||||
@@ -220,7 +220,7 @@ const UpdateEmailTemplate = ({
|
||||
}, [isOpen]);
|
||||
useEffect(() => {
|
||||
const updatedTemplateVariables = Object.entries(
|
||||
emailTemplateVariables
|
||||
emailTemplateVariables,
|
||||
).reduce((acc, [key, val]): any => {
|
||||
if (
|
||||
(templateData[EmailTemplateInputDataFields.EVENT_NAME] !==
|
||||
@@ -367,7 +367,7 @@ const UpdateEmailTemplate = ({
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
EmailTemplateInputDataFields.EVENT_NAME,
|
||||
e.currentTarget.value
|
||||
e.currentTarget.value,
|
||||
)
|
||||
}
|
||||
>
|
||||
@@ -376,7 +376,7 @@ const UpdateEmailTemplate = ({
|
||||
<option value={value} key={key}>
|
||||
{key}
|
||||
</option>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</Select>
|
||||
</Flex>
|
||||
@@ -401,7 +401,7 @@ const UpdateEmailTemplate = ({
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
EmailTemplateInputDataFields.SUBJECT,
|
||||
e.currentTarget.value
|
||||
e.currentTarget.value,
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
@@ -126,13 +126,13 @@ const UpdateWebhookModal = ({
|
||||
...initWebhookValidatorData,
|
||||
});
|
||||
const [verifiedStatus, setVerifiedStatus] = useState<webhookVerifiedStatus>(
|
||||
webhookVerifiedStatus.PENDING
|
||||
webhookVerifiedStatus.PENDING,
|
||||
);
|
||||
const inputChangehandler = (
|
||||
inputType: string,
|
||||
value: any,
|
||||
headerInputType: string = WebhookInputHeaderFields.KEY,
|
||||
headerIndex: number = 0
|
||||
headerIndex: number = 0,
|
||||
) => {
|
||||
if (
|
||||
verifiedStatus !== webhookVerifiedStatus.PENDING &&
|
||||
@@ -238,7 +238,7 @@ const UpdateWebhookModal = ({
|
||||
validator[WebhookInputDataFields.ENDPOINT] &&
|
||||
!validator[WebhookInputDataFields.HEADERS].some(
|
||||
(headerData: headersValidatorDataType) =>
|
||||
!headerData.key || !headerData.value
|
||||
!headerData.key || !headerData.value,
|
||||
)
|
||||
);
|
||||
};
|
||||
@@ -256,7 +256,7 @@ const UpdateWebhookModal = ({
|
||||
(acc, data) => {
|
||||
return data.key ? { ...acc, [data.key]: data.value } : acc;
|
||||
},
|
||||
{}
|
||||
{},
|
||||
);
|
||||
if (Object.keys(headers).length) {
|
||||
params[WebhookInputDataFields.HEADERS] = headers;
|
||||
@@ -295,7 +295,7 @@ const UpdateWebhookModal = ({
|
||||
} else if (res.data?._add_webhook || res.data?._update_webhook) {
|
||||
toast({
|
||||
title: capitalizeFirstLetter(
|
||||
res.data?._add_webhook?.message || res.data?._update_webhook?.message
|
||||
res.data?._add_webhook?.message || res.data?._update_webhook?.message,
|
||||
),
|
||||
isClosable: true,
|
||||
status: 'success',
|
||||
@@ -333,7 +333,7 @@ const UpdateWebhookModal = ({
|
||||
setValidator({
|
||||
...validator,
|
||||
[WebhookInputDataFields.HEADERS]: new Array(
|
||||
formattedHeadersData.length
|
||||
formattedHeadersData.length,
|
||||
)
|
||||
.fill({})
|
||||
.map(() => ({ ...initHeadersValidatorData })),
|
||||
@@ -406,7 +406,7 @@ const UpdateWebhookModal = ({
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
WebhookInputDataFields.EVENT_NAME,
|
||||
e.currentTarget.value
|
||||
e.currentTarget.value,
|
||||
)
|
||||
}
|
||||
>
|
||||
@@ -415,7 +415,7 @@ const UpdateWebhookModal = ({
|
||||
<option value={value} key={key}>
|
||||
{key}
|
||||
</option>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</Select>
|
||||
</Flex>
|
||||
@@ -438,7 +438,7 @@ const UpdateWebhookModal = ({
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
WebhookInputDataFields.ENDPOINT,
|
||||
e.currentTarget.value
|
||||
e.currentTarget.value,
|
||||
)
|
||||
}
|
||||
/>
|
||||
@@ -462,7 +462,7 @@ const UpdateWebhookModal = ({
|
||||
onChange={() =>
|
||||
inputChangehandler(
|
||||
WebhookInputDataFields.ENABLED,
|
||||
!webhook[WebhookInputDataFields.ENABLED]
|
||||
!webhook[WebhookInputDataFields.ENABLED],
|
||||
)
|
||||
}
|
||||
/>
|
||||
@@ -517,7 +517,7 @@ const UpdateWebhookModal = ({
|
||||
WebhookInputDataFields.HEADERS,
|
||||
e.target.value,
|
||||
WebhookInputHeaderFields.KEY,
|
||||
index
|
||||
index,
|
||||
)
|
||||
}
|
||||
width="30%"
|
||||
@@ -540,7 +540,7 @@ const UpdateWebhookModal = ({
|
||||
WebhookInputDataFields.HEADERS,
|
||||
e.target.value,
|
||||
WebhookInputHeaderFields.VALUE,
|
||||
index
|
||||
index,
|
||||
)
|
||||
}
|
||||
width="65%"
|
||||
@@ -560,7 +560,7 @@ const UpdateWebhookModal = ({
|
||||
</InputRightElement>
|
||||
</InputGroup>
|
||||
</Flex>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</Flex>
|
||||
<Divider marginY={5} />
|
||||
|
@@ -161,15 +161,15 @@ const ViewWebhookLogsModal = ({
|
||||
<Td>
|
||||
<Text fontSize="sm">{`${logData.id.substring(
|
||||
0,
|
||||
5
|
||||
5,
|
||||
)}***${logData.id.substring(
|
||||
logData.id.length - 5,
|
||||
logData.id.length
|
||||
logData.id.length,
|
||||
)}`}</Text>
|
||||
</Td>
|
||||
<Td>
|
||||
{dayjs(logData.created_at * 1000).format(
|
||||
'MMM DD, YYYY'
|
||||
'MMM DD, YYYY',
|
||||
)}
|
||||
</Td>
|
||||
<Td>
|
||||
|
@@ -63,6 +63,8 @@ export const TextAreaInputType = {
|
||||
};
|
||||
|
||||
export const SwitchInputType = {
|
||||
APP_COOKIE_SECURE: 'APP_COOKIE_SECURE',
|
||||
ADMIN_COOKIE_SECURE: 'ADMIN_COOKIE_SECURE',
|
||||
DISABLE_LOGIN_PAGE: 'DISABLE_LOGIN_PAGE',
|
||||
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
|
||||
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
|
||||
@@ -133,6 +135,8 @@ export interface envVarTypes {
|
||||
ORGANIZATION_LOGO: string;
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT: string;
|
||||
ADMIN_SECRET: string;
|
||||
APP_COOKIE_SECURE: boolean;
|
||||
ADMIN_COOKIE_SECURE: boolean;
|
||||
DISABLE_LOGIN_PAGE: boolean;
|
||||
DISABLE_MAGIC_LINK_LOGIN: boolean;
|
||||
DISABLE_EMAIL_VERIFICATION: boolean;
|
||||
|
@@ -50,6 +50,8 @@ export const EnvVariablesQuery = `
|
||||
ORGANIZATION_NAME
|
||||
ORGANIZATION_LOGO
|
||||
ADMIN_SECRET
|
||||
APP_COOKIE_SECURE
|
||||
ADMIN_COOKIE_SECURE
|
||||
DISABLE_LOGIN_PAGE
|
||||
DISABLE_MAGIC_LINK_LOGIN
|
||||
DISABLE_EMAIL_VERIFICATION
|
||||
|
@@ -6,5 +6,5 @@ ReactDOM.render(
|
||||
<div>
|
||||
<App />
|
||||
</div>,
|
||||
document.getElementById('root')
|
||||
document.getElementById('root'),
|
||||
);
|
||||
|
@@ -154,7 +154,7 @@ const EmailTemplates = () => {
|
||||
<Td>{templateData[EmailTemplateInputDataFields.SUBJECT]}</Td>
|
||||
<Td>
|
||||
{dayjs(templateData.created_at * 1000).format(
|
||||
'MMM DD, YYYY'
|
||||
'MMM DD, YYYY',
|
||||
)}
|
||||
</Td>
|
||||
<Td>
|
||||
|
@@ -71,6 +71,8 @@ const Environment = () => {
|
||||
ORGANIZATION_LOGO: '',
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT: '',
|
||||
ADMIN_SECRET: '',
|
||||
APP_COOKIE_SECURE: false,
|
||||
ADMIN_COOKIE_SECURE: false,
|
||||
DISABLE_LOGIN_PAGE: false,
|
||||
DISABLE_MAGIC_LINK_LOGIN: false,
|
||||
DISABLE_EMAIL_VERIFICATION: false,
|
||||
@@ -155,7 +157,7 @@ const Environment = () => {
|
||||
// @ts-ignore
|
||||
[property]: envVariables[property],
|
||||
}),
|
||||
{}
|
||||
{},
|
||||
);
|
||||
if (
|
||||
updatedEnvVariables[HiddenInputType.ADMIN_SECRET] === '' ||
|
||||
|
@@ -29,7 +29,7 @@ import {
|
||||
MenuItem,
|
||||
useToast,
|
||||
Spinner,
|
||||
TableContainer
|
||||
TableContainer,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaAngleLeft,
|
||||
@@ -195,7 +195,7 @@ export default function Users() {
|
||||
|
||||
const updateAccessHandler = async (
|
||||
id: string,
|
||||
action: updateAccessActions
|
||||
action: updateAccessActions,
|
||||
) => {
|
||||
switch (action) {
|
||||
case updateAccessActions.ENABLE:
|
||||
@@ -263,8 +263,9 @@ export default function Users() {
|
||||
.toPromise();
|
||||
if (res.data?._update_user?.id) {
|
||||
toast({
|
||||
title: `Multi factor authentication ${user.is_multi_factor_auth_enabled ? 'disabled' : 'enabled'
|
||||
} for user`,
|
||||
title: `Multi factor authentication ${
|
||||
user.is_multi_factor_auth_enabled ? 'disabled' : 'enabled'
|
||||
} for user`,
|
||||
isClosable: true,
|
||||
status: 'success',
|
||||
position: 'bottom-right',
|
||||
@@ -387,7 +388,7 @@ export default function Users() {
|
||||
onClick={() =>
|
||||
updateAccessHandler(
|
||||
user.id,
|
||||
updateAccessActions.ENABLE
|
||||
updateAccessActions.ENABLE,
|
||||
)
|
||||
}
|
||||
>
|
||||
@@ -398,7 +399,7 @@ export default function Users() {
|
||||
onClick={() =>
|
||||
updateAccessHandler(
|
||||
user.id,
|
||||
updateAccessActions.REVOKE
|
||||
updateAccessActions.REVOKE,
|
||||
)
|
||||
}
|
||||
>
|
||||
@@ -407,13 +408,17 @@ export default function Users() {
|
||||
)}
|
||||
{user.is_multi_factor_auth_enabled ? (
|
||||
<MenuItem
|
||||
onClick={() => multiFactorAuthUpdateHandler(user)}
|
||||
onClick={() =>
|
||||
multiFactorAuthUpdateHandler(user)
|
||||
}
|
||||
>
|
||||
Disable MultiFactor Authentication
|
||||
</MenuItem>
|
||||
) : (
|
||||
<MenuItem
|
||||
onClick={() => multiFactorAuthUpdateHandler(user)}
|
||||
onClick={() =>
|
||||
multiFactorAuthUpdateHandler(user)
|
||||
}
|
||||
>
|
||||
Enable MultiFactor Authentication
|
||||
</MenuItem>
|
||||
|
@@ -170,12 +170,12 @@ const Webhooks = () => {
|
||||
label={JSON.stringify(
|
||||
webhook[WebhookInputDataFields.HEADERS],
|
||||
null,
|
||||
' '
|
||||
' ',
|
||||
)}
|
||||
>
|
||||
<Tag size="sm" variant="outline" colorScheme="gray">
|
||||
{Object.keys(
|
||||
webhook[WebhookInputDataFields.HEADERS] || {}
|
||||
webhook[WebhookInputDataFields.HEADERS] || {},
|
||||
)?.length.toString()}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
|
@@ -67,7 +67,7 @@ export const validateEmail = (email: string) => {
|
||||
return email
|
||||
.toLowerCase()
|
||||
.match(
|
||||
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
|
||||
)
|
||||
? true
|
||||
: false;
|
||||
@@ -78,7 +78,7 @@ export const validateURI = (uri: string) => {
|
||||
return uri
|
||||
.toLowerCase()
|
||||
.match(
|
||||
/(?:^|\s)((https?:\/\/)?(?:localhost|[\w-]+(?:\.[\w-]+)+)(:\d+)?(\/\S*)?)/
|
||||
/(?:^|\s)((https?:\/\/)?(?:localhost|[\w-]+(?:\.[\w-]+)+)(:\d+)?(\/\S*)?)/,
|
||||
)
|
||||
? true
|
||||
: false;
|
||||
|
@@ -27,7 +27,7 @@ const parseCSV = (file: File, delimiter: string): Promise<dataTypes[]> => {
|
||||
value: email.trim(),
|
||||
isInvalid: !validateEmail(email.trim()),
|
||||
};
|
||||
})
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
|
19
server/constants/oauth2.go
Normal file
19
server/constants/oauth2.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
// - query: for Authorization Code grant. 302 Found triggers redirect.
|
||||
ResponseModeQuery = "query"
|
||||
// - fragment: for Implicit grant. 302 Found triggers redirect.
|
||||
ResponseModeFragment = "fragment"
|
||||
// - form_post: 200 OK with response parameters embedded in an HTML form as hidden parameters.
|
||||
ResponseModeFormPost = "form_post"
|
||||
// - web_message: For Silent Authentication. Uses HTML5 web messaging.
|
||||
ResponseModeWebMessage = "web_message"
|
||||
|
||||
// For the Authorization Code grant, use response_type=code to include the authorization code.
|
||||
ResponseTypeCode = "code"
|
||||
// For the Implicit grant, use response_type=token to include an access token.
|
||||
ResponseTypeToken = "token"
|
||||
// For the Implicit grant of id_token, use response_type=id_token to include an identifier token.
|
||||
ResponseTypeIDToken = "id_token"
|
||||
)
|
@@ -29,8 +29,7 @@ func SetSession(gc *gin.Context, sessionID string) {
|
||||
domain = "." + domain
|
||||
}
|
||||
|
||||
// Use sameSite = lax by default
|
||||
// Since app cookie can come from cross site it becomes important to set this in lax mode.
|
||||
// Since app cookie can come from cross site it becomes important to set this in lax mode when insecure.
|
||||
// Example person using custom UI on their app domain and making request to authorizer domain.
|
||||
// For more information check:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
|
||||
|
@@ -12,9 +12,9 @@ type EmailTemplate struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
|
||||
EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name"`
|
||||
Subject string `gorm:"type:text" json:"subject" bson:"subject" cql:"subject"`
|
||||
Template string `gorm:"type:text" json:"template" bson:"template" cql:"template"`
|
||||
Design string `gorm:"type:text" json:"design" bson:"design" cql:"design"`
|
||||
Subject string `json:"subject" bson:"subject" cql:"subject"`
|
||||
Template string `json:"template" bson:"template" cql:"template"`
|
||||
Design string `json:"design" bson:"design" cql:"design"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
|
||||
}
|
||||
|
@@ -6,8 +6,8 @@ package models
|
||||
type Env struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
|
||||
EnvData string `gorm:"type:text" json:"env" bson:"env" cql:"env"`
|
||||
Hash string `gorm:"type:text" json:"hash" bson:"hash" cql:"hash"`
|
||||
EnvData string `json:"env" bson:"env" cql:"env"`
|
||||
Hash string `json:"hash" bson:"hash" cql:"hash"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ type User struct {
|
||||
|
||||
Email string `gorm:"unique" json:"email" bson:"email" cql:"email"`
|
||||
EmailVerifiedAt *int64 `json:"email_verified_at" bson:"email_verified_at" cql:"email_verified_at"`
|
||||
Password *string `gorm:"type:text" json:"password" bson:"password" cql:"password"`
|
||||
Password *string `json:"password" bson:"password" cql:"password"`
|
||||
SignupMethods string `json:"signup_methods" bson:"signup_methods" cql:"signup_methods"`
|
||||
GivenName *string `json:"given_name" bson:"given_name" cql:"given_name"`
|
||||
FamilyName *string `json:"family_name" bson:"family_name" cql:"family_name"`
|
||||
@@ -27,7 +27,7 @@ type User struct {
|
||||
Birthdate *string `json:"birthdate" bson:"birthdate" cql:"birthdate"`
|
||||
PhoneNumber *string `gorm:"unique" json:"phone_number" bson:"phone_number" cql:"phone_number"`
|
||||
PhoneNumberVerifiedAt *int64 `json:"phone_number_verified_at" bson:"phone_number_verified_at" cql:"phone_number_verified_at"`
|
||||
Picture *string `gorm:"type:text" json:"picture" bson:"picture" cql:"picture"`
|
||||
Picture *string `json:"picture" bson:"picture" cql:"picture"`
|
||||
Roles string `json:"roles" bson:"roles" cql:"roles"`
|
||||
RevokedTimestamp *int64 `json:"revoked_timestamp" bson:"revoked_timestamp" cql:"revoked_timestamp"`
|
||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled" bson:"is_multi_factor_auth_enabled" cql:"is_multi_factor_auth_enabled"`
|
||||
|
@@ -13,12 +13,12 @@ import (
|
||||
type VerificationRequest struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key" cql:"_key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
|
||||
Token string `gorm:"type:text" json:"token" bson:"token" cql:"jwt_token"` // token is reserved keyword in cassandra
|
||||
Token string `json:"token" bson:"token" cql:"jwt_token"` // token is reserved keyword in cassandra
|
||||
Identifier string `gorm:"uniqueIndex:idx_email_identifier;type:varchar(64)" json:"identifier" bson:"identifier" cql:"identifier"`
|
||||
ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at"`
|
||||
Email string `gorm:"uniqueIndex:idx_email_identifier;type:varchar(256)" json:"email" bson:"email" cql:"email"`
|
||||
Nonce string `gorm:"type:text" json:"nonce" bson:"nonce" cql:"nonce"`
|
||||
RedirectURI string `gorm:"type:text" json:"redirect_uri" bson:"redirect_uri" cql:"redirect_uri"`
|
||||
Nonce string `json:"nonce" bson:"nonce" cql:"nonce"`
|
||||
RedirectURI string `json:"redirect_uri" bson:"redirect_uri" cql:"redirect_uri"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
|
||||
}
|
||||
|
@@ -15,8 +15,8 @@ type Webhook struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
|
||||
EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name"`
|
||||
EndPoint string `gorm:"type:text" json:"endpoint" bson:"endpoint" cql:"endpoint"`
|
||||
Headers string `gorm:"type:text" json:"headers" bson:"headers" cql:"headers"`
|
||||
EndPoint string `json:"endpoint" bson:"endpoint" cql:"endpoint"`
|
||||
Headers string `json:"headers" bson:"headers" cql:"headers"`
|
||||
Enabled bool `json:"enabled" bson:"enabled" cql:"enabled"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
|
||||
|
@@ -14,8 +14,8 @@ type WebhookLog struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
|
||||
HttpStatus int64 `json:"http_status" bson:"http_status" cql:"http_status"`
|
||||
Response string `gorm:"type:text" json:"response" bson:"response" cql:"response"`
|
||||
Request string `gorm:"type:text" json:"request" bson:"request" cql:"request"`
|
||||
Response string `json:"response" bson:"response" cql:"response"`
|
||||
Request string `json:"request" bson:"request" cql:"request"`
|
||||
WebhookID string `gorm:"type:char(36)" json:"webhook_id" bson:"webhook_id" cql:"webhook_id"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
|
||||
|
@@ -6,26 +6,28 @@ require (
|
||||
github.com/99designs/gqlgen v0.17.20
|
||||
github.com/arangodb/go-driver v1.2.1
|
||||
github.com/coreos/go-oidc/v3 v3.1.0
|
||||
github.com/gin-gonic/gin v1.7.2
|
||||
github.com/go-playground/validator/v10 v10.8.0 // indirect
|
||||
github.com/gin-gonic/gin v1.8.1
|
||||
github.com/go-playground/validator/v10 v10.11.1 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.0
|
||||
github.com/goccy/go-json v0.9.11 // indirect
|
||||
github.com/gocql/gocql v1.2.0
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/ugorji/go v1.2.6 // indirect
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/vektah/gqlparser/v2 v2.5.1
|
||||
go.mongodb.org/mongo-driver v1.8.1
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
|
||||
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/mail.v2 v2.3.1
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
|
@@ -71,6 +71,7 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -90,8 +91,8 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA=
|
||||
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
|
||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@@ -99,19 +100,22 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-playground/validator/v10 v10.8.0 h1:1kAa0fCrnpv+QYdkdcRzrRM7AyYs5o8+jZdJCz9xj6k=
|
||||
github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk=
|
||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
|
||||
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
|
||||
github.com/go-redis/redis/v8 v8.11.0 h1:O1Td0mQ8UFChQ3N9zFQqo6kTU2cJ+/it88gDB+zg0wo=
|
||||
github.com/go-redis/redis/v8 v8.11.0/go.mod h1:DLomh7y2e3ggQXQLd1YgmvIfecPJoFl7WU5SOQ/r06M=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
|
||||
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gocql/gocql v1.2.0 h1:TZhsCd7fRuye4VyHr3WCvWwIQaZUmjsqnSIXK9FcVCE=
|
||||
github.com/gocql/gocql v1.2.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||
@@ -245,9 +249,8 @@ github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI=
|
||||
github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM=
|
||||
@@ -256,13 +259,15 @@ github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQ
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
@@ -278,6 +283,7 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
|
||||
@@ -287,9 +293,8 @@ github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
@@ -301,6 +306,10 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ=
|
||||
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -310,6 +319,9 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
|
||||
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f h1:a7clxaGmmqtdNTXyvrp/lVO/Gnkzlhc/+dLs5v965GM=
|
||||
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f/go.mod h1:/mK7FZ3mFYEn9zvNPhpngTyatyehSwte5bJZ4ehL5Xw=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
@@ -329,22 +341,22 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
|
||||
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
|
||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
github.com/urfave/cli/v2 v2.8.1 h1:CGuYNZF9IKZY/rfBe3lJpccSoIY1ytfvmgQT90cNOl4=
|
||||
github.com/urfave/cli/v2 v2.8.1/go.mod h1:Z41J9TPoffeoqP0Iza0YbAhGvymRdZAd2uPmZ5JxRdY=
|
||||
github.com/vektah/gqlparser/v2 v2.5.1 h1:ZGu+bquAY23jsxDRcYpWjttRZrUz07LbiY77gUOHcr4=
|
||||
@@ -396,8 +408,10 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP
|
||||
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -465,8 +479,10 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b h1:uKO3Js8lXGjpjdc4J3rqs0/Ex5yDKUGfk43tTYWVLas=
|
||||
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -528,11 +544,14 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -684,14 +703,16 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
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.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
@@ -714,6 +735,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.2.1 h1:h+3f1l9Ng2C072Y2tIiLgPpWN78r1KXL7bHJ0nTjlhU=
|
||||
|
@@ -71,8 +71,10 @@ type ComplexityRoot struct {
|
||||
|
||||
Env struct {
|
||||
AccessTokenExpiryTime func(childComplexity int) int
|
||||
AdminCookieSecure func(childComplexity int) int
|
||||
AdminSecret func(childComplexity int) int
|
||||
AllowedOrigins func(childComplexity int) int
|
||||
AppCookieSecure func(childComplexity int) int
|
||||
AppURL func(childComplexity int) int
|
||||
AppleClientID func(childComplexity int) int
|
||||
AppleClientSecret func(childComplexity int) int
|
||||
@@ -474,6 +476,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.Env.AccessTokenExpiryTime(childComplexity), true
|
||||
|
||||
case "Env.ADMIN_COOKIE_SECURE":
|
||||
if e.complexity.Env.AdminCookieSecure == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Env.AdminCookieSecure(childComplexity), true
|
||||
|
||||
case "Env.ADMIN_SECRET":
|
||||
if e.complexity.Env.AdminSecret == nil {
|
||||
break
|
||||
@@ -488,6 +497,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.Env.AllowedOrigins(childComplexity), true
|
||||
|
||||
case "Env.APP_COOKIE_SECURE":
|
||||
if e.complexity.Env.AppCookieSecure == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Env.AppCookieSecure(childComplexity), true
|
||||
|
||||
case "Env.APP_URL":
|
||||
if e.complexity.Env.AppURL == nil {
|
||||
break
|
||||
@@ -2079,6 +2095,8 @@ type Env {
|
||||
TWITTER_CLIENT_SECRET: String
|
||||
ORGANIZATION_NAME: String
|
||||
ORGANIZATION_LOGO: String
|
||||
APP_COOKIE_SECURE: Boolean!
|
||||
ADMIN_COOKIE_SECURE: Boolean!
|
||||
}
|
||||
|
||||
type ValidateJWTTokenResponse {
|
||||
@@ -2158,6 +2176,8 @@ input UpdateEnvInput {
|
||||
ALLOWED_ORIGINS: [String!]
|
||||
APP_URL: String
|
||||
RESET_PASSWORD_URL: String
|
||||
APP_COOKIE_SECURE: Boolean
|
||||
ADMIN_COOKIE_SECURE: Boolean
|
||||
DISABLE_EMAIL_VERIFICATION: Boolean
|
||||
DISABLE_BASIC_AUTHENTICATION: Boolean
|
||||
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
||||
@@ -5925,6 +5945,94 @@ func (ec *executionContext) fieldContext_Env_ORGANIZATION_LOGO(ctx context.Conte
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Env_APP_COOKIE_SECURE(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Env_APP_COOKIE_SECURE(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.AppCookieSecure, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(bool)
|
||||
fc.Result = res
|
||||
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Env_APP_COOKIE_SECURE(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Env",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type Boolean does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Env_ADMIN_COOKIE_SECURE(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Env_ADMIN_COOKIE_SECURE(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.AdminCookieSecure, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(bool)
|
||||
fc.Result = res
|
||||
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Env_ADMIN_COOKIE_SECURE(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Env",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type Boolean does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Error_message(ctx context.Context, field graphql.CollectedField, obj *model.Error) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Error_message(ctx, field)
|
||||
if err != nil {
|
||||
@@ -9308,6 +9416,10 @@ func (ec *executionContext) fieldContext_Query__env(ctx context.Context, field g
|
||||
return ec.fieldContext_Env_ORGANIZATION_NAME(ctx, field)
|
||||
case "ORGANIZATION_LOGO":
|
||||
return ec.fieldContext_Env_ORGANIZATION_LOGO(ctx, field)
|
||||
case "APP_COOKIE_SECURE":
|
||||
return ec.fieldContext_Env_APP_COOKIE_SECURE(ctx, field)
|
||||
case "ADMIN_COOKIE_SECURE":
|
||||
return ec.fieldContext_Env_ADMIN_COOKIE_SECURE(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type Env", field.Name)
|
||||
},
|
||||
@@ -14858,7 +14970,7 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
||||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SENDER_EMAIL", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "ORGANIZATION_NAME", "ORGANIZATION_LOGO"}
|
||||
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SENDER_EMAIL", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "ORGANIZATION_NAME", "ORGANIZATION_LOGO"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
@@ -14993,6 +15105,22 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
case "APP_COOKIE_SECURE":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("APP_COOKIE_SECURE"))
|
||||
it.AppCookieSecure, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
case "ADMIN_COOKIE_SECURE":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ADMIN_COOKIE_SECURE"))
|
||||
it.AdminCookieSecure, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
case "DISABLE_EMAIL_VERIFICATION":
|
||||
var err error
|
||||
|
||||
@@ -16069,6 +16197,20 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
|
||||
|
||||
out.Values[i] = ec._Env_ORGANIZATION_LOGO(ctx, field, obj)
|
||||
|
||||
case "APP_COOKIE_SECURE":
|
||||
|
||||
out.Values[i] = ec._Env_APP_COOKIE_SECURE(ctx, field, obj)
|
||||
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "ADMIN_COOKIE_SECURE":
|
||||
|
||||
out.Values[i] = ec._Env_ADMIN_COOKIE_SECURE(ctx, field, obj)
|
||||
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
|
@@ -110,6 +110,8 @@ type Env struct {
|
||||
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET"`
|
||||
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
||||
AppCookieSecure bool `json:"APP_COOKIE_SECURE"`
|
||||
AdminCookieSecure bool `json:"ADMIN_COOKIE_SECURE"`
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
@@ -277,6 +279,8 @@ type UpdateEnvInput struct {
|
||||
AllowedOrigins []string `json:"ALLOWED_ORIGINS"`
|
||||
AppURL *string `json:"APP_URL"`
|
||||
ResetPasswordURL *string `json:"RESET_PASSWORD_URL"`
|
||||
AppCookieSecure *bool `json:"APP_COOKIE_SECURE"`
|
||||
AdminCookieSecure *bool `json:"ADMIN_COOKIE_SECURE"`
|
||||
DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION"`
|
||||
DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION"`
|
||||
DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN"`
|
||||
|
@@ -146,6 +146,8 @@ type Env {
|
||||
TWITTER_CLIENT_SECRET: String
|
||||
ORGANIZATION_NAME: String
|
||||
ORGANIZATION_LOGO: String
|
||||
APP_COOKIE_SECURE: Boolean!
|
||||
ADMIN_COOKIE_SECURE: Boolean!
|
||||
}
|
||||
|
||||
type ValidateJWTTokenResponse {
|
||||
@@ -225,6 +227,8 @@ input UpdateEnvInput {
|
||||
ALLOWED_ORIGINS: [String!]
|
||||
APP_URL: String
|
||||
RESET_PASSWORD_URL: String
|
||||
APP_COOKIE_SECURE: Boolean
|
||||
ADMIN_COOKIE_SECURE: Boolean
|
||||
DISABLE_EMAIL_VERIFICATION: Boolean
|
||||
DISABLE_BASIC_AUTHENTICATION: Boolean
|
||||
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -26,6 +27,12 @@ import (
|
||||
// code_challenge_method = to prevent CSRF attack [only sh256 is supported]
|
||||
|
||||
// check the flow for generating and verifying codes: https://developer.okta.com/blog/2019/08/22/okta-authjs-pkce#:~:text=PKCE%20works%20by%20having%20the,is%20called%20the%20Code%20Challenge.
|
||||
|
||||
const (
|
||||
authorizeWebMessageTemplate = "authorize_web_message.tmpl"
|
||||
authorizeFormPostTemplate = "authorize_form_post.tmpl"
|
||||
)
|
||||
|
||||
func AuthorizeHandler() gin.HandlerFunc {
|
||||
return func(gc *gin.Context) {
|
||||
redirectURI := strings.TrimSpace(gc.Query("redirect_uri"))
|
||||
@@ -34,7 +41,6 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
codeChallenge := strings.TrimSpace(gc.Query("code_challenge"))
|
||||
scopeString := strings.TrimSpace(gc.Query("scope"))
|
||||
clientID := strings.TrimSpace(gc.Query("client_id"))
|
||||
template := "authorize.tmpl"
|
||||
responseMode := strings.TrimSpace(gc.Query("response_mode"))
|
||||
|
||||
var scope []string
|
||||
@@ -45,176 +51,98 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
}
|
||||
|
||||
if responseMode == "" {
|
||||
responseMode = "query"
|
||||
}
|
||||
|
||||
if responseMode != "query" && responseMode != "web_message" {
|
||||
log.Debug("Invalid response_mode: ", responseMode)
|
||||
gc.JSON(400, gin.H{"error": "invalid response mode"})
|
||||
responseMode = constants.ResponseModeQuery
|
||||
}
|
||||
|
||||
if redirectURI == "" {
|
||||
redirectURI = "/app"
|
||||
}
|
||||
|
||||
isQuery := responseMode == "query"
|
||||
|
||||
loginURL := "/app?state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI
|
||||
|
||||
if clientID == "" {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
log.Debug("Failed to get client_id: ", clientID)
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"error": "client_id is required",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if client, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); client != clientID || err != nil {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
log.Debug("Invalid client_id: ", clientID)
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"error": "invalid_client_id",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if state == "" {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
log.Debug("Failed to get state: ", state)
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"error": "state is required",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if responseType == "" {
|
||||
responseType = "token"
|
||||
}
|
||||
|
||||
isResponseTypeCode := responseType == "code"
|
||||
isResponseTypeToken := responseType == "token"
|
||||
|
||||
if !isResponseTypeCode && !isResponseTypeToken {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
log.Debug("Invalid response_type: ", responseType)
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"error": "response_type is invalid",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
if err := validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge); err != nil {
|
||||
log.Debug("invalid authorization request: ", err)
|
||||
gc.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if isResponseTypeCode {
|
||||
if codeChallenge == "" {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
log.Debug("Failed to get code_challenge: ", codeChallenge)
|
||||
gc.HTML(http.StatusBadRequest, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"error": "code_challenge is required",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
log := log.WithFields(log.Fields{
|
||||
"response_mode": responseMode,
|
||||
"response_type": responseType,
|
||||
"state": state,
|
||||
"code_challenge": codeChallenge,
|
||||
"scope": scope,
|
||||
"redirect_uri": redirectURI,
|
||||
})
|
||||
|
||||
code := uuid.New().String()
|
||||
nonce := uuid.New().String()
|
||||
memorystore.Provider.SetState(codeChallenge, code)
|
||||
|
||||
// used for response mode query or fragment
|
||||
loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + "&code=" + code + "&nonce=" + nonce
|
||||
loginURL := "/app?" + loginState
|
||||
|
||||
if responseMode == constants.ResponseModeFragment {
|
||||
loginURL = "/app#" + loginState
|
||||
}
|
||||
|
||||
if state == "" {
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]interface{}{
|
||||
"error": "state_required",
|
||||
"error_description": "state is required",
|
||||
},
|
||||
}, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
if responseType == constants.ResponseTypeCode && codeChallenge == "" {
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]interface{}{
|
||||
"error": "code_challenge_required",
|
||||
"error_description": "code challenge is required",
|
||||
},
|
||||
}, http.StatusOK)
|
||||
}
|
||||
|
||||
loginError := map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]interface{}{
|
||||
"error": "login_required",
|
||||
"error_description": "Login is required",
|
||||
},
|
||||
}
|
||||
sessionToken, err := cookie.GetSession(gc)
|
||||
if err != nil {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"error": "login_required",
|
||||
"error_description": "Login is required",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
log.Debug("GetSession failed: ", err)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
// get session from cookie
|
||||
claims, err := token.ValidateBrowserSession(gc, sessionToken)
|
||||
if err != nil {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"error": "login_required",
|
||||
"error_description": "Login is required",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
log.Debug("ValidateBrowserSession failed: ", err)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
userID := claims.Subject
|
||||
user, err := db.Provider.GetUserByID(gc, userID)
|
||||
if err != nil {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"error": "signup_required",
|
||||
"error_description": "Sign up required",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
log.Debug("GetUserByID failed: ", err)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]interface{}{
|
||||
"error": "signup_required",
|
||||
"error_description": "Sign up required",
|
||||
},
|
||||
}, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -223,72 +151,90 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
sessionKey = claims.LoginMethod + ":" + user.ID
|
||||
}
|
||||
|
||||
// if user is logged in
|
||||
// based on the response type code, generate the response
|
||||
if isResponseTypeCode {
|
||||
// rollover the session for security
|
||||
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
|
||||
nonce := uuid.New().String()
|
||||
newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod)
|
||||
if err != nil {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"error": "login_required",
|
||||
"error_description": "Login is required",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken)
|
||||
cookie.SetSession(gc, newSessionToken)
|
||||
code := uuid.New().String()
|
||||
memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken)
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"code": code,
|
||||
"state": state,
|
||||
},
|
||||
},
|
||||
})
|
||||
newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod)
|
||||
if err != nil {
|
||||
log.Debug("CreateSessionToken failed: ", err)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
if isResponseTypeToken {
|
||||
// rollover the session for security
|
||||
authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod)
|
||||
if err != nil {
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"error": "login_required",
|
||||
"error_description": "Login is required",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
if err := memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken); err != nil {
|
||||
log.Debug("SetState failed: ", err)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
// rollover the session for security
|
||||
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
|
||||
if responseType == constants.ResponseTypeCode {
|
||||
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken); err != nil {
|
||||
log.Debug("SetUserSession failed: ", err)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
cookie.SetSession(gc, newSessionToken)
|
||||
|
||||
// in case, response type is code and user is already logged in send the code and state
|
||||
// and cookie session will already be rolled over and set
|
||||
// gc.HTML(http.StatusOK, authorizeWebMessageTemplate, gin.H{
|
||||
// "target_origin": redirectURI,
|
||||
// "authorization_response": map[string]interface{}{
|
||||
// "type": "authorization_response",
|
||||
// "response": map[string]string{
|
||||
// "code": code,
|
||||
// "state": state,
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
|
||||
params := "code=" + code + "&state=" + state + "&nonce=" + nonce
|
||||
if responseMode == constants.ResponseModeQuery {
|
||||
if strings.Contains(redirectURI, "?") {
|
||||
redirectURI = redirectURI + "&" + params
|
||||
} else {
|
||||
redirectURI = redirectURI + "?" + params
|
||||
}
|
||||
} else if responseMode == constants.ResponseModeFragment {
|
||||
if strings.Contains(redirectURI, "#") {
|
||||
redirectURI = redirectURI + "&" + params
|
||||
} else {
|
||||
redirectURI = redirectURI + "#" + params
|
||||
}
|
||||
}
|
||||
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]interface{}{
|
||||
"code": code,
|
||||
"state": state,
|
||||
},
|
||||
}, http.StatusOK)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if responseType == constants.ResponseTypeToken || responseType == constants.ResponseTypeIDToken {
|
||||
// rollover the session for security
|
||||
authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod)
|
||||
if err != nil {
|
||||
log.Debug("CreateAuthToken failed: ", err)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash); err != nil {
|
||||
log.Debug("SetUserSession failed: ", err)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token); err != nil {
|
||||
log.Debug("SetUserSession failed: ", err)
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||
|
||||
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||
@@ -297,7 +243,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
}
|
||||
|
||||
// used of query mode
|
||||
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token
|
||||
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&code=" + code + "&nonce=" + nonce
|
||||
|
||||
res := map[string]interface{}{
|
||||
"access_token": authToken.AccessToken.Token,
|
||||
@@ -306,6 +252,8 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
"scope": scope,
|
||||
"token_type": "Bearer",
|
||||
"expires_in": expiresIn,
|
||||
"code": code,
|
||||
"nonce": nonce,
|
||||
}
|
||||
|
||||
if authToken.RefreshToken != nil {
|
||||
@@ -314,38 +262,72 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||
}
|
||||
|
||||
if isQuery {
|
||||
if responseMode == constants.ResponseModeQuery {
|
||||
if strings.Contains(redirectURI, "?") {
|
||||
gc.Redirect(http.StatusFound, redirectURI+"&"+params)
|
||||
redirectURI = redirectURI + "&" + params
|
||||
} else {
|
||||
gc.Redirect(http.StatusFound, redirectURI+"?"+params)
|
||||
redirectURI = redirectURI + "?" + params
|
||||
}
|
||||
} else if responseMode == constants.ResponseModeFragment {
|
||||
if strings.Contains(redirectURI, "#") {
|
||||
redirectURI = redirectURI + "&" + params
|
||||
} else {
|
||||
redirectURI = redirectURI + "#" + params
|
||||
}
|
||||
} else {
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": res,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": res,
|
||||
}, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
if isQuery {
|
||||
gc.Redirect(http.StatusFound, loginURL)
|
||||
} else {
|
||||
// by default return with error
|
||||
gc.HTML(http.StatusOK, template, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": map[string]interface{}{
|
||||
"type": "authorization_response",
|
||||
"response": map[string]string{
|
||||
"error": "login_required",
|
||||
"error_description": "Login is required",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge string) error {
|
||||
if responseType != constants.ResponseTypeCode && responseType != constants.ResponseTypeToken && responseType != constants.ResponseTypeIDToken {
|
||||
return fmt.Errorf("invalid response type %s. 'code' & 'token' are valid response_type", responseMode)
|
||||
}
|
||||
|
||||
if responseMode != constants.ResponseModeQuery && responseMode != constants.ResponseModeWebMessage && responseMode != constants.ResponseModeFragment && responseMode != constants.ResponseModeFormPost {
|
||||
return fmt.Errorf("invalid response mode %s. 'query', 'fragment', 'form_post' and 'web_message' are valid response_mode", responseMode)
|
||||
}
|
||||
|
||||
if client, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); client != clientID || err != nil {
|
||||
return fmt.Errorf("invalid client_id %s", clientID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleResponse(gc *gin.Context, responseMode, loginURI, redirectURI string, data map[string]interface{}, httpStatusCode int) {
|
||||
isAuthenticationRequired := false
|
||||
if _, ok := data["response"].(map[string]interface{})["error"]; ok {
|
||||
isAuthenticationRequired = true
|
||||
}
|
||||
|
||||
switch responseMode {
|
||||
case constants.ResponseModeQuery, constants.ResponseModeFragment:
|
||||
if isAuthenticationRequired {
|
||||
gc.Redirect(http.StatusFound, loginURI)
|
||||
} else {
|
||||
gc.Redirect(http.StatusFound, redirectURI)
|
||||
}
|
||||
return
|
||||
case constants.ResponseModeWebMessage:
|
||||
gc.HTML(httpStatusCode, authorizeWebMessageTemplate, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": data,
|
||||
})
|
||||
return
|
||||
case constants.ResponseModeFormPost:
|
||||
gc.HTML(httpStatusCode, authorizeFormPostTemplate, gin.H{
|
||||
"target_origin": redirectURI,
|
||||
"authorization_response": data["response"],
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@@ -20,9 +20,9 @@ func OpenIDConfigurationHandler() gin.HandlerFunc {
|
||||
"token_endpoint": issuer + "/token",
|
||||
"userinfo_endpoint": issuer + "/userinfo",
|
||||
"jwks_uri": issuer + "/.well-known/jwks.json",
|
||||
"response_types_supported": []string{"code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token"},
|
||||
"response_types_supported": []string{"code", "token", "id_token"},
|
||||
"scopes_supported": []string{"openid", "email", "profile", "email_verified", "given_name", "family_name", "nick_name", "picture"},
|
||||
"response_modes_supported": []string{"query", "fragment", "form_post"},
|
||||
"response_modes_supported": []string{"query", "fragment", "form_post", "web_message"},
|
||||
"id_token_signing_alg_values_supported": []string{jwtType},
|
||||
"claims_supported": []string{"aud", "exp", "iss", "iat", "sub", "given_name", "family_name", "middle_name", "nickname", "preferred_username", "picture", "email", "email_verified", "roles", "gender", "birthdate", "phone_number", "phone_number_verified"},
|
||||
})
|
||||
|
@@ -58,7 +58,10 @@ func main() {
|
||||
default:
|
||||
logLevel = logrus.InfoLevel
|
||||
}
|
||||
// set log level globally
|
||||
logrus.SetLevel(logLevel)
|
||||
|
||||
// set log level for go-gin middleware
|
||||
log.SetLevel(logLevel)
|
||||
|
||||
// show file path in log for debug or other log levels.
|
||||
|
@@ -57,7 +57,7 @@ func InitMemStore() error {
|
||||
}
|
||||
|
||||
redisURL := requiredEnvs.RedisURL
|
||||
if redisURL != "" && !requiredEnvs.disableRedisForEnv {
|
||||
if redisURL != "" && !requiredEnvs.DisableRedisForEnv {
|
||||
log.Info("Initializing Redis memory store")
|
||||
Provider, err = redis.NewRedisProvider(redisURL)
|
||||
if err != nil {
|
||||
|
@@ -27,7 +27,7 @@ type RequiredEnv struct {
|
||||
DatabaseCertKey string `json:"DATABASE_CERT_KEY"`
|
||||
DatabaseCACert string `json:"DATABASE_CA_CERT"`
|
||||
RedisURL string `json:"REDIS_URL"`
|
||||
disableRedisForEnv bool `json:"DISABLE_REDIS_FOR_ENV"`
|
||||
DisableRedisForEnv bool `json:"DISABLE_REDIS_FOR_ENV"`
|
||||
}
|
||||
|
||||
// RequiredEnvObj is a simple in-memory store for sessions.
|
||||
@@ -138,7 +138,7 @@ func InitRequiredEnv() error {
|
||||
DatabaseCertKey: dbCertKey,
|
||||
DatabaseCACert: dbCACert,
|
||||
RedisURL: redisURL,
|
||||
disableRedisForEnv: disableRedisForEnv,
|
||||
DisableRedisForEnv: disableRedisForEnv,
|
||||
}
|
||||
|
||||
RequiredEnvStoreObj = &RequiredEnvStore{
|
||||
|
@@ -179,6 +179,8 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
|
||||
res.DisableStrongPassword = store[constants.EnvKeyDisableStrongPassword].(bool)
|
||||
res.EnforceMultiFactorAuthentication = store[constants.EnvKeyEnforceMultiFactorAuthentication].(bool)
|
||||
res.DisableMultiFactorAuthentication = store[constants.EnvKeyDisableMultiFactorAuthentication].(bool)
|
||||
res.AdminCookieSecure = store[constants.EnvKeyAdminCookieSecure].(bool)
|
||||
res.AppCookieSecure = store[constants.EnvKeyAppCookieSecure].(bool)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
@@ -85,7 +85,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
return res, err
|
||||
}
|
||||
|
||||
// exec it as go routine so that we can reduce the api latency
|
||||
// execute it as go routine so that we can reduce the api latency
|
||||
go email.SendEmail([]string{params.Email}, constants.VerificationTypeForgotPassword, map[string]interface{}{
|
||||
"user": user.ToMap(),
|
||||
"organization": utils.GetOrganization(),
|
||||
|
13
templates/authorize_form_post.tmpl
Normal file
13
templates/authorize_form_post.tmpl
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Authorization Response</title>
|
||||
</head>
|
||||
<body onload="document.forms['authorize_form_post'].submit()">
|
||||
<form action="{{.target_origin}}" name="authorize_form_post" method="POST">
|
||||
{{ range $key, $val := .authorization_response }}
|
||||
<input type="hidden" key="{{$key}}" value="{{$val}}" name="{{$key}}" id="{{$key}}" />
|
||||
{{ end }}
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user