Skip to content

Commit cf5f089

Browse files
authored
Validate IoT device metadata upon submit (#160)
* Fix mqtt TS error due to package-lock bump * Validate IoT device metadata * Remove dead metadata validation code * Use translation keys for metadata
1 parent 46f106e commit cf5f089

File tree

4 files changed

+63
-0
lines changed

4 files changed

+63
-0
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
"@types/passport-local": "^1.0.33",
8888
"@types/supertest": "^2.0.10",
8989
"@types/validator": "^13.7.1",
90+
"@types/ws": "^8.5.2",
9091
"@typescript-eslint/eslint-plugin": "^4.10.0",
9192
"@typescript-eslint/parser": "^4.10.0",
9293
"eslint": "^7.15.0",

src/entities/dto/create-iot-device.dto.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { IoTDeviceType } from "@enum/device-type.enum";
1616

1717
import { CreateLoRaWANSettingsDto } from "./create-lorawan-settings.dto";
1818
import { CreateSigFoxSettingsDto } from "./create-sigfox-settings.dto";
19+
import { IsMetadataJson } from "@helpers/is-metadata-json.validator";
20+
import { nameof } from "@helpers/type-helper";
1921

2022
export class CreateIoTDeviceDto {
2123
@ApiProperty({ required: true })
@@ -60,6 +62,7 @@ export class CreateIoTDeviceDto {
6062

6163
@ApiProperty({ required: false })
6264
@IsOptional()
65+
@IsMetadataJson(nameof<CreateIoTDeviceDto>("metadata"))
6366
metadata?: JSON;
6467

6568
@ApiProperty({ required: false })

src/entities/enum/error-codes.enum.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ export enum ErrorCodes {
4242
ApplicationDoesNotExist = "MESSAGE.APPLICATION-DOES-NOT-EXIST",
4343
FailedToCreateOrUpdateIotDevice = "MESSAGE.FAILED-TO-CREATE-OR-UPDATE-IOT-DEVICE",
4444
DeviceModelDoesNotExist = "MESSAGE.DEVICE-MODEL-DOES-NOT-EXIST",
45+
InvalidKeyInKeyValuePair = "MESSAGE.INVALID-KEY-IN-KEY-VALUE-PAIR",
46+
InvalidValueInKeyValuePair = "MESSAGE.INVALID-VALUE-IN-KEY-VALUE-PAIR",
4547
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { ErrorCodes } from "@enum/error-codes.enum";
2+
import {
3+
registerDecorator,
4+
ValidationArguments,
5+
ValidationOptions,
6+
ValidatorConstraint,
7+
ValidatorConstraintInterface,
8+
} from "class-validator";
9+
10+
@ValidatorConstraint({ name: "isMetadataJson", async: false })
11+
export class IsMetadataJsonConstraint implements ValidatorConstraintInterface {
12+
private message = "";
13+
14+
public validate(value: string, args: ValidationArguments): boolean {
15+
const [propertyName] = args.constraints;
16+
this.message = `${propertyName} must be a valid list of metadata keys and values`;
17+
18+
if (typeof value !== "string") {
19+
return false;
20+
}
21+
try {
22+
const json = JSON.parse(value) as Record<string, string>;
23+
24+
for (const key of Object.keys(json)) {
25+
if (typeof key !== "string" || key.trim() === "") {
26+
this.message = ErrorCodes.InvalidKeyInKeyValuePair;
27+
return false;
28+
}
29+
if (typeof json[key] !== "string" || json[key].trim() === "") {
30+
this.message = ErrorCodes.InvalidValueInKeyValuePair;
31+
return false;
32+
}
33+
}
34+
} catch (error) {
35+
return false;
36+
}
37+
38+
return true;
39+
}
40+
41+
public defaultMessage(_args: ValidationArguments): string {
42+
return this.message;
43+
}
44+
}
45+
46+
export function IsMetadataJson(property: string, validationOptions?: ValidationOptions) {
47+
return function (object: unknown, propertyName: string): void {
48+
registerDecorator({
49+
name: "isMetadataJson",
50+
target: object.constructor,
51+
propertyName: propertyName,
52+
constraints: [property],
53+
options: validationOptions,
54+
validator: IsMetadataJsonConstraint,
55+
});
56+
};
57+
}

0 commit comments

Comments
 (0)