chore: Audit of all model column validations (#3757)

* chore: Updating all model validations before the white-hatters get to it ;)

* test

* Remove isUrl validation, thinking about it need to account for minio and other weird urls here
This commit is contained in:
Tom Moor
2022-07-09 17:04:40 +02:00
committed by GitHub
parent da4a10e877
commit 8bb88b8550
13 changed files with 100 additions and 19 deletions

View File

@@ -10,10 +10,16 @@ import {
import User from "./User";
import ParanoidModel from "./base/ParanoidModel";
import Fix from "./decorators/Fix";
import Length from "./validators/Length";
@Table({ tableName: "apiKeys", modelName: "apiKey" })
@Fix
class ApiKey extends ParanoidModel {
@Length({
min: 3,
max: 255,
msg: "Name must be between 3 and 255 characters",
})
@Column
name: string;

View File

@@ -8,6 +8,7 @@ import {
IsIn,
Table,
DataType,
IsNumeric,
} from "sequelize-typescript";
import { publicS3Endpoint, deleteFromS3, getFileByKey } from "@server/utils/s3";
import Document from "./Document";
@@ -15,19 +16,33 @@ import Team from "./Team";
import User from "./User";
import IdModel from "./base/IdModel";
import Fix from "./decorators/Fix";
import Length from "./validators/Length";
@Table({ tableName: "attachments", modelName: "attachment" })
@Fix
class Attachment extends IdModel {
@Length({
max: 4096,
msg: "key must be 4096 characters or less",
})
@Column
key: string;
@Length({
max: 4096,
msg: "url must be 4096 characters or less",
})
@Column
url: string;
@Length({
max: 255,
msg: "contentType must be 255 characters or less",
})
@Column
contentType: string;
@IsNumeric
@Column(DataType.BIGINT)
size: number;

View File

@@ -20,6 +20,7 @@ import { ValidationError } from "../errors";
import Team from "./Team";
import UserAuthentication from "./UserAuthentication";
import Fix from "./decorators/Fix";
import Length from "./validators/Length";
@Table({
tableName: "authentication_providers",
@@ -34,6 +35,10 @@ class AuthenticationProvider extends Model {
@Column(DataType.UUID)
id: string;
@Length({
max: 255,
msg: "name must be 255 characters or less",
})
@Column
name: string;
@@ -41,6 +46,10 @@ class AuthenticationProvider extends Model {
@Column
enabled: boolean;
@Length({
max: 255,
msg: "providerId must be 255 characters or less",
})
@Column
providerId: string;

View File

@@ -18,6 +18,7 @@ import {
ForeignKey,
Scopes,
DataType,
Length as SimpleLength,
} from "sequelize-typescript";
import isUUID from "validator/lib/isUUID";
import { MAX_TITLE_LENGTH } from "@shared/constants";
@@ -131,6 +132,11 @@ type Sort = CollectionSort;
@Table({ tableName: "collections", modelName: "collection" })
@Fix
class Collection extends ParanoidModel {
@SimpleLength({
min: 10,
max: 10,
msg: `urlId must be 10 characters`,
})
@Unique
@Column
urlId: string;
@@ -138,21 +144,21 @@ class Collection extends ParanoidModel {
@NotContainsUrl
@Length({
max: MAX_TITLE_LENGTH,
msg: `Collection name must be less than ${MAX_TITLE_LENGTH} characters`,
msg: `name must be ${MAX_TITLE_LENGTH} characters or less`,
})
@Column
name: string;
@Length({
max: 1000,
msg: `Collection description must be less than 1000 characters`,
msg: `description must be 1000 characters or less`,
})
@Column
description: string;
@Length({
max: 50,
msg: `Collection icon must be less than 50 characters`,
msg: `icon must be 50 characters or less`,
})
@Column
icon: string | null;
@@ -163,7 +169,7 @@ class Collection extends ParanoidModel {
@Length({
max: 50,
msg: `Collection index must be less than 50 characters`,
msg: `index must 50 characters or less`,
})
@Column
index: string | null;

View File

@@ -28,6 +28,9 @@ import {
AfterCreate,
Scopes,
DataType,
Length as SimpleLength,
IsNumeric,
IsDate,
} from "sequelize-typescript";
import MarkdownSerializer from "slate-md-serializer";
import isUUID from "validator/lib/isUUID";
@@ -183,13 +186,18 @@ export const DOCUMENT_VERSION = 2;
@Table({ tableName: "documents", modelName: "document" })
@Fix
class Document extends ParanoidModel {
@SimpleLength({
min: 10,
max: 10,
msg: `urlId must be 10 characters`,
})
@PrimaryKey
@Column
urlId: string;
@Length({
max: MAX_TITLE_LENGTH,
msg: `Document title must be less than ${MAX_TITLE_LENGTH} characters`,
msg: `Document title must be ${MAX_TITLE_LENGTH} characters or less`,
})
@Column
title: string;
@@ -197,6 +205,7 @@ class Document extends ParanoidModel {
@Column(DataType.ARRAY(DataType.STRING))
previousTitles: string[] = [];
@IsNumeric
@Column(DataType.SMALLINT)
version: number;
@@ -206,6 +215,10 @@ class Document extends ParanoidModel {
@Column
fullWidth: boolean;
@SimpleLength({
max: 255,
msg: `editorVersion must be 255 characters or less`,
})
@Column
editorVersion: string;
@@ -222,13 +235,16 @@ class Document extends ParanoidModel {
@Column
isWelcome: boolean;
@IsNumeric
@Default(0)
@Column(DataType.INTEGER)
revisionCount: number;
@IsDate
@Column
archivedAt: Date | null;
@IsDate
@Column
publishedAt: Date | null;

View File

@@ -9,6 +9,7 @@ import {
IsUUID,
Table,
DataType,
Length,
} from "sequelize-typescript";
import { globalEventQueue } from "../queues";
import { Event as TEvent } from "../types";
@@ -26,6 +27,10 @@ class Event extends IdModel {
@Column(DataType.UUID)
modelId: string;
@Length({
max: 255,
msg: "name must be 255 characters or less",
})
@Column
name: string;

View File

@@ -52,7 +52,7 @@ import NotContainsUrl from "./validators/NotContainsUrl";
})
@Fix
class Group extends ParanoidModel {
@Length({ min: 0, max: 255, msg: "Must be less than 255 characters" })
@Length({ min: 0, max: 255, msg: "name must be be 255 characters or less" })
@NotContainsUrl
@Column
name: string;

View File

@@ -34,7 +34,7 @@ class Integration extends IdModel {
service: string;
@Column(DataType.JSONB)
settings: any;
settings: Record<string, any>;
@Column(DataType.ARRAY(DataType.STRING))
events: string[];

View File

@@ -6,12 +6,16 @@ import {
DefaultScope,
ForeignKey,
Table,
IsNumeric,
Length as SimpleLength,
} from "sequelize-typescript";
import MarkdownSerializer from "slate-md-serializer";
import { MAX_TITLE_LENGTH } from "@shared/constants";
import Document from "./Document";
import User from "./User";
import IdModel from "./base/IdModel";
import Fix from "./decorators/Fix";
import Length from "./validators/Length";
const serializer = new MarkdownSerializer();
@@ -27,12 +31,21 @@ const serializer = new MarkdownSerializer();
@Table({ tableName: "revisions", modelName: "revision" })
@Fix
class Revision extends IdModel {
@IsNumeric
@Column(DataType.SMALLINT)
version: number;
@SimpleLength({
max: 255,
msg: `editorVersion must be 255 characters or less`,
})
@Column
editorVersion: string;
@Length({
max: MAX_TITLE_LENGTH,
msg: `Revision title must be ${MAX_TITLE_LENGTH} characters or less`,
})
@Column
title: string;

View File

@@ -15,6 +15,7 @@ import {
Scopes,
Is,
DataType,
IsUUID,
} from "sequelize-typescript";
import { getBaseDomain, RESERVED_SUBDOMAINS } from "@shared/utils/domains";
import env from "@server/env";
@@ -26,6 +27,7 @@ import TeamDomain from "./TeamDomain";
import User from "./User";
import ParanoidModel from "./base/ParanoidModel";
import Fix from "./decorators/Fix";
import IsFQDN from "./validators/IsFQDN";
import Length from "./validators/Length";
import NotContainsUrl from "./validators/NotContainsUrl";
@@ -48,12 +50,17 @@ const readFile = util.promisify(fs.readFile);
@Fix
class Team extends ParanoidModel {
@NotContainsUrl
@Length({ max: 255, msg: "name must be 255 characters or less" })
@Column
name: string;
@IsLowercase
@Unique
@Length({ min: 4, max: 32, msg: "Must be between 4 and 32 characters" })
@Length({
min: 4,
max: 32,
msg: "subdomain must be between 4 and 32 characters",
})
@Is({
args: [/^[a-z\d-]+$/, "i"],
msg: "Must be only alphanumeric and dashes",
@@ -66,13 +73,16 @@ class Team extends ParanoidModel {
subdomain: string | null;
@Unique
@Length({ max: 255, msg: "domain must be 255 characters or less" })
@IsFQDN
@Column
domain: string | null;
@IsUUID(4)
@Column(DataType.UUID)
defaultCollectionId: string | null;
@Length({ min: 0, max: 255, msg: "Must be less than 255 characters" })
@Length({ max: 255, msg: "avatarUrl must be 255 characters or less" })
@Column
avatarUrl: string | null;

View File

@@ -26,7 +26,7 @@ class TeamDomain extends IdModel {
msg: "You chose a restricted domain, please try another.",
})
@NotEmpty
@Length({ min: 0, max: 255, msg: "Must be less than 255 characters" })
@Length({ max: 255, msg: "name must be 255 characters or less" })
@IsFQDN
@Column
name: string;

View File

@@ -17,6 +17,7 @@ import {
DataType,
HasMany,
Scopes,
IsDate,
} from "sequelize-typescript";
import { languages } from "@shared/i18n";
import { stringToColor } from "@shared/utils/color";
@@ -84,17 +85,17 @@ export enum UserFlag {
@Fix
class User extends ParanoidModel {
@IsEmail
@Length({ max: 255, msg: "User email must be less than 255 characters" })
@Length({ max: 255, msg: "User email must be 255 characters or less" })
@Column
email: string | null;
@NotContainsUrl
@Length({ max: 255, msg: "User username must be less than 255 characters" })
@Length({ max: 255, msg: "User username must be 255 characters or less" })
@Column
username: string | null;
@NotContainsUrl
@Length({ max: 255, msg: "User name must be less than 255 characters" })
@Length({ max: 255, msg: "User name must be 255 characters or less" })
@Column
name: string;
@@ -116,6 +117,7 @@ class User extends ParanoidModel {
setEncryptedColumn(this, "jwtSecret", value);
}
@IsDate
@Column
lastActiveAt: Date | null;
@@ -123,6 +125,7 @@ class User extends ParanoidModel {
@Column
lastActiveIp: string | null;
@IsDate
@Column
lastSignedInAt: Date | null;
@@ -130,9 +133,11 @@ class User extends ParanoidModel {
@Column
lastSignedInIp: string | null;
@IsDate
@Column
lastSigninEmailSentAt: Date | null;
@IsDate
@Column
suspendedAt: Date | null;
@@ -144,11 +149,7 @@ class User extends ParanoidModel {
@Column
language: string;
@Length({
min: 0,
max: 1000,
msg: "avatarUrl must be less than 1000 characters",
})
@Length({ max: 1000, msg: "avatarUrl must be less than 1000 characters" })
@Column(DataType.STRING)
get avatarUrl() {
const original = this.getDataValue("avatarUrl");

View File

@@ -364,7 +364,7 @@ export async function buildAttachment(overrides: Partial<Attachment> = {}) {
count++;
return Attachment.create({
key: `uploads/key/to/file ${count}.png`,
url: `https://redirect.url.com/uploads/key/to/file ${count}.png`,
url: `https://redirect.url.com/uploads/key/to/file${count}.png`,
contentType: "image/png",
size: 100,
acl: "public-read",