mirror of https://github.com/Chocobozzz/PeerTube
Handle reports from mastodon
parent
4b1f1b810a
commit
0b5c385b45
|
@ -27,7 +27,7 @@ function isActorPublicKeyValid (publicKey: string) {
|
|||
validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY)
|
||||
}
|
||||
|
||||
const actorNameAlphabet = '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.]'
|
||||
const actorNameAlphabet = '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.:]'
|
||||
const actorNameRegExp = new RegExp(`^${actorNameAlphabet}+$`)
|
||||
function isActorPreferredUsernameValid (preferredUsername: string) {
|
||||
return exists(preferredUsername) && validator.matches(preferredUsername, actorNameRegExp)
|
||||
|
@ -46,19 +46,20 @@ function isActorObjectValid (actor: any) {
|
|||
return exists(actor) &&
|
||||
isActivityPubUrlValid(actor.id) &&
|
||||
isActorTypeValid(actor.type) &&
|
||||
isActivityPubUrlValid(actor.following) &&
|
||||
isActivityPubUrlValid(actor.followers) &&
|
||||
isActivityPubUrlValid(actor.inbox) &&
|
||||
isActivityPubUrlValid(actor.outbox) &&
|
||||
isActorPreferredUsernameValid(actor.preferredUsername) &&
|
||||
isActivityPubUrlValid(actor.url) &&
|
||||
isActorPublicKeyObjectValid(actor.publicKey) &&
|
||||
isActorEndpointsObjectValid(actor.endpoints) &&
|
||||
setValidAttributedTo(actor) &&
|
||||
|
||||
// If this is not an account, it should be attributed to an account
|
||||
(!actor.outbox || isActivityPubUrlValid(actor.outbox)) &&
|
||||
(!actor.following || isActivityPubUrlValid(actor.following)) &&
|
||||
(!actor.followers || isActivityPubUrlValid(actor.followers)) &&
|
||||
|
||||
setValidAttributedTo(actor) &&
|
||||
// If this is a group (a channel), it should be attributed to an account
|
||||
// In PeerTube we use this to attach a video channel to a specific account
|
||||
(actor.type === 'Person' || actor.attributedTo.length !== 0)
|
||||
(actor.type !== 'Group' || actor.attributedTo.length !== 0)
|
||||
}
|
||||
|
||||
function isActorFollowingCountValid (value: string) {
|
||||
|
|
|
@ -14,7 +14,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const LAST_MIGRATION_VERSION = 420
|
||||
const LAST_MIGRATION_VERSION = 425
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import * as Sequelize from 'sequelize'
|
||||
|
||||
async function up (utils: {
|
||||
transaction: Sequelize.Transaction,
|
||||
queryInterface: Sequelize.QueryInterface,
|
||||
sequelize: Sequelize.Sequelize,
|
||||
db: any
|
||||
}): Promise<void> {
|
||||
const data = {
|
||||
type: Sequelize.STRING,
|
||||
allowNull: true
|
||||
}
|
||||
|
||||
await utils.queryInterface.changeColumn('actor', 'outboxUrl', data)
|
||||
await utils.queryInterface.changeColumn('actor', 'followersUrl', data)
|
||||
await utils.queryInterface.changeColumn('actor', 'followingUrl', data)
|
||||
}
|
||||
|
||||
function down (options) {
|
||||
throw new Error('Not implemented.')
|
||||
}
|
||||
|
||||
export {
|
||||
up,
|
||||
down
|
||||
}
|
|
@ -26,28 +26,36 @@ export {
|
|||
async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: MActorSignature) {
|
||||
const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject)
|
||||
|
||||
logger.debug('Reporting remote abuse for video %s.', getAPId(flag.object))
|
||||
|
||||
const account = byActor.Account
|
||||
if (!account) throw new Error('Cannot create video abuse with the non account actor ' + byActor.url)
|
||||
|
||||
const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: flag.object })
|
||||
const objects = Array.isArray(flag.object) ? flag.object : [ flag.object ]
|
||||
|
||||
const videoAbuse = await sequelizeTypescript.transaction(async t => {
|
||||
const videoAbuseData = {
|
||||
reporterAccountId: account.id,
|
||||
reason: flag.content,
|
||||
videoId: video.id,
|
||||
state: VideoAbuseState.PENDING
|
||||
for (const object of objects) {
|
||||
try {
|
||||
logger.debug('Reporting remote abuse for video %s.', getAPId(object))
|
||||
|
||||
const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: object })
|
||||
|
||||
const videoAbuse = await sequelizeTypescript.transaction(async t => {
|
||||
const videoAbuseData = {
|
||||
reporterAccountId: account.id,
|
||||
reason: flag.content,
|
||||
videoId: video.id,
|
||||
state: VideoAbuseState.PENDING
|
||||
}
|
||||
|
||||
const videoAbuseInstance = await VideoAbuseModel.create(videoAbuseData, { transaction: t }) as MVideoAbuseVideo
|
||||
videoAbuseInstance.Video = video
|
||||
|
||||
logger.info('Remote abuse for video uuid %s created', flag.object)
|
||||
|
||||
return videoAbuseInstance
|
||||
})
|
||||
|
||||
Notifier.Instance.notifyOnNewVideoAbuse(videoAbuse)
|
||||
} catch (err) {
|
||||
logger.debug('Cannot process report of %s. (Maybe not a video abuse).', getAPId(object), { err })
|
||||
}
|
||||
|
||||
const videoAbuseInstance = await VideoAbuseModel.create(videoAbuseData, { transaction: t }) as MVideoAbuseVideo
|
||||
videoAbuseInstance.Video = video
|
||||
|
||||
logger.info('Remote abuse for video uuid %s created', flag.object)
|
||||
|
||||
return videoAbuseInstance
|
||||
})
|
||||
|
||||
Notifier.Instance.notifyOnNewVideoAbuse(videoAbuse)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,8 +175,8 @@ export class ActorModel extends Model<ActorModel> {
|
|||
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
|
||||
inboxUrl: string
|
||||
|
||||
@AllowNull(false)
|
||||
@Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url'))
|
||||
@AllowNull(true)
|
||||
@Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url', true))
|
||||
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
|
||||
outboxUrl: string
|
||||
|
||||
|
@ -185,13 +185,13 @@ export class ActorModel extends Model<ActorModel> {
|
|||
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
|
||||
sharedInboxUrl: string
|
||||
|
||||
@AllowNull(false)
|
||||
@Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url'))
|
||||
@AllowNull(true)
|
||||
@Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url', true))
|
||||
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
|
||||
followersUrl: string
|
||||
|
||||
@AllowNull(false)
|
||||
@Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url'))
|
||||
@AllowNull(true)
|
||||
@Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url', true))
|
||||
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
|
||||
followingUrl: string
|
||||
|
||||
|
|
|
@ -91,5 +91,5 @@ export interface ActivityDislike extends BaseActivity {
|
|||
export interface ActivityFlag extends BaseActivity {
|
||||
type: 'Flag',
|
||||
content: string,
|
||||
object: APObject
|
||||
object: APObject | APObject[]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export interface VideoAbuseObject {
|
||||
type: 'Flag',
|
||||
content: string
|
||||
object: string
|
||||
object: string | string[]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue