diff --git a/components/OAuth2Page/OAuth2Page.tsx b/components/OAuth2Page/OAuth2Page.tsx index d35f647..bb10144 100644 --- a/components/OAuth2Page/OAuth2Page.tsx +++ b/components/OAuth2Page/OAuth2Page.tsx @@ -88,10 +88,12 @@ const EditClientModal = ({ isAdmin: boolean; }>) => { const formRef = useRef(null); + const scopeReq = useSWR('/api/admin/oauth2/scopes'); + const grantReq = useSWR('/api/admin/oauth2/grants'); const { formData, handleInputChange, handleSubmit } = useForm< Partial - >(client || {}, () => { + >(client || { grants: 'authorization_code' }, () => { toast .promise( publishJSON( @@ -151,6 +153,16 @@ const EditClientModal = ({ value={formData.scope || ''} onChange={handleInputChange} /> + {scopeReq.data && ( + + Available:{' '} + {scopeReq.data + .filter( + (item) => !formData.scope?.split(' ').includes(item) + ) + .join(', ') || 'None'} + + )} @@ -160,6 +172,16 @@ const EditClientModal = ({ value={formData.grants || ''} onChange={handleInputChange} /> + {grantReq.data && ( + + Available:{' '} + {grantReq.data + .filter( + (item) => !formData.grants?.split(' ').includes(item) + ) + .join(', ') || 'None'} + + )} {isAdmin && ( <> @@ -268,7 +290,7 @@ const OAuth2ClientCard = ({ - {!client.activated && } + {!client.activated && ( + + )} {client.description} diff --git a/components/UsersPage/UsersPage.tsx b/components/UsersPage/UsersPage.tsx index f73deea..38f61f6 100644 --- a/components/UsersPage/UsersPage.tsx +++ b/components/UsersPage/UsersPage.tsx @@ -47,7 +47,7 @@ const PrivilegeEditor = ({ user: UserListItem; onChange: (privvy: Privilege[]) => void; }) => { - const [toggle, setToggle] = useState(false); + const [userPrivvy, setUserPrivvy] = useState(user.privileges || []); const [selectionAvailable, setSelectionAvailable] = useState([]); const [selectionExisting, setSelectionExisting] = useState([]); const [availablePrivileges, setAvailablePrivileges] = useState( @@ -61,7 +61,7 @@ const PrivilegeEditor = ({ ({ id }) => !(user.privileges || []).some((privvy) => privvy.id === id) ) ); - }, [user, data, toggle]); + }, [user, data, userPrivvy]); return ( <> @@ -91,10 +91,9 @@ const PrivilegeEditor = ({ const toAdd = availablePrivileges.filter(({ id }) => selectionAvailable.includes(id.toString()) ); - user.privileges = [...(user.privileges || []), ...toAdd]; - setToggle(!toggle); + setUserPrivvy([...(userPrivvy || []), ...toAdd]); setSelectionAvailable([]); - onChange(user.privileges); + onChange(userPrivvy); }} > >> @@ -104,12 +103,13 @@ const PrivilegeEditor = ({ disabled={!selectionExisting.length} onClick={() => { // Remove privileges - user.privileges = (user.privileges || []).filter( - ({ id }) => !selectionExisting.includes(id.toString()) - ); - onChange(user.privileges); + onChange(userPrivvy); setSelectionExisting([]); - setToggle(!toggle); + setUserPrivvy( + (userPrivvy || []).filter( + ({ id }) => !selectionExisting.includes(id.toString()) + ) + ); }} > << diff --git a/components/common/Button/Button.tsx b/components/common/Button/Button.tsx index 986c194..6d3c35a 100644 --- a/components/common/Button/Button.tsx +++ b/components/common/Button/Button.tsx @@ -7,7 +7,7 @@ export const Button = ({ children, ...props }: { - variant?: 'default' | 'primary' | 'secondary'; + variant?: 'default' | 'primary' | 'secondary' | 'link'; onClick: MouseEventHandler; children?: React.ReactNode; } & JSX.IntrinsicElements['button']) => { diff --git a/components/common/Form/Form.module.scss b/components/common/Form/Form.module.scss index 0d30c5c..45536b4 100644 --- a/components/common/Form/Form.module.scss +++ b/components/common/Form/Form.module.scss @@ -34,6 +34,12 @@ font-weight: 400; border: 1px solid #a4a4a4; box-shadow: inset 0 0 4px #0000001f; + + + span { + font-size: 0.875rem; + margin-top: 0.25rem; + color: rgb(100, 100, 100); + } } &:last-child { diff --git a/components/common/Header/Header.tsx b/components/common/Header/Header.tsx index fbfcf41..b67cd5f 100644 --- a/components/common/Header/Header.tsx +++ b/components/common/Header/Header.tsx @@ -21,11 +21,11 @@ const navItems = [ title: 'OAuth2', privileges: [['admin', 'admin:oauth2'], 'self:oauth2'], }, - { - path: '/privileges', - title: 'Privileges', - privileges: ['admin', 'admin:user:privilege'], - }, + // { + // path: '/privileges', + // title: 'Privileges', + // privileges: ['admin', 'admin:user:privilege'], + // }, { path: '/documents', title: 'Documents', diff --git a/pages/api/callback.ts b/pages/api/callback.ts index 069ccf4..a27e771 100644 --- a/pages/api/callback.ts +++ b/pages/api/callback.ts @@ -11,39 +11,37 @@ export default async function handler( req: NextApiRequest, res: NextApiResponse ) { - if (req.query.code) { - if (!req.query.state) { + if (!req.query.code || !req.query.state) { + return res.redirect('/'); + } + + const getAuth = await getAccessToken(req.query.code as string); + const cookies = new Cookies(req, res, { keys: COOKIE_KEYS }); + + if (getAuth) { + const decrypted = decrypt(req.query.state as string); + const stateToken = cookies.get('validation', { signed: true }); + const parsedState = JSON.parse(decrypted); + + if ( + parsedState.state !== stateToken || + parsedState.redirect_uri !== redirect + ) { return res.redirect('/'); } - const getAuth = await getAccessToken(req.query.code as string); - const cookies = new Cookies(req, res, { keys: COOKIE_KEYS }); + cookies.set('authorization', getAuth.access_token, { + expires: new Date(Date.now() + getAuth.expires_in * 1000), + secure: process.env.NODE_ENV === 'production', + signed: true, + }); - if (getAuth) { - const decrypted = decrypt(req.query.state as string); - const stateToken = cookies.get('validation', { signed: true }); - const parsedState = JSON.parse(decrypted); - - if ( - parsedState.state !== stateToken || - parsedState.redirect_uri !== redirect - ) { - return res.redirect('/'); - } - - cookies.set('authorization', getAuth.access_token, { - expires: new Date(Date.now() + getAuth.expires_in * 1000), - secure: process.env.NODE_ENV === 'production', - signed: true, - }); - - cookies.set('validation', undefined, { - expires: new Date(0), - secure: process.env.NODE_ENV === 'production', - signed: true, - }); - } - - res.redirect('/'); + cookies.set('validation', undefined, { + expires: new Date(0), + secure: process.env.NODE_ENV === 'production', + signed: true, + }); } + + res.redirect('/'); } diff --git a/styles/_focus.scss b/styles/_focus.scss index b71f001..2e7c68f 100644 --- a/styles/_focus.scss +++ b/styles/_focus.scss @@ -2,6 +2,7 @@ input, button, textarea, a { + transition: outline 0.15s linear; &:focus { outline: 4px solid #94cfff9c; }