aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-08-30 09:40:21 +0200
committerChocobozzz <me@florianbigard.com>2019-08-30 09:40:32 +0200
commit0b5c385b4529f3bef8f9523de3f9470ffa58f5f5 (patch)
treef8110a8fc9aaea1572d75749df15cfd57ce36914
parent4b1f1b810a50829be8d8998cdd4d296143e34f2e (diff)
downloadPeerTube-0b5c385b4529f3bef8f9523de3f9470ffa58f5f5.tar.gz
PeerTube-0b5c385b4529f3bef8f9523de3f9470ffa58f5f5.tar.zst
PeerTube-0b5c385b4529f3bef8f9523de3f9470ffa58f5f5.zip
Handle reports from mastodon
-rw-r--r--server/helpers/custom-validators/activitypub/actor.ts15
-rw-r--r--server/initializers/constants.ts2
-rw-r--r--server/initializers/migrations/0425-nullable-actor-fields.ts26
-rw-r--r--server/lib/activitypub/process/process-flag.ts40
-rw-r--r--server/models/activitypub/actor.ts12
-rw-r--r--shared/models/activitypub/activity.ts2
-rw-r--r--shared/models/activitypub/objects/video-abuse-object.ts2
7 files changed, 67 insertions, 32 deletions
diff --git a/server/helpers/custom-validators/activitypub/actor.ts b/server/helpers/custom-validators/activitypub/actor.ts
index deb331abb..55bc8cc96 100644
--- a/server/helpers/custom-validators/activitypub/actor.ts
+++ b/server/helpers/custom-validators/activitypub/actor.ts
@@ -27,7 +27,7 @@ function isActorPublicKeyValid (publicKey: string) {
27 validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY) 27 validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY)
28} 28}
29 29
30const actorNameAlphabet = '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.]' 30const actorNameAlphabet = '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.:]'
31const actorNameRegExp = new RegExp(`^${actorNameAlphabet}+$`) 31const actorNameRegExp = new RegExp(`^${actorNameAlphabet}+$`)
32function isActorPreferredUsernameValid (preferredUsername: string) { 32function isActorPreferredUsernameValid (preferredUsername: string) {
33 return exists(preferredUsername) && validator.matches(preferredUsername, actorNameRegExp) 33 return exists(preferredUsername) && validator.matches(preferredUsername, actorNameRegExp)
@@ -46,19 +46,20 @@ function isActorObjectValid (actor: any) {
46 return exists(actor) && 46 return exists(actor) &&
47 isActivityPubUrlValid(actor.id) && 47 isActivityPubUrlValid(actor.id) &&
48 isActorTypeValid(actor.type) && 48 isActorTypeValid(actor.type) &&
49 isActivityPubUrlValid(actor.following) &&
50 isActivityPubUrlValid(actor.followers) &&
51 isActivityPubUrlValid(actor.inbox) && 49 isActivityPubUrlValid(actor.inbox) &&
52 isActivityPubUrlValid(actor.outbox) &&
53 isActorPreferredUsernameValid(actor.preferredUsername) && 50 isActorPreferredUsernameValid(actor.preferredUsername) &&
54 isActivityPubUrlValid(actor.url) && 51 isActivityPubUrlValid(actor.url) &&
55 isActorPublicKeyObjectValid(actor.publicKey) && 52 isActorPublicKeyObjectValid(actor.publicKey) &&
56 isActorEndpointsObjectValid(actor.endpoints) && 53 isActorEndpointsObjectValid(actor.endpoints) &&
57 setValidAttributedTo(actor) &&
58 54
59 // If this is not an account, it should be attributed to an account 55 (!actor.outbox || isActivityPubUrlValid(actor.outbox)) &&
56 (!actor.following || isActivityPubUrlValid(actor.following)) &&
57 (!actor.followers || isActivityPubUrlValid(actor.followers)) &&
58
59 setValidAttributedTo(actor) &&
60 // If this is a group (a channel), it should be attributed to an account
60 // In PeerTube we use this to attach a video channel to a specific account 61 // In PeerTube we use this to attach a video channel to a specific account
61 (actor.type === 'Person' || actor.attributedTo.length !== 0) 62 (actor.type !== 'Group' || actor.attributedTo.length !== 0)
62} 63}
63 64
64function isActorFollowingCountValid (value: string) { 65function isActorFollowingCountValid (value: string) {
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 3dc178b11..908231a88 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -14,7 +14,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
14 14
15// --------------------------------------------------------------------------- 15// ---------------------------------------------------------------------------
16 16
17const LAST_MIGRATION_VERSION = 420 17const LAST_MIGRATION_VERSION = 425
18 18
19// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
20 20
diff --git a/server/initializers/migrations/0425-nullable-actor-fields.ts b/server/initializers/migrations/0425-nullable-actor-fields.ts
new file mode 100644
index 000000000..4e5f9e6ab
--- /dev/null
+++ b/server/initializers/migrations/0425-nullable-actor-fields.ts
@@ -0,0 +1,26 @@
1import * as Sequelize from 'sequelize'
2
3async function up (utils: {
4 transaction: Sequelize.Transaction,
5 queryInterface: Sequelize.QueryInterface,
6 sequelize: Sequelize.Sequelize,
7 db: any
8}): Promise<void> {
9 const data = {
10 type: Sequelize.STRING,
11 allowNull: true
12 }
13
14 await utils.queryInterface.changeColumn('actor', 'outboxUrl', data)
15 await utils.queryInterface.changeColumn('actor', 'followersUrl', data)
16 await utils.queryInterface.changeColumn('actor', 'followingUrl', data)
17}
18
19function down (options) {
20 throw new Error('Not implemented.')
21}
22
23export {
24 up,
25 down
26}
diff --git a/server/lib/activitypub/process/process-flag.ts b/server/lib/activitypub/process/process-flag.ts
index 422386540..e6e9084de 100644
--- a/server/lib/activitypub/process/process-flag.ts
+++ b/server/lib/activitypub/process/process-flag.ts
@@ -26,28 +26,36 @@ export {
26async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: MActorSignature) { 26async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: MActorSignature) {
27 const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject) 27 const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject)
28 28
29 logger.debug('Reporting remote abuse for video %s.', getAPId(flag.object))
30
31 const account = byActor.Account 29 const account = byActor.Account
32 if (!account) throw new Error('Cannot create video abuse with the non account actor ' + byActor.url) 30 if (!account) throw new Error('Cannot create video abuse with the non account actor ' + byActor.url)
33 31
34 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: flag.object }) 32 const objects = Array.isArray(flag.object) ? flag.object : [ flag.object ]
35 33
36 const videoAbuse = await sequelizeTypescript.transaction(async t => { 34 for (const object of objects) {
37 const videoAbuseData = { 35 try {
38 reporterAccountId: account.id, 36 logger.debug('Reporting remote abuse for video %s.', getAPId(object))
39 reason: flag.content, 37
40 videoId: video.id, 38 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: object })
41 state: VideoAbuseState.PENDING
42 }
43 39
44 const videoAbuseInstance = await VideoAbuseModel.create(videoAbuseData, { transaction: t }) as MVideoAbuseVideo 40 const videoAbuse = await sequelizeTypescript.transaction(async t => {
45 videoAbuseInstance.Video = video 41 const videoAbuseData = {
42 reporterAccountId: account.id,
43 reason: flag.content,
44 videoId: video.id,
45 state: VideoAbuseState.PENDING
46 }
46 47
47 logger.info('Remote abuse for video uuid %s created', flag.object) 48 const videoAbuseInstance = await VideoAbuseModel.create(videoAbuseData, { transaction: t }) as MVideoAbuseVideo
49 videoAbuseInstance.Video = video
48 50
49 return videoAbuseInstance 51 logger.info('Remote abuse for video uuid %s created', flag.object)
50 })
51 52
52 Notifier.Instance.notifyOnNewVideoAbuse(videoAbuse) 53 return videoAbuseInstance
54 })
55
56 Notifier.Instance.notifyOnNewVideoAbuse(videoAbuse)
57 } catch (err) {
58 logger.debug('Cannot process report of %s. (Maybe not a video abuse).', getAPId(object), { err })
59 }
60 }
53} 61}
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts
index fb4327e4f..67a1b5bc1 100644
--- a/server/models/activitypub/actor.ts
+++ b/server/models/activitypub/actor.ts
@@ -175,8 +175,8 @@ export class ActorModel extends Model<ActorModel> {
175 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) 175 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
176 inboxUrl: string 176 inboxUrl: string
177 177
178 @AllowNull(false) 178 @AllowNull(true)
179 @Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url')) 179 @Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url', true))
180 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) 180 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
181 outboxUrl: string 181 outboxUrl: string
182 182
@@ -185,13 +185,13 @@ export class ActorModel extends Model<ActorModel> {
185 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) 185 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
186 sharedInboxUrl: string 186 sharedInboxUrl: string
187 187
188 @AllowNull(false) 188 @AllowNull(true)
189 @Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url')) 189 @Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url', true))
190 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) 190 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
191 followersUrl: string 191 followersUrl: string
192 192
193 @AllowNull(false) 193 @AllowNull(true)
194 @Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url')) 194 @Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url', true))
195 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) 195 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
196 followingUrl: string 196 followingUrl: string
197 197
diff --git a/shared/models/activitypub/activity.ts b/shared/models/activitypub/activity.ts
index 95801190d..492b672c7 100644
--- a/shared/models/activitypub/activity.ts
+++ b/shared/models/activitypub/activity.ts
@@ -91,5 +91,5 @@ export interface ActivityDislike extends BaseActivity {
91export interface ActivityFlag extends BaseActivity { 91export interface ActivityFlag extends BaseActivity {
92 type: 'Flag', 92 type: 'Flag',
93 content: string, 93 content: string,
94 object: APObject 94 object: APObject | APObject[]
95} 95}
diff --git a/shared/models/activitypub/objects/video-abuse-object.ts b/shared/models/activitypub/objects/video-abuse-object.ts
index 40e7abd57..5f1264a76 100644
--- a/shared/models/activitypub/objects/video-abuse-object.ts
+++ b/shared/models/activitypub/objects/video-abuse-object.ts
@@ -1,5 +1,5 @@
1export interface VideoAbuseObject { 1export interface VideoAbuseObject {
2 type: 'Flag', 2 type: 'Flag',
3 content: string 3 content: string
4 object: string 4 object: string | string[]
5} 5}