diff --git a/src/api/endpoints/posts/create.js b/src/api/endpoints/posts/create.js index 57e95bd71..2f03ebd8e 100644 --- a/src/api/endpoints/posts/create.js +++ b/src/api/endpoints/posts/create.js @@ -4,8 +4,9 @@ * Module dependencies */ import * as mongo from 'mongodb'; +import validate from '../../validator'; import parse from '../../../common/text'; -import Post from '../../models/post'; +import { Post, isValidText } from '../../models/post'; import User from '../../models/user'; import Following from '../../models/following'; import DriveFile from '../../models/drive-file'; @@ -15,16 +16,15 @@ import notify from '../../common/notify'; import event from '../../event'; import config from '../../../conf'; -/** - * 最大文字数 - */ -const maxTextLength = 1000; - /** * 添付できるファイルの数 */ const maxMediaCount = 4; +function hasDuplicates(array) { + return (new Set(array)).size !== array.length; +} + /** * Create a post * @@ -37,30 +37,16 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => { // Get 'text' parameter - let text = params.text; - if (text !== undefined && text !== null) { - if (typeof text != 'string') { - return rej('text must be a string'); - } - text = text.trim(); - if (text.length == 0) { - text = null; - } else if (text.length > maxTextLength) { - return rej('too long text'); - } - } else { - text = null; - } + const [text, textErr] = validate(params.text, 'string', false, isValidText); + if (textErr) return rej('invalid text'); // Get 'media_ids' parameter - let medias = params.media_ids; - let files = []; - if (medias !== undefined && medias !== null) { - if (!Array.isArray(medias)) { - return rej('media_ids must be an array'); - } + const [mediaIds, mediaIdsErr] = validate(params.media_ids, 'array', false, x => !hasDuplicates(x)); + if (mediaIdsErr) return rej('invalid media_ids'); - if (medias.length > maxMediaCount) { + let files = []; + if (mediaIds !== null) { + if (mediaIds.length > maxMediaCount) { return rej('too many media'); } diff --git a/src/api/models/post.ts b/src/api/models/post.ts index ab2918725..baab63f99 100644 --- a/src/api/models/post.ts +++ b/src/api/models/post.ts @@ -1,3 +1,7 @@ import db from '../../db/mongodb'; export default db.get('posts') as any; // fuck type definition + +export function isValidText(text: string): boolean { + return text.length <= 1000 && text.trim() != ''; +} diff --git a/src/api/validator.ts b/src/api/validator.ts index 2562535c0..830786a18 100644 --- a/src/api/validator.ts +++ b/src/api/validator.ts @@ -2,7 +2,15 @@ import * as mongo from 'mongodb'; type Type = 'id' | 'string' | 'number' | 'boolean' | 'array' | 'object'; -export default (value: any, isRequired: boolean, type: Type, validator?: (any) => boolean): [T, string] => { +type Validator = ((x: T) => boolean | string) | ((x: T) => boolean | string)[]; + +function validate(value: any, type: 'id', isRequired?: boolean): [mongo.ObjectID, string]; +function validate(value: any, type: 'string', isRequired?: boolean, validator?: Validator): [string, string]; +function validate(value: any, type: 'number', isRequired?: boolean, validator?: Validator): [number, string]; +function validate(value: any, type: 'boolean', isRequired?: boolean): [boolean, string]; +function validate(value: any, type: 'array', isRequired?: boolean, validator?: Validator): [any[], string]; +function validate(value: any, type: 'object', isRequired?: boolean, validator?: Validator): [Object, string]; +function validate(value: any, type: Type, isRequired?: boolean, validator?: Validator): [T, string] { if (value === undefined || value === null) { if (isRequired) { return [null, 'is-required'] @@ -49,11 +57,21 @@ export default (value: any, isRequired: boolean, type: Type, validator?: (any break; } + if (type == 'id') value = new mongo.ObjectID(value); + if (validator) { - if (!validator(value)) { - return [null, 'invalid-format']; + const validators = Array.isArray(validator) ? validator : [validator]; + for (let i = 0; i < validators.length; i++) { + const result = validators[i](value); + if (result === false) { + return [null, 'invalid-format']; + } else if (typeof result == 'string') { + return [null, result]; + } } } return [value, null]; -}; +} + +export default validate;