diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts index 65f18d644..a3dfe27b5 100644 --- a/server/helpers/core-utils.ts +++ b/server/helpers/core-utils.ts @@ -12,6 +12,7 @@ import { isAbsolute, join } from 'path' import * as pem from 'pem' import * as rimraf from 'rimraf' import { URL } from 'url' +import { truncate } from 'lodash' function sanitizeUrl (url: string) { const urlObject = new URL(url) @@ -78,6 +79,22 @@ function buildPath (path: string) { return join(root(), path) } +// Consistent with .length, lodash truncate function is not +function peertubeTruncate (str: string, maxLength: number) { + const options = { + length: maxLength + } + const truncatedStr = truncate(str, options) + + // The truncated string is okay, we can return it + if (truncatedStr.length <= maxLength) return truncatedStr + + // Lodash takes into account all UTF characters, whereas String.prototype.length does not: some characters have a length of 2 + // We always use the .length so we need to truncate more if needed + options.length -= truncatedStr.length - maxLength + return truncate(str, options) +} + function promisify0 (func: (cb: (err: any, result: A) => void) => void): () => Promise { return function promisified (): Promise { return new Promise((resolve: (arg: A) => void, reject: (err: any) => void) => { @@ -145,6 +162,7 @@ export { sanitizeUrl, sanitizeHost, buildPath, + peertubeTruncate, promisify0, promisify1, diff --git a/server/helpers/custom-validators/activitypub/videos.ts b/server/helpers/custom-validators/activitypub/videos.ts index 10588423a..3af587a32 100644 --- a/server/helpers/custom-validators/activitypub/videos.ts +++ b/server/helpers/custom-validators/activitypub/videos.ts @@ -1,5 +1,6 @@ import * as validator from 'validator' -import { ACTIVITY_PUB } from '../../../initializers' +import { ACTIVITY_PUB, CONSTRAINTS_FIELDS } from '../../../initializers' +import { peertubeTruncate } from '../../core-utils' import { exists, isBooleanValid, isDateValid, isUUIDValid } from '../misc' import { isVideoAbuseReasonValid, @@ -56,6 +57,7 @@ function isVideoTorrentObjectValid (video: any) { isBooleanValid(video.commentsEnabled) && isDateValid(video.published) && isDateValid(video.updated) && + setTruncatedContent(video) && (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) && isRemoteVideoIconValid(video.icon) && setValidRemoteVideoUrls(video) && @@ -111,6 +113,14 @@ function setValidRemoteVideoUrls (video: any) { return true } +function setTruncatedContent (video: any) { + if (video.content) { + video.content = peertubeTruncate(video.content, CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max) + } + + return true +} + function isRemoteVideoUrlValid (url: any) { return url.type === 'Link' && ( diff --git a/server/lib/activitypub/process/process.ts b/server/lib/activitypub/process/process.ts index 10d8ba189..da91675ce 100644 --- a/server/lib/activitypub/process/process.ts +++ b/server/lib/activitypub/process/process.ts @@ -43,7 +43,7 @@ async function processActivities (activities: Activity[], signatureActor?: Actor try { await activityProcessor(activity, inboxActor) } catch (err) { - logger.warn('Cannot process activity %s.', activity.type, { error: err.stack }) + logger.warn('Cannot process activity %s.', activity.type, { err }) } } } diff --git a/server/models/video/video.ts b/server/models/video/video.ts index a28b5209b..7c56c65a6 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts @@ -1,5 +1,5 @@ import * as Bluebird from 'bluebird' -import { map, maxBy, truncate } from 'lodash' +import { map, maxBy } from 'lodash' import * as magnetUtil from 'magnet-uri' import * as parseTorrent from 'parse-torrent' import { join } from 'path' @@ -31,7 +31,10 @@ import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' import { Video, VideoDetails } from '../../../shared/models/videos' import { VideoFilter } from '../../../shared/models/videos/video-query.type' import { activityPubCollection } from '../../helpers/activitypub' -import { createTorrentPromise, renamePromise, statPromise, unlinkPromise, writeFilePromise } from '../../helpers/core-utils' +import { + createTorrentPromise, peertubeTruncate, renamePromise, statPromise, unlinkPromise, + writeFilePromise +} from '../../helpers/core-utils' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' import { isBooleanValid } from '../../helpers/custom-validators/misc' import { @@ -1191,19 +1194,7 @@ export class VideoModel extends Model { if (!this.description) return null const maxLength = CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max - - const options = { - length: maxLength - } - const truncatedDescription = truncate(this.description, options) - - // The truncated string is okay, we can return it - if (truncatedDescription.length <= maxLength) return truncatedDescription - - // Lodash takes into account all UTF characters, whereas String.prototype.length does not: some characters have a length of 2 - // We always use the .length so we need to truncate more if needed - options.length -= maxLength - truncatedDescription.length - return truncate(this.description, options) + return peertubeTruncate(this.description, maxLength) } optimizeOriginalVideofile = async function () {