diff --git a/server/models/Collection.ts b/server/models/Collection.ts index d1f6187adcfd..595f6d29f18c 100644 --- a/server/models/Collection.ts +++ b/server/models/Collection.ts @@ -33,6 +33,7 @@ import Team from "./Team"; import User from "./User"; import ParanoidModel from "./base/ParanoidModel"; import Fix from "./decorators/Fix"; +import NotContainsUrl from "./validators/NotContainsUrl"; // without this indirection, the app crashes on starup type Sort = CollectionSort; @@ -131,6 +132,7 @@ class Collection extends ParanoidModel { @Column urlId: string; + @NotContainsUrl @Column name: string; diff --git a/server/models/Document.ts b/server/models/Document.ts index 8c31e97dc724..a75f15ee686e 100644 --- a/server/models/Document.ts +++ b/server/models/Document.ts @@ -50,7 +50,7 @@ import User from "./User"; import View from "./View"; import ParanoidModel from "./base/ParanoidModel"; import Fix from "./decorators/Fix"; -import { Length } from "./decorators/Length"; +import Length from "./validators/Length"; export type SearchResponse = { results: { diff --git a/server/models/Group.ts b/server/models/Group.ts index 182b93f9db03..511bf6c31dab 100644 --- a/server/models/Group.ts +++ b/server/models/Group.ts @@ -16,6 +16,8 @@ import Team from "./Team"; import User from "./User"; import ParanoidModel from "./base/ParanoidModel"; import Fix from "./decorators/Fix"; +import Length from "./validators/Length"; +import NotContainsUrl from "./validators/NotContainsUrl"; @DefaultScope(() => ({ include: [ @@ -50,6 +52,8 @@ import Fix from "./decorators/Fix"; }) @Fix class Group extends ParanoidModel { + @Length({ min: 0, max: 255, msg: "Must be less than 255 characters" }) + @NotContainsUrl @Column name: string; diff --git a/server/models/Team.ts b/server/models/Team.ts index c79e9eb7603a..8c1cf252494a 100644 --- a/server/models/Team.ts +++ b/server/models/Team.ts @@ -14,7 +14,6 @@ import { BeforeSave, HasMany, Scopes, - Length, Is, DataType, } from "sequelize-typescript"; @@ -31,6 +30,8 @@ import TeamDomain from "./TeamDomain"; import User from "./User"; import ParanoidModel from "./base/ParanoidModel"; import Fix from "./decorators/Fix"; +import Length from "./validators/Length"; +import NotContainsUrl from "./validators/NotContainsUrl"; const readFile = util.promisify(fs.readFile); @@ -50,6 +51,7 @@ const readFile = util.promisify(fs.readFile); @Table({ tableName: "teams", modelName: "team" }) @Fix class Team extends ParanoidModel { + @NotContainsUrl @Column name: string; @@ -74,6 +76,7 @@ class Team extends ParanoidModel { @Column(DataType.UUID) defaultCollectionId: string | null; + @Length({ min: 0, max: 255, msg: "Must be less than 255 characters" }) @Column avatarUrl: string | null; diff --git a/server/models/TeamDomain.ts b/server/models/TeamDomain.ts index ed4358fc5ad5..2845c098cc85 100644 --- a/server/models/TeamDomain.ts +++ b/server/models/TeamDomain.ts @@ -11,6 +11,7 @@ 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: "team_domains", modelName: "team_domain" }) @Fix @@ -20,6 +21,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" }) @Column name: string; diff --git a/server/models/User.ts b/server/models/User.ts index 2cd1191c5a0b..be48cad87889 100644 --- a/server/models/User.ts +++ b/server/models/User.ts @@ -38,6 +38,8 @@ import Encrypted, { getEncryptedColumn, } from "./decorators/Encrypted"; import Fix from "./decorators/Fix"; +import Length from "./validators/Length"; +import NotContainsUrl from "./validators/NotContainsUrl"; /** * Flags that are available for setting on the user. @@ -86,12 +88,17 @@ export enum UserFlag { @Fix class User extends ParanoidModel { @IsEmail + @Length({ min: 0, max: 255, msg: "Must be less than 255 characters" }) @Column email: string | null; + @NotContainsUrl + @Length({ min: 0, max: 255, msg: "Must be less than 255 characters" }) @Column username: string | null; + @NotContainsUrl + @Length({ min: 0, max: 255, msg: "Must be less than 255 characters" }) @Column name: string; @@ -141,6 +148,7 @@ class User extends ParanoidModel { @Column language: string; + @Length({ min: 0, max: 255, msg: "Must be less than 255 characters" }) @Column(DataType.STRING) get avatarUrl() { const original = this.getDataValue("avatarUrl"); diff --git a/server/models/WebhookSubscription.ts b/server/models/WebhookSubscription.ts index d27271ee669a..f212dc49a90f 100644 --- a/server/models/WebhookSubscription.ts +++ b/server/models/WebhookSubscription.ts @@ -13,6 +13,7 @@ import Team from "./Team"; import User from "./User"; import ParanoidModel from "./base/ParanoidModel"; import Fix from "./decorators/Fix"; +import Length from "./validators/Length"; @Table({ tableName: "webhook_subscriptions", @@ -21,11 +22,13 @@ import Fix from "./decorators/Fix"; @Fix class WebhookSubscription extends ParanoidModel { @NotEmpty + @Length({ min: 0, max: 255, msg: "Must be less than 255 characters" }) @Column name: string; @IsUrl @NotEmpty + @Length({ min: 0, max: 255, msg: "Must be less than 255 characters" }) @Column url: string; diff --git a/server/models/decorators/Length.ts b/server/models/validators/Length.ts similarity index 72% rename from server/models/decorators/Length.ts rename to server/models/validators/Length.ts index a8efa14017d5..a4773ae0cb98 100644 --- a/server/models/decorators/Length.ts +++ b/server/models/validators/Length.ts @@ -2,10 +2,10 @@ import { size } from "lodash"; import { addAttributeOptions } from "sequelize-typescript"; /** - * A decorator that calculates size of the string based on lodash's size function. - * particularly useful for strings with unicode characters of variable lengths. + * A decorator that validates the size of a string based on lodash's size. + * function. Useful for strings with unicode characters of variable lengths. */ -export function Length({ +export default function Length({ msg, min, max, diff --git a/server/models/validators/NotContainsUrl.ts b/server/models/validators/NotContainsUrl.ts new file mode 100644 index 000000000000..63b9aad36e14 --- /dev/null +++ b/server/models/validators/NotContainsUrl.ts @@ -0,0 +1,16 @@ +import { addAttributeOptions } from "sequelize-typescript"; + +/** + * A decorator that validates that a string does not include something that + * looks like a URL. + */ +export default function NotContainsUrl(target: any, propertyName: string) { + return addAttributeOptions(target, propertyName, { + validate: { + not: { + args: /(www|file:|http:|https:)+[^\s]+[\w]/, + msg: "Must not contain a URL", + }, + }, + }); +}