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

[CVAT-UI] Better labels validation and fixed React warning #1727

Merged
merged 4 commits into from
Jun 16, 2020
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Shortcut to change color of an activated shape in new UI (Enter) (<https://github.com/opencv/cvat/pull/1683>)
- Shortcut to switch split mode (<https://github.com/opencv/cvat/pull/1683>)
- Built-in search for labels when create an object or change a label (<https://github.com/opencv/cvat/pull/1683>)
- Better validation of labels and attributes in raw viewer (<https://github.com/opencv/cvat/pull/1727>)

### Changed
- Removed information about e-mail from the basic user information (<https://github.com/opencv/cvat/pull/1627>)
Expand All @@ -32,6 +33,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Wrong rexex for account name validation (<https://github.com/opencv/cvat/pull/1667>)
- Wrong description on register view for the username field (<https://github.com/opencv/cvat/pull/1667>)
- Wrong resolution for resizing a shape (<https://github.com/opencv/cvat/pull/1667>)
- React warning because of not unique keys in labels viewer (<https://github.com/opencv/cvat/pull/1727>)


### Security
- SQL injection in Django `CVE-2020-9402` (<https://github.com/opencv/cvat/pull/1657>)
Expand Down
2 changes: 1 addition & 1 deletion cvat-ui/package-lock.json

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

2 changes: 1 addition & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.3.0",
"version": "1.3.1",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
53 changes: 53 additions & 0 deletions cvat-ui/src/components/labels-editor/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,59 @@ export interface Label {

let id = 0;

function validateParsedAttribute(attr: Attribute): void {
if (typeof (attr.name) !== 'string') {
throw new Error(`Type of attribute name must be a string. Got value ${attr.name}`);
}

if (!['number', 'undefined'].includes(typeof (attr.id))) {
throw new Error(`Attribute: "${attr.name}". `
+ `Type of attribute id must be a number or undefined. Got value ${attr.id}`);
}

if (!['checkbox', 'number', 'text', 'radio', 'select'].includes((attr.input_type || '').toLowerCase())) {
throw new Error(`Attribute: "${attr.name}". `
+ `Unknown input type: ${attr.input_type}`);
}

if (typeof (attr.mutable) !== 'boolean') {
throw new Error(`Attribute: "${attr.name}". `
+ `Mutable flag must be a boolean value. Got value ${attr.mutable}`);
}

if (!Array.isArray(attr.values)) {
throw new Error(`Attribute: "${attr.name}". `
+ `Attribute values must be an array. Got type ${typeof (attr.values)}`);
}

for (const value of attr.values) {
if (typeof (value) !== 'string') {
throw new Error(`Attribute: "${attr.name}". `
+ `Each value must be a string. Got value ${value}`);
}
}
}

export function validateParsedLabel(label: Label): void {
if (typeof (label.name) !== 'string') {
throw new Error(`Type of label name must be a string. Got value ${label.name}`);
}

if (!['number', 'undefined'].includes(typeof (label.id))) {
throw new Error(`Label "${label.name}". `
+ `Type of label id must be only a number or undefined. Got value ${label.id}`);
}

if (!Array.isArray(label.attributes)) {
throw new Error(`Label "${label.name}". `
+ `attributes must be an array. Got type ${typeof (label.attributes)}`);
}

for (const attr of label.attributes) {
validateParsedAttribute(attr);
}
}

export function idGenerator(): number {
return --id;
}
Expand Down
24 changes: 22 additions & 2 deletions cvat-ui/src/components/labels-editor/raw-viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import Form, { FormComponentProps } from 'antd/lib/form/Form';
import {
Label,
Attribute,
validateParsedLabel,
idGenerator,
} from './common';

type Props = FormComponentProps & {
Expand All @@ -22,7 +24,18 @@ type Props = FormComponentProps & {
class RawViewer extends React.PureComponent<Props> {
private validateLabels = (_: any, value: string, callback: any): void => {
try {
JSON.parse(value);
const parsed = JSON.parse(value);
if (!Array.isArray(parsed)) {
callback('Field is expected to be a JSON array');
}

for (const label of parsed) {
try {
validateParsedLabel(label);
} catch (error) {
callback(error.toString());
}
}
} catch (error) {
callback(error.toString());
}
Expand All @@ -39,7 +52,14 @@ class RawViewer extends React.PureComponent<Props> {
e.preventDefault();
form.validateFields((error, values): void => {
if (!error) {
onSubmit(JSON.parse(values.labels));
const parsed = JSON.parse(values.labels);
for (const label of parsed) {
label.id = label.id || idGenerator();
for (const attr of label.attributes) {
attr.id = attr.id || idGenerator();
}
}
onSubmit(parsed);
}
});
};
Expand Down