Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redirecting to Restricted in case of unauthorized access to a VC #6525

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,338 changes: 2,584 additions & 754 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/yup": "^0.29.11",
"@vitejs/plugin-react": "^4.0.4",
"@xstate/graph": "^1.3.0",
"@xstate/react": "^1.5.1",
"apollo-upload-client": "^17.0.0",
Expand Down Expand Up @@ -162,6 +161,7 @@
"@types/react-mentions": "^4.1.8",
"@types/socket.io-client": "^3.0.0",
"@types/uuid": "^8.3.1",
"@vitejs/plugin-react": "^4.3.1",
"@vitest/browser": "^0.34.2",
"@vitest/coverage-istanbul": "^0.34.3",
"coveralls": "^3.1.1",
Expand All @@ -173,7 +173,8 @@
"prettier": "^2.5.1",
"sass": "^1.52.1",
"source-map-explorer": "^2.5.3",
"vite-plugin-svgr": "^3.2.0",
"vite": "^5.3.2",
"vite-plugin-svgr": "^4.2.0",
"vite-tsconfig-paths": "^4.2.0",
"vitest": "^0.34.2",
"webdriverio": "^8.15.4",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { ComponentType, FC } from 'react';
import linkedInTheme from '../AuthProviders/LinkedInTheme';
import { ReactComponent as LinkedInIcon } from '../AuthProviders/LinkedIn.svg';
import LinkedInIcon from '../AuthProviders/LinkedIn.svg?react';
import microsoftTheme from '../AuthProviders/MicrosoftTheme';
import { ReactComponent as MicrosoftIcon } from '../AuthProviders/Microsoft.svg';
import MicrosoftIcon from '../AuthProviders/Microsoft.svg?react';
import TranslationKey from '../../../../i18n/utils/TranslationKey';
import ButtonStyling from '../AuthProviders/ButtonStyling';
import { UiNodeInput } from './UiNodeTypes';
Expand Down
49 changes: 49 additions & 0 deletions src/core/routing/useRestrictedRedirect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { ApolloError } from '@apollo/client';
import { AuthorizationPrivilege } from '../apollo/generated/graphql-schema';
import { useLocation, useNavigate } from 'react-router-dom';
import { useEffect } from 'react';
import { isApolloForbiddenError } from '../apollo/hooks/useApolloErrorHandler';
import { NavigateOptions } from 'react-router/lib/hooks';

interface RestrictedRedirectQueryResponse<Data extends {}> {
data?: Data;
error?: ApolloError;
}

interface PrivilegesReader<Data> {
(data: Data): AuthorizationPrivilege[] | undefined;
}

interface RestrictedRedirectOptions extends NavigateOptions {
requiredPrivilege?: AuthorizationPrivilege;
}

const DEFAULT_NAVIGATE_OPTIONS: NavigateOptions = {
replace: true,
};

const useRestrictedRedirect = <Data extends {}>(
{ data, error }: RestrictedRedirectQueryResponse<Data>,
readPrivileges: PrivilegesReader<Data>,
{
requiredPrivilege = AuthorizationPrivilege.Read,
...navigateOptions
}: RestrictedRedirectOptions = DEFAULT_NAVIGATE_OPTIONS
) => {
const { pathname } = useLocation();
const navigate = useNavigate();

const redirectUrl = `/restricted?origin=${encodeURI(pathname)}`;

useEffect(() => {
if (error && isApolloForbiddenError(error)) {
navigate(redirectUrl, navigateOptions);
}

if (data && !readPrivileges(data)?.includes(requiredPrivilege)) {
navigate(redirectUrl, navigateOptions);
}
}, [data, error]);
};

export default useRestrictedRedirect;
2 changes: 1 addition & 1 deletion src/core/ui/content/ExpandContent/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { ReactComponent as ExpandContentIcon } from './ExpandContentIcon.svg';
import ExpandContentIcon from './ExpandContentIcon.svg?react';

export { ExpandContentIcon };
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SvgIcon, SvgIconProps } from '@mui/material';

import { ReactComponent as InnovationFlowIconSvg } from './InnovationFlowIcon.svg';
import InnovationFlowIconSvg from './InnovationFlowIcon.svg?react';

const InnovationFlowIcon = (props: SvgIconProps) => {
return <SvgIcon component={InnovationFlowIconSvg} inheritViewBox {...props} />;
Expand Down
2 changes: 1 addition & 1 deletion src/domain/collaboration/callout/icon/CalloutIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SvgIcon, SvgIconProps } from '@mui/material';

import { ReactComponent as CalloutIconIconSvg } from './CalloutIcon.svg';
import CalloutIconIconSvg from './CalloutIcon.svg?react';

const CalloutIcon = (props: SvgIconProps) => {
return <SvgIcon component={CalloutIconIconSvg} inheritViewBox {...props} />;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
query VirtualContributor ($id: UUID_NAMEID!) {
virtualContributor (ID: $id) {
query VirtualContributor($id: UUID_NAMEID!) {
virtualContributor(ID: $id) {
id
nameID
authorization {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import VCPageBanner from './VCPageBanner';
import { useVirtualContributorQuery } from '../../../../core/apollo/generated/apollo-hooks';
import { SettingsSection, VCProfileTabs } from '../../../platform/admin/layout/EntitySettingsLayout/constants';
import EntitySettingsLayout from '../../../platform/admin/layout/EntitySettingsLayout/EntitySettingsLayout';
import useRestrictedRedirect from '../../../../core/routing/useRestrictedRedirect';
import { AuthorizationPrivilege } from '../../../../core/apollo/generated/graphql-schema';

interface VCPageLayoutProps {
currentTab: SettingsSection;
Expand All @@ -19,10 +21,10 @@ const tabs = [SettingsSection.MyProfile, SettingsSection.Membership, SettingsSec
return VCProfileTabs.find(tab => tab.section === section)!;
});

const VCPageLayout = ({ ...props }: PropsWithChildren<VCPageLayoutProps>) => {
const VCSettingsPageLayout = ({ ...props }: PropsWithChildren<VCPageLayoutProps>) => {
const { vcNameId = '' } = useUrlParams();

const { data, loading } = useVirtualContributorQuery({
const { data, loading, error } = useVirtualContributorQuery({
variables: {
id: vcNameId,
},
Expand All @@ -35,6 +37,10 @@ const VCPageLayout = ({ ...props }: PropsWithChildren<VCPageLayoutProps>) => {
userNameId: data?.virtualContributor.nameID || '',
};

useRestrictedRedirect({ data, error }, data => data.virtualContributor.authorization?.myPrivileges, {
requiredPrivilege: AuthorizationPrivilege.Update,
});

return (
<EntitySettingsLayout
breadcrumbs={
Expand All @@ -61,4 +67,4 @@ const VCPageLayout = ({ ...props }: PropsWithChildren<VCPageLayoutProps>) => {
);
};

export default VCPageLayout;
export default VCSettingsPageLayout;
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import {
} from '../../../../core/apollo/generated/apollo-hooks';
import { useTranslation } from 'react-i18next';
import { AiPersonaBodyOfKnowledgeType } from '../../../../core/apollo/generated/graphql-schema';
import { isApolloNotFoundError } from '../../../../core/apollo/hooks/useApolloErrorHandler';
import useRestrictedRedirect from '../../../../core/routing/useRestrictedRedirect';

export const VCProfilePage = () => {
const { t } = useTranslation();

const { vcNameId = '' } = useUrlParams();

const { data, loading, error } = useVirtualContributorQuery({
Expand All @@ -32,12 +33,15 @@ export const VCProfilePage = () => {
skip: !data?.virtualContributor?.aiPersona?.bodyOfKnowledgeID || !isBoKSpace,
});

if (loading)
useRestrictedRedirect({ data, error }, data => data.virtualContributor.authorization?.myPrivileges);

if (loading) {
return (
<Loading text={t('components.loading.message', { blockName: t('pages.virtualContributorProfile.title') })} />
);
}

if (error) {
if (error && isApolloNotFoundError(error)) {
return (
<VCPageLayout>
<Error404 />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PageContentBlock from '../../../core/ui/content/PageContentBlock';
import { InnovationHubAttrs } from './InnovationHubAttrs';
import WrapperMarkdown from '../../../core/ui/markdown/WrapperMarkdown';
import { BlockTitle } from '../../../core/ui/typography';
import { ReactComponent as Logo } from '../../../main/ui/logo/logoSmall.svg';
import Logo from '../../../main/ui/logo/logoSmall.svg?react';
import { gutters } from '../../../core/ui/grid/utils';
import InnovationHubBanner from './InnovationHubBanner';
import PageContentBlockHeader from '../../../core/ui/content/PageContentBlockHeader';
Expand Down
2 changes: 1 addition & 1 deletion src/main/search/SearchView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { SEARCH_SPACE_URL_PARAM, SEARCH_TERMS_URL_PARAM } from './constants';
import PageContentBlockSeamless from '../../core/ui/content/PageContentBlockSeamless';
import SearchResultsScope from '../../core/ui/search/SearchResultsScope';
import SearchResultsScopeCard from '../../core/ui/search/SearchResultsScopeCard';
import { ReactComponent as AlkemioLogo } from '../ui/logo/logoSmall.svg';
import AlkemioLogo from '../ui/logo/logoSmall.svg?react';
import { SpaceIcon } from '../../domain/journey/space/icon/SpaceIcon';
import { findKey, groupBy, identity } from 'lodash';
import SearchResultPostChooser from './searchResults/SearchResultPostChooser';
Expand Down
2 changes: 1 addition & 1 deletion src/main/ui/breadcrumbs/BreadcrumbsRootItem.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactComponent as AlkemioLogo } from '../logo/logoSmall.svg';
import AlkemioLogo from '../logo/logoSmall.svg?react';
import { ROUTE_HOME } from '../../../domain/platform/routes/constants';
import useJourneyBreadcrumbsTopLevelItem from '../../../domain/journey/common/journeyBreadcrumbs/useJourneyBreadcrumbsTopLevelItem';
import { Expandable } from '../../../core/ui/navigation/Expandable';
Expand Down
2 changes: 1 addition & 1 deletion src/main/ui/layout/topBar/LogoComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { Box, BoxProps, styled, Link as MuiLink } from '@mui/material';
import { ReactComponent as LogoImage } from '../../logo/logoPreview.svg';
import LogoImage from '../../logo/logoPreview.svg?react';
import { env } from '../../../env';
import RouterLink from '../../../../core/ui/link/RouterLink';
import { ROUTE_HOME } from '../../../../domain/platform/routes/constants';
Expand Down
4 changes: 2 additions & 2 deletions src/main/ui/poweredBy/PoweredBy.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useTranslation } from 'react-i18next';
import { BlockSectionTitle } from '../../../core/ui/typography';
import { ReactComponent as LogoPreviewImage } from '../logo/logoPreview.svg';
import { ReactComponent as LogoImage } from '../logo/logo.svg';
import LogoPreviewImage from '../logo/logoPreview.svg?react';
import LogoImage from '../logo/logo.svg?react';
import { gutters } from '../../../core/ui/grid/utils';
import { Box, BoxProps } from '@mui/material';
import { useConfig } from '../../../domain/platform/config/useConfig';
Expand Down