diff options
author | Chocobozzz <me@florianbigard.com> | 2018-03-19 10:23:42 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-03-19 10:32:51 +0100 |
commit | f47776e265a45859aaf8519d7de85c6f35fdf40a (patch) | |
tree | 73ff2ff46204b3e129202b10e17eba4c0ebbad6f /server | |
parent | f6aec1b0f64b18a767b458286e0d6a5f6549a573 (diff) | |
download | PeerTube-f47776e265a45859aaf8519d7de85c6f35fdf40a.tar.gz PeerTube-f47776e265a45859aaf8519d7de85c6f35fdf40a.tar.zst PeerTube-f47776e265a45859aaf8519d7de85c6f35fdf40a.zip |
Sanitize invalid actor description
Diffstat (limited to 'server')
-rw-r--r-- | server/helpers/custom-validators/activitypub/actor.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/actor.ts | 35 |
2 files changed, 29 insertions, 10 deletions
diff --git a/server/helpers/custom-validators/activitypub/actor.ts b/server/helpers/custom-validators/activitypub/actor.ts index df0edc30e..9908be4d3 100644 --- a/server/helpers/custom-validators/activitypub/actor.ts +++ b/server/helpers/custom-validators/activitypub/actor.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import * as validator from 'validator' | 1 | import * as validator from 'validator' |
2 | import { CONSTRAINTS_FIELDS } from '../../../initializers' | 2 | import { CONSTRAINTS_FIELDS } from '../../../initializers' |
3 | import { normalizeActor } from '../../../lib/activitypub' | ||
3 | import { exists } from '../misc' | 4 | import { exists } from '../misc' |
4 | import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc' | 5 | import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc' |
5 | 6 | ||
@@ -52,6 +53,7 @@ function isActorObjectValid (actor: any) { | |||
52 | isActorPublicKeyObjectValid(actor.publicKey) && | 53 | isActorPublicKeyObjectValid(actor.publicKey) && |
53 | isActorEndpointsObjectValid(actor.endpoints) && | 54 | isActorEndpointsObjectValid(actor.endpoints) && |
54 | setValidAttributedTo(actor) && | 55 | setValidAttributedTo(actor) && |
56 | |||
55 | // If this is not an account, it should be attributed to an account | 57 | // If this is not an account, it should be attributed to an account |
56 | // In PeerTube we use this to attach a video channel to a specific account | 58 | // In PeerTube we use this to attach a video channel to a specific account |
57 | (actor.type === 'Person' || actor.attributedTo.length !== 0) | 59 | (actor.type === 'Person' || actor.attributedTo.length !== 0) |
@@ -83,6 +85,8 @@ function isActorRejectActivityValid (activity: any) { | |||
83 | } | 85 | } |
84 | 86 | ||
85 | function isActorUpdateActivityValid (activity: any) { | 87 | function isActorUpdateActivityValid (activity: any) { |
88 | normalizeActor(activity.object) | ||
89 | |||
86 | return isBaseActivityValid(activity, 'Update') && | 90 | return isBaseActivityValid(activity, 'Update') && |
87 | isActorObjectValid(activity.object) | 91 | isActorObjectValid(activity.object) |
88 | } | 92 | } |
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 897acee85..b7114bbee 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -12,12 +12,13 @@ import { logger } from '../../helpers/logger' | |||
12 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' | 12 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' |
13 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' | 13 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' |
14 | import { getUrlFromWebfinger } from '../../helpers/webfinger' | 14 | import { getUrlFromWebfinger } from '../../helpers/webfinger' |
15 | import { IMAGE_MIMETYPE_EXT, CONFIG, sequelizeTypescript } from '../../initializers' | 15 | import { IMAGE_MIMETYPE_EXT, CONFIG, sequelizeTypescript, CONSTRAINTS_FIELDS } from '../../initializers' |
16 | import { AccountModel } from '../../models/account/account' | 16 | import { AccountModel } from '../../models/account/account' |
17 | import { ActorModel } from '../../models/activitypub/actor' | 17 | import { ActorModel } from '../../models/activitypub/actor' |
18 | import { AvatarModel } from '../../models/avatar/avatar' | 18 | import { AvatarModel } from '../../models/avatar/avatar' |
19 | import { ServerModel } from '../../models/server/server' | 19 | import { ServerModel } from '../../models/server/server' |
20 | import { VideoChannelModel } from '../../models/video/video-channel' | 20 | import { VideoChannelModel } from '../../models/video/video-channel' |
21 | import { truncate } from 'lodash' | ||
21 | 22 | ||
22 | // Set account keys, this could be long so process after the account creation and do not block the client | 23 | // Set account keys, this could be long so process after the account creation and do not block the client |
23 | function setAsyncActorKeys (actor: ActorModel) { | 24 | function setAsyncActorKeys (actor: ActorModel) { |
@@ -166,6 +167,24 @@ async function fetchAvatarIfExists (actorJSON: ActivityPubActor) { | |||
166 | return undefined | 167 | return undefined |
167 | } | 168 | } |
168 | 169 | ||
170 | function normalizeActor (actor: any) { | ||
171 | if (!actor) return | ||
172 | |||
173 | if (!actor.url || typeof actor.url !== 'string') { | ||
174 | actor.url = actor.url.href || actor.url.url | ||
175 | } | ||
176 | |||
177 | if (actor.summary && typeof actor.summary === 'string') { | ||
178 | actor.summary = truncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max }) | ||
179 | |||
180 | if (actor.summary.length < CONSTRAINTS_FIELDS.USERS.DESCRIPTION.min) { | ||
181 | actor.summary = null | ||
182 | } | ||
183 | } | ||
184 | |||
185 | return | ||
186 | } | ||
187 | |||
169 | export { | 188 | export { |
170 | getOrCreateActorAndServerAndModel, | 189 | getOrCreateActorAndServerAndModel, |
171 | buildActorInstance, | 190 | buildActorInstance, |
@@ -173,7 +192,8 @@ export { | |||
173 | fetchActorTotalItems, | 192 | fetchActorTotalItems, |
174 | fetchAvatarIfExists, | 193 | fetchAvatarIfExists, |
175 | updateActorInstance, | 194 | updateActorInstance, |
176 | updateActorAvatarInstance | 195 | updateActorAvatarInstance, |
196 | normalizeActor | ||
177 | } | 197 | } |
178 | 198 | ||
179 | // --------------------------------------------------------------------------- | 199 | // --------------------------------------------------------------------------- |
@@ -255,7 +275,9 @@ async function fetchRemoteActor (actorUrl: string): Promise<FetchRemoteActorResu | |||
255 | logger.info('Fetching remote actor %s.', actorUrl) | 275 | logger.info('Fetching remote actor %s.', actorUrl) |
256 | 276 | ||
257 | const requestResult = await doRequest(options) | 277 | const requestResult = await doRequest(options) |
258 | const actorJSON: ActivityPubActor = normalizeActor(requestResult.body) | 278 | normalizeActor(requestResult.body) |
279 | |||
280 | const actorJSON: ActivityPubActor = requestResult.body | ||
259 | 281 | ||
260 | if (isActorObjectValid(actorJSON) === false) { | 282 | if (isActorObjectValid(actorJSON) === false) { |
261 | logger.debug('Remote actor JSON is not valid.', { actorJSON: actorJSON }) | 283 | logger.debug('Remote actor JSON is not valid.', { actorJSON: actorJSON }) |
@@ -372,10 +394,3 @@ async function refreshActorIfNeeded (actor: ActorModel) { | |||
372 | return actor | 394 | return actor |
373 | } | 395 | } |
374 | } | 396 | } |
375 | |||
376 | function normalizeActor (actor: any) { | ||
377 | if (actor && actor.url && typeof actor.url === 'string') return actor | ||
378 | |||
379 | actor.url = actor.url.href || actor.url.url | ||
380 | return actor | ||
381 | } | ||