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

fix codeql 0217 #687

Merged
merged 5 commits into from
Feb 7, 2025
Merged
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
17 changes: 16 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@
"crypto-browserify": "3.12.0",
"date-fns": "2.14.0",
"electron-window-state": "5.0.3",
"escape-html": "^1.0.3",
"express": "4.21.2",
"he": "^1.2.0",
"i18next": "20.6.1",
"immutable": "4.0.0-rc.12",
"jsonschema": "1.2.4",
Expand Down Expand Up @@ -114,7 +116,9 @@
"@types/cors": "2.8.4",
"@types/enzyme": "3.10.8",
"@types/enzyme-adapter-react-16": "1.0.5",
"@types/escape-html": "^1.0.4",
"@types/express": "4.16.0",
"@types/he": "^1.2.3",
"@types/jest": "26.0.24",
"@types/jest-plugin-context": "2.9.0",
"@types/node": "18.16.15",
Expand Down Expand Up @@ -189,7 +193,9 @@
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": "ts-jest"
},
"transformIgnorePatterns": ["node_modules/(?!react-movable)"],
"transformIgnorePatterns": [
"node_modules/(?!react-movable)"
],
"testRegex": "(\\.|/)(spec)\\.(tsx?)$",
"moduleNameMapper": {
"^.+\\.(scss)$": "<rootDir>/scss-stub.js",
Expand Down
11 changes: 1 addition & 10 deletions src/app/api/services/localRepoService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,5 @@ export const fetchLocalFileNaive = async (path: string, fileName: string): Promi

export const fetchDirectories = async (path: string): Promise<string[]> => {
const response = await fetch(`${CONTROLLER_API_ENDPOINT}${GET_DIRECTORIES}/${encodeURIComponent(path || DEFAULT_DIRECTORY)}`);
if (!path) {
// only possible when platform is windows, expecting drives to be returned
const responseText = await response.text();
const drives = responseText.split(/\r\n/).map(drive => drive.trim()).filter(drive => drive !== '');
drives.shift(); // remove header
return drives.map(drive => `${drive}/`); // add trailing slash for drives
}
else {
return response.json();
}
return response.json();
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,11 @@ exports[`ListItemConfigurableRepo matches snapshot 1`] = `
>
modelRepository.types.configurable.infoText
</div>
<StyledMessageBar
messageBarType={5}
>
modelRepository.types.configurable.warning
</StyledMessageBar>
</div>
<StyledTextFieldBase
ariaLabel="modelRepository.types.configurable.textBoxLabel"
className="local-folder-textbox"
errorMessage=""
label="modelRepository.types.configurable.textBoxLabel"
onChange={[Function]}
prefix="https://"
readOnly={false}
value="test.com"
/>
</Fragment>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ exports[`ListItemLocalLabel matches snapshot when repo type equals Local 1`] = `
>
modelRepository.types.local.infoText
</div>
<StyledMessageBar
messageBarType={5}
>
modelRepository.types.local.warning
</StyledMessageBar>
</div>
</Fragment>
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,4 @@ describe('ListItemConfigurableRepo', () => {
);
expect(wrapper).toMatchSnapshot();
});

it('calls actions with expected params', () => {
const setDirtyFlag = jest.fn();
const setRepositoryLocationSettings = jest.fn();
const wrapper = shallow(
<ListItemConfigurableRepo
index={0}
item={{
repositoryLocationType: REPOSITORY_LOCATION_TYPE.Configurable,
value: 'test.com'
}}
formState={[{...getInitialModelRepositoryFormState(), repositoryLocationSettings: [{repositoryLocationType: REPOSITORY_LOCATION_TYPE.Configurable, value: 'old.com'}]},
{...getInitialModelRepositoryFormOps(), setDirtyFlag, setRepositoryLocationSettings}]}
/>
);
act(() => wrapper.find(TextField).props().onChange?.(undefined as any, 'test.com'));
expect(setDirtyFlag).toBeCalledWith(true);
expect(setRepositoryLocationSettings).toBeCalledWith([{repositoryLocationType: REPOSITORY_LOCATION_TYPE.Configurable, value: 'test.com'}])
});
});
42 changes: 4 additions & 38 deletions src/app/modelRepository/components/listItemConfigurableRepo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
**********************************************************/
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { TextField } from '@fluentui/react';
import { MessageBar, MessageBarType } from '@fluentui/react';
import { REPOSITORY_LOCATION_TYPE } from '../../constants/repositoryLocationTypes';
import { ResourceKeys } from '../../../localization/resourceKeys';
import { ModelRepositoryConfiguration } from '../../shared/modelRepository/state';
Expand All @@ -18,55 +18,21 @@ export interface ListItemConfigurableRepoProps{

export const ListItemConfigurableRepo: React.FC<ListItemConfigurableRepoProps> = ({index, item, formState}) => {
const { t } = useTranslation();
const [{repositoryLocationSettings, repositoryLocationSettingsErrors }, {setRepositoryLocationSettings, setDirtyFlag}] = formState;
const errorKey = repositoryLocationSettingsErrors[item.repositoryLocationType];

let initialConfigurableRepositoryPath = '';
if (item && item.repositoryLocationType === REPOSITORY_LOCATION_TYPE.Configurable) {
initialConfigurableRepositoryPath = item.value;
}
const [ currentConfigurableRepositoryPath, setCurrentConfigurableRepositoryPath ] = React.useState(initialConfigurableRepositoryPath);

React.useEffect(() => {
setCurrentConfigurableRepositoryPath(initialConfigurableRepositoryPath);
}, [initialConfigurableRepositoryPath]); // tslint:disable-line: align

const onChangeRepositoryLocationSettingValue = (value: string) => {
const updatedRepositoryLocationSettings = repositoryLocationSettings.map((setting, i) => {
if (i === index) {
const updatedSetting = {...setting};
updatedSetting.value = value;
return updatedSetting;
} else {
return setting;
}
});

setDirtyFlag(true);
setRepositoryLocationSettings(updatedRepositoryLocationSettings);
};

const repositoryEndpointChange = (event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => {
setCurrentConfigurableRepositoryPath(newValue);
onChangeRepositoryLocationSettingValue(newValue);
};

return(
<>
<div className="labelSection">
<div className="label">{t(ResourceKeys.modelRepository.types.configurable.label)}</div>
<div className="description">{t(ResourceKeys.modelRepository.types.configurable.infoText)}</div>
<MessageBar messageBarType={MessageBarType.warning}>
{t(ResourceKeys.modelRepository.types.configurable.warning)}
</MessageBar>
</div>
<TextField
className="local-folder-textbox"
label={t(ResourceKeys.modelRepository.types.configurable.textBoxLabel)}
ariaLabel={t(ResourceKeys.modelRepository.types.configurable.textBoxLabel)}
value={currentConfigurableRepositoryPath}
readOnly={false}
errorMessage={errorKey ? t(errorKey) : ''}
onChange={repositoryEndpointChange}
prefix="https://"
/>
</>
);
};
7 changes: 5 additions & 2 deletions src/app/modelRepository/components/listItemLocalLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
**********************************************************/
import * as React from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { Link } from '@fluentui/react';
import { Link, MessageBar, MessageBarType } from '@fluentui/react';
import { REPOSITORY_LOCATION_TYPE } from '../../constants/repositoryLocationTypes';
import { ResourceKeys } from '../../../localization/resourceKeys';

Expand All @@ -17,7 +17,10 @@ export const ListItemLocalLabel: React.FC<{repoType: REPOSITORY_LOCATION_TYPE}>
<div className="labelSection">
<div className="label">{t(ResourceKeys.modelRepository.types.local.label)}</div>
<div className="description">{t(ResourceKeys.modelRepository.types.local.infoText)}</div>
</div>}
<MessageBar messageBarType={MessageBarType.warning}>
{t(ResourceKeys.modelRepository.types.local.warning)}
</MessageBar>
</div>}
{repoType === REPOSITORY_LOCATION_TYPE.LocalDMR &&
<div className="labelSection">
<div className="label">{t(ResourceKeys.modelRepository.types.dmr.label)}</div>
Expand Down
6 changes: 3 additions & 3 deletions src/app/shared/components/monacoEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ export const MonacoEditorComponent: React.FC<MonacoEditorComponentProps> = ({
we will need to shift focus to another DOM element or window.
It is due to Electron's integration with Chromium and the way focus is managed between the webview and the main process.
We will create a dummy input, move the focus to it, and then clean it up. */
const dummyInput = document.createElement("input");
dummyInput.style.position = "absolute";
dummyInput.style.opacity = "0";
const dummyInput = document.createElement('input');
dummyInput.style.position = 'absolute';
dummyInput.style.opacity = '0';
document.body.appendChild(dummyInput);
dummyInput.focus();
setTimeout(() => document.body.removeChild(dummyInput), 0);
Expand Down
2 changes: 2 additions & 0 deletions src/localization/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -972,11 +972,13 @@
"configurable" : {
"label": "Configurable Repository",
"infoText": "Configure your own repository endpoint.",
"warning": "For security reasons, configurable repository is no longer supported.",
"textBoxLabel": "Repository endpoint"
},
"local": {
"label": "Local Folder",
"infoText": "Use your local folder as a model repository. The model definition files you wish to use should have a json extension. The first JSON file with an '@id' property matching the digital twin model identifier (DTMI) will be retrieved.",
"warning": "For security reasons, please select a subdirectory inside C:\\Users\\ (Windows) or /home/ (Linux/macOS).",
"textBoxLabel": "Selected folder",
"folderPicker": {
"command": {
Expand Down
2 changes: 2 additions & 0 deletions src/localization/resourceKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,7 @@ export class ResourceKeys {
infoText : "modelRepository.types.configurable.infoText",
label : "modelRepository.types.configurable.label",
textBoxLabel : "modelRepository.types.configurable.textBoxLabel",
warning : "modelRepository.types.configurable.warning",
},
dmr : {
infoText : "modelRepository.types.dmr.infoText",
Expand All @@ -857,6 +858,7 @@ export class ResourceKeys {
infoText : "modelRepository.types.local.infoText",
label : "modelRepository.types.local.label",
textBoxLabel : "modelRepository.types.local.textBoxLabel",
warning : "modelRepository.types.local.warning",
},
mandatory : "modelRepository.types.mandatory",
notAvailable : "modelRepository.types.notAvailable",
Expand Down
20 changes: 2 additions & 18 deletions src/server/serverBase.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ describe('serverBase', () => {
};

const mockResponse = () => {
const res = {status: undefined, json: undefined, send: undefined};
const res = {status: undefined, json: undefined, send: undefined} as any; // tslint:disable-line:no-any
res.status = jest.fn().mockReturnValue(res);
res.send = jest.fn().mockReturnValue(res);
res.json = jest.fn().mockReturnValue(res);
return res as any; // tslint:disable-line:no-any
return res as any; // tslint:disable-line:no-any
};

context('handleDataPlanePostRequest', () => {
Expand All @@ -37,20 +37,4 @@ describe('serverBase', () => {
expect(res.status).toHaveBeenCalledWith(400); // tslint:disable-line:no-magic-numbers
});
});

context('handleModelRepoPostRequest', () => {
it('returns 400 if body is not provided', async () => {
const req = mockRequest();
const res = mockResponse();
await ServerBase.handleModelRepoPostRequest(req, res);
expect(res.status).toHaveBeenCalledWith(400); // tslint:disable-line:no-magic-numbers
});

it('returns 500 if response is error', async () => {
const req = mockRequest('test');
const res = mockResponse();
await ServerBase.handleModelRepoPostRequest(req, res);
expect(res.status).toHaveBeenCalledWith(500); // tslint:disable-line:no-magic-numbers
});
});
});
29 changes: 5 additions & 24 deletions src/server/serverBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
import * as bodyParser from 'body-parser';
import * as cors from 'cors';
import fetch from 'node-fetch';
import * as he from 'he';
import { EventHubConsumerClient, Subscription, ReceivedEventData, earliestEventPosition } from '@azure/event-hubs';
import { generateDataPlaneRequestBody, generateDataPlaneResponse } from './dataPlaneHelper';
import { convertIotHubToEventHubsConnectionString } from './eventHubHelper';
import { fetchDirectories, fetchDrivesOnWindows, findMatchingFile, readFileFromLocal } from './utils';
import { fetchDirectories, findMatchingFile, readFileFromLocal, SAFE_ROOT } from './utils';

export const SERVER_ERROR = 500;
export const SUCCESS = 200;
Expand Down Expand Up @@ -51,7 +52,6 @@
app.post(dataPlaneUri, handleDataPlanePostRequest);
app.post(eventHubMonitorUri, handleEventHubMonitorPostRequest);
app.post(eventHubStopUri, handleEventHubStopPostRequest);
app.post(modelRepoUri, handleModelRepoPostRequest);
app.get(readFileUri, handleReadFileRequest);
app.get(readFileNaiveUri, handleReadFileNaiveRequest);
app.get(getDirectoriesUri, handleGetDirectoriesRequest);
Expand Down Expand Up @@ -134,14 +134,14 @@
try {
const dir = req.params.path;
if (dir === '$DEFAULT') {
fetchDrivesOnWindows(res);
res.status(SUCCESS).send([SAFE_ROOT]);
}
else {
fetchDirectories(dir, res);
}
}
catch (error) {
res.status(SERVER_ERROR).send(error?.message);

Check warning

Code scanning / CodeQL

Exception text reinterpreted as HTML Medium

Exception text
is reinterpreted as HTML without escaping meta-characters.
Exception text
is reinterpreted as HTML without escaping meta-characters.
Exception text
is reinterpreted as HTML without escaping meta-characters.
}
};

Expand Down Expand Up @@ -177,7 +177,7 @@
res.status(SUCCESS).send([]);
});
} catch (error) {
res.status(SERVER_ERROR).send(error);
res.status(SERVER_ERROR).send(he.encode(error.toString()));
}
};

Expand All @@ -193,26 +193,7 @@
res.status(SUCCESS).send();
});
} catch (error) {
res.status(SERVER_ERROR).send(error);
}
};

const modelRepoUri = '/api/ModelRepo';
export const handleModelRepoPostRequest = async (req: express.Request, res: express.Response) => {
if (!req.body) {
res.status(BAD_REQUEST).send();
}
const controllerRequest = req.body;
try {
const response = await fetch(controllerRequest.uri,
{
body: controllerRequest.body || null,
headers: controllerRequest.headers || null,
method: controllerRequest.method || 'GET',
});
res.status((response && response.status) || SUCCESS).send(await response.json() || {}); //tslint:disable-line
} catch (error) {
res.status(SERVER_ERROR).send(error);
res.status(SERVER_ERROR).send(he.encode(error.toString()));
}
};

Expand Down
Loading