Skip to content

Commit

Permalink
Fix: use resources to validate paths (#2812)
Browse files Browse the repository at this point in the history
  • Loading branch information
thewahome authored Oct 6, 2023
1 parent e94cd6c commit f680ae9
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 10 deletions.
40 changes: 34 additions & 6 deletions src/app/services/context/validation-context/ValidationProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,49 @@
import { useState, ReactNode } from 'react';
import { ValidationContext } from './ValidationContext';
import { ReactNode, useEffect, useState } from 'react';

import { ValidationService } from '../../../../modules/validation/validation-service';
import { useAppSelector } from '../../../../store';
import { IResource } from '../../../../types/resources';
import { ValidationError } from '../../../utils/error-utils/ValidationError';
import { getResourcesSupportedByVersion } from '../../../utils/resources/resources-filter';
import { parseSampleUrl } from '../../../utils/sample-url-generation';
import { GRAPH_API_VERSIONS } from '../../graph-constants';
import { ValidationContext } from './ValidationContext';

interface ValidationProviderProps {
children: ReactNode;
}

export const ValidationProvider = ({ children }: ValidationProviderProps) => {
const [isValid, setIsValid] = useState(false);
const [query, setQuery] = useState('');
const [validationError, setValidationError] = useState('');
const { resources } = useAppSelector((state) => state);
const base = getResourcesSupportedByVersion(resources.data.children, GRAPH_API_VERSIONS[0]);

const [isValid, setIsValid] = useState<boolean>(false);
const [query, setQuery] = useState<string>('');
const [validationError, setValidationError] = useState<string>('');

const [versionedResources, setVersionedResources] =
useState<IResource[]>(resources.data.children.length > 0 ? base : []);
const [version, setVersion] = useState<string>(GRAPH_API_VERSIONS[0]);

const { queryVersion } = parseSampleUrl(query);

useEffect(() => {
if (resources.data.children.length > 0) {
setVersionedResources(getResourcesSupportedByVersion(resources.data.children, GRAPH_API_VERSIONS[0]));
}
}, [resources])

useEffect(() => {
if (version !== queryVersion && GRAPH_API_VERSIONS.includes(queryVersion) && resources.data.children.length > 0) {
setVersionedResources(getResourcesSupportedByVersion(resources.data.children, queryVersion));
setVersion(queryVersion);
}
}, [query]);

const validate = (queryToValidate: string) => {
setQuery(queryToValidate);
try {
ValidationService.validate(queryToValidate);
ValidationService.validate(queryToValidate, versionedResources);
setIsValid(true);
setValidationError('');
} catch (error: unknown) {
Expand Down
2 changes: 1 addition & 1 deletion src/modules/validation/ODataUrlABNF.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1075,4 +1075,4 @@ VCHAR = %x21-7E

;------------------------------------------------------------------------------
; End of odata-abnf-construction-rules
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
2 changes: 1 addition & 1 deletion src/modules/validation/abnf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ export class ValidatedUrl {
);
return result;
}
}
}
87 changes: 87 additions & 0 deletions src/modules/validation/validation-service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { ValidationError } from '../../app/utils/error-utils/ValidationError';
import { ValidationService } from './validation-service';

const validUrls = [
'https://graph.microsoft.com/v1.0/me/events',
'https://graph.microsoft.com/me',

// eslint-disable-next-line max-len
'https://graph.microsoft.com/v1.0/me/messages/AAMkAGVmMDEzMTM4LTZmYWUtNDdkNC1hMDZiLTU1OGY5OTZhYmY4OABGAAAAAAAiQ8W967B7TKBjgx9rVEURBwAiIsqMbYjsT5e-T7KzowPTAAAAAAEMAAAiIsqMbYjsT5e-T7KzowPTAAMCzwJpAAA=/',
'https://graph.microsoft.com/v1.0/security/alerts?$filter=Category eq \'ransomware\'&$top=5',
'https://graph.microsoft.com/v1.0/planner/plans/CONGZUWfGUu4msTgNP66e2UAAySi',
'https://graph.microsoft.com/v1.0/me/onenote/sections/1f7ff346-c174-45e5-af38-294e51d9969a/pages',
'https://graph.microsoft.com/v1.0/users(\'48d31887-5fad-4d73-a9f5-3c356e68a038\')',
'https://graph.microsoft.com/beta/me/drive/root/delta(token=\'1230919asd190410jlka\')',
// eslint-disable-next-line max-len
'https://graph.microsoft.com/beta/items/getActivitiesByInterval(startDateTime=\'2017-01-01\',endDateTime=\'2017-01-03\',interval=\'day\')',
'https://graph.microsoft.com/beta/me/drive/root:/FolderA/FileB.txt:/content',
'https://graph.microsoft.com/v1.0/me/drive/root:/Test Folder',
'https://graph.microsoft.com/v1.0/me/drive/root:/Encoded%20URL'
];

const invalidUrls = [
'https://graph.microsoft.com/me+you',
'https://graph.microsoft.com/v1.0/me/messages?$$select=id',
'https://graph.microsoft.com/v1.0/me/drive/root:/Encoded%',
'https://graph.microsoft.com/v1.0/me/drive/root:/Encoded%2'
];

/*
* These are valid URLs that fail without the trailing slash added to them.
*/

const forcedTrailingSlashes = [
'https://graph.microsoft.com/beta/directory/deleteditems/microsoft.graph.group/',
'https://graph.microsoft.com/v1.0/me/photo/$value/',
'https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/healthOverviews/$count/',
'https://graph.microsoft.com/v1.0/me/drive/root:/book1.xlsx/',
'https://graph.microsoft.com/v1.0/planner/tasks/oIx3zN98jEmVOM-4mUJzSGUANeje/',
'https://graph.microsoft.com/v1.0/users/[email protected]/',
'https://graph.microsoft.com/v1.0/me/extensions/com.contoso.roamingSettings/',
'https://graph.microsoft.com/v1.0/applications_v2/02bd9fd6-8f93-4758-87c3-1fb73740a315/',
'https://graph.microsoft.com/beta/groups/02bd9fd6-8f93-4758-87c3-1fb73740a315/owners/$ref/',
// eslint-disable-next-line max-len
'https://graph.microsoft.com/v1.0/teams/02bd9fd6-8f93-4758-87c3-1fb73740a315/channels/19:[email protected]/'

]
describe('Abnf parser should', () => {
validUrls.forEach((sample) => {
it(`validate url: ${sample} should pass`, () => {
let error = '';
try {
ValidationService.validate(sample, []);
} catch (err) {
const theError = err as ValidationError;
error = theError.message;
}
expect(error).toBeFalsy();
});
});

invalidUrls.forEach((sample) => {
it(`validate url: ${sample} should fail`, () => {
let error = '';
try {
ValidationService.validate(sample, []);
} catch (err) {
const theError = err as ValidationError;
error = theError.message;
}
expect(error).toBeTruthy();
});
});

forcedTrailingSlashes.forEach((sample) => {
it(`validate url: ${sample} should pass`, () => {
let error = '';
try {
ValidationService.validate(sample, []);
} catch (err) {
const theError = err as ValidationError;
error = theError.message;
}
expect(error).toBeFalsy();
});
});

});
29 changes: 27 additions & 2 deletions src/modules/validation/validation-service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
import { ValidationError } from '../../app/utils/error-utils/ValidationError';
import { hasPlaceHolders } from '../../app/utils/sample-url-generation';
import { sanitizeQueryUrl } from '../../app/utils/query-url-sanitization';
import { getMatchingResourceForUrl } from '../../app/utils/resources/resources-filter';
import { hasPlaceHolders, parseSampleUrl } from '../../app/utils/sample-url-generation';
import { translateMessage } from '../../app/utils/translate-messages';
import { IResource } from '../../types/resources';
import { ValidatedUrl } from './abnf';

class ValidationService {

private static getResourceValidationError(queryUrl: string, resources: IResource[]): string | null {
if (resources.length === 0) {
return null;
}
const sanitizedUrl = sanitizeQueryUrl(queryUrl);
const { requestUrl } = parseSampleUrl(sanitizedUrl);
const matchingResource = getMatchingResourceForUrl(requestUrl, resources)!;
if (!matchingResource) {
return 'No resource found matching this query';
}
return null;
}

private static getAbnfValidationError(queryUrl: string): string | null {
try {
const validator = new ValidatedUrl();
Expand All @@ -16,7 +32,7 @@ class ValidationService {
}
}

static validate(queryUrl: string): boolean {
static validate(queryUrl: string, resources: IResource[]): boolean {

if (!queryUrl) {
throw new ValidationError(
Expand All @@ -36,14 +52,23 @@ class ValidationService {
, 'warning');
}

const resourcesError = ValidationService.getResourceValidationError(queryUrl, resources);
if (resourcesError) {
throw new ValidationError(
`${translateMessage(resourcesError)}`,
'error');
}

const abnfError = ValidationService.getAbnfValidationError(queryUrl);
if (abnfError) {
throw new ValidationError(
`${translateMessage('Possible error found in URL near')}: ${abnfError}`,
'warning');
}

return true;
}
}

export { ValidationService };

0 comments on commit f680ae9

Please sign in to comment.