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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user