Skip to content

Commit

Permalink
Add TokenValidatior component to JwtForm and generateToken function (#…
Browse files Browse the repository at this point in the history
…177)

* Add TokenValidatior component to JwtForm and generateToken function

* Update TokenValidatior component in JwtSection to fix handleClose function and add styling

* add tooltip

* fmt

---------

Co-authored-by: generall <[email protected]>
  • Loading branch information
kartik-gupta-ij and generall authored Apr 20, 2024
1 parent d7e54ca commit 5db568c
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 4 deletions.
10 changes: 8 additions & 2 deletions src/components/JwtSection/JwtForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ import IconButton from '@mui/material/IconButton';
import AddIcon from '@mui/icons-material/Add';
import CollectionAccessDialog from './CollectionAccessDialog';
import configureCollection from './RbacCollectionSettings';
import TokenValidatior from './TokenValidatior';

const ExpirationSelect = ({ expiration, setExpiration }) => {
const handleChange = (event) => {
setExpiration(event.target.value);
};

return (
<Box sx={{ mb: 4 }}>
<Box>
<FormControl fullWidth>
<InputLabel id="expiration-label">Expiration</InputLabel>
<Select
Expand Down Expand Up @@ -136,6 +137,7 @@ function JwtForm({
setManageAccess,
collections,
setCollections,
setTokenValidatior,
sx,
}) {
return (
Expand All @@ -153,7 +155,7 @@ function JwtForm({
</Tooltip>
</Box>

<Box sx={{ display: 'flex', alignItems: 'center', mb: 4 }}>
<Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
<Tooltip
title="Allows full access to the cluster, including
writing and deleting data,
Expand All @@ -167,6 +169,9 @@ function JwtForm({
/>
</Tooltip>
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', mb: 4 }}>
<TokenValidatior setTokenValidatior={setTokenValidatior} />
</Box>
</Box>

{/* Select */}
Expand All @@ -188,6 +193,7 @@ JwtForm.propTypes = {
setManageAccess: PropTypes.func.isRequired,
collections: PropTypes.array.isRequired,
setCollections: PropTypes.func.isRequired,
setTokenValidatior: PropTypes.func.isRequired,
sx: PropTypes.object,
};

Expand Down
172 changes: 172 additions & 0 deletions src/components/JwtSection/TokenValidatior.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import {
Box,
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
FormControl,
FormControlLabel,
IconButton,
InputLabel,
MenuItem,
Select,
Switch,
TextField,
Typography,
Tooltip,
} from '@mui/material';
import React, { useEffect, useState } from 'react';
import { useClient } from '../../context/client-context';
import { Check, Delete } from '@mui/icons-material';
import PropTypes from 'prop-types';

function configureTokenValidator({ validationCollection, matches, setTokenValidatior }) {
const valueExists = {
collection: validationCollection,
matches: Object.keys(matches).map((myKey) => ({
key: myKey,
value: matches[myKey],
})),
};
setTokenValidatior(valueExists);
}

const TokenValidatior = ({ setTokenValidatior }) => {
const [open, setOpen] = useState(false);
const [isTokenValidator, setIsTokenValidator] = useState(false);
const [selectedCollection, setSelectedCollection] = useState('');
const [collections, setCollections] = useState([]);
const handleClose = () => {
setOpen(false);
setIsTokenValidator(false);
};
const [matches, setMatches] = useState({});
const { client: qdrantClient } = useClient();
const [newMatchesKey, setNewMatchesKey] = useState('');
const [newMatchesValue, setNewMatchesValue] = useState('');
const handleToggle = () => {
if (isTokenValidator) {
setOpen(false);
setTokenValidatior({});
setIsTokenValidator(false);
} else {
setOpen(true);
setIsTokenValidator(true);
}
};
useEffect(() => {
const fetchCollections = async () => {
setCollections((await qdrantClient.getCollections()).collections);
};
fetchCollections();
}, [open]);

return (
<>
{/* <Box sx={{ display: 'flex', alignItems: 'center', ml: 1 }}> */}
<Tooltip title="Configures validation of the token based on record stored in the collection" placement="right">
<FormControlLabel
control={<Switch checked={isTokenValidator} onChange={handleToggle} />}
label="Token Validator"
/>
</Tooltip>
{/* </Box> */}
<Dialog fullWidth open={open} onClose={handleClose}>
<DialogTitle>Token Validator</DialogTitle>
<DialogContent>
<Box sx={{ display: 'flex', gap: 2, mb: 2, mt: 1 }}>
<FormControl fullWidth>
<InputLabel id="collection-select-label">Collection</InputLabel>
<Select
id="collection-select"
labelId="collection-select-label"
label="Collection"
value={selectedCollection?.name || ''}
onChange={(e) => {
setSelectedCollection(collections.find((collection) => collection.name === e.target.value));
}}
>
<MenuItem value="" key="">
Not Selected
</MenuItem>
{collections.map((collection) => (
<MenuItem key={collection.name} value={collection.name}>
{collection.name}
</MenuItem>
))}
</Select>
</FormControl>
</Box>

<Box sx={{ mb: 2 }}>
<Typography variant="h6" color={selectedCollection.name ? 'textPrimary' : 'textSecondary'}>
Set Matches
</Typography>
</Box>
{Object.keys(matches).map((key) => {
return (
<Box sx={{ display: 'flex', gap: 2, mb: 2, '& > :not(:last-of-type)': { width: '40%' } }} key={key}>
<TextField disabled label="Key" value={key} />
<TextField disabled label="Value" value={matches[key]} />
<IconButton
aria-label="delete"
size="large"
onClick={() => {
const newMatches = { ...matches };
delete newMatches[key];
setMatches(newMatches);
}}
>
<Delete />
</IconButton>
</Box>
);
})}
<Box sx={{ display: 'flex', gap: 2, '& > :not(:last-of-type)': { width: '40%' } }}>
<TextField label="Key" value={newMatchesKey} onChange={(e) => setNewMatchesKey(e.target.value)} />

<TextField label="Value" value={newMatchesValue} onChange={(e) => setNewMatchesValue(e.target.value)} />
<IconButton
aria-label="delete"
size="large"
onClick={() => {
setMatches((prev) => ({
...prev,
[newMatchesKey]: newMatchesValue,
}));
setNewMatchesKey('');
setNewMatchesValue('');
}}
disabled={!newMatchesKey || !newMatchesValue}
>
<Check />
</IconButton>
</Box>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button
onClick={() => {
configureTokenValidator({
validationCollection: selectedCollection.name,
matches,
setTokenValidatior,
});
setOpen(false);
}}
disabled={!selectedCollection.name || Object.keys(matches).length === 0}
>
Save
</Button>
</DialogActions>
</Dialog>
</>
);
};

TokenValidatior.propTypes = {
setTokenValidatior: PropTypes.func.isRequired,
};

export default TokenValidatior;
9 changes: 7 additions & 2 deletions src/pages/Jwt.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async function getJwt(apiKey, token, setJwt) {
setJwt(jwt);
}

function generateToken(globalAccess, manageAccess, expirationDays, configuredCollections) {
function generateToken(globalAccess, manageAccess, expirationDays, configuredCollections, tokenValidatior) {
const token = {};
if (globalAccess) {
if (manageAccess) {
Expand All @@ -30,6 +30,9 @@ function generateToken(globalAccess, manageAccess, expirationDays, configuredCol

token.exp = Math.floor(Date.now() / 1000) + expirationDays * secondsInDay;
}
if (tokenValidatior && tokenValidatior.collection && tokenValidatior.matches.length > 0) {
token.value_exists = tokenValidatior;
}

return token;
}
Expand All @@ -46,11 +49,12 @@ function Jwt() {

const [collections, setCollections] = useState([]);
const [configuredCollections, setConfiguredCollections] = useState([]);
const [tokenValidatior, setTokenValidatior] = useState({});
const [apiKey, setApiKey] = useState('');

const [jwt, setJwt] = useState('');

const token = generateToken(globalAccess, manageAccess, expirationDays, configuredCollections);
const token = generateToken(globalAccess, manageAccess, expirationDays, configuredCollections, tokenValidatior);

useEffect(() => {
if (apiKey && token) {
Expand Down Expand Up @@ -104,6 +108,7 @@ function Jwt() {
setManageAccess={setManageAccess}
collections={configuredCollections}
setCollections={setConfiguredCollections}
setTokenValidatior={setTokenValidatior}
/>

<JwtTokenViewer jwt={jwt} token={token} />
Expand Down

0 comments on commit 5db568c

Please sign in to comment.