1
0
Fork 0
mirror of https://github.com/Chocobozzz/PeerTube.git synced 2025-10-04 02:09:37 +02:00

Continue activitypub

This commit is contained in:
Chocobozzz 2017-11-10 14:34:45 +01:00
parent e4f97babf7
commit 0d0e8dd090
No known key found for this signature in database
GPG key ID: 583A612D890159BE
27 changed files with 1039 additions and 1086 deletions

View file

@ -0,0 +1,34 @@
import * as validator from 'validator'
import {
isVideoChannelCreateActivityValid,
isVideoTorrentAddActivityValid,
isVideoTorrentUpdateActivityValid,
isVideoChannelUpdateActivityValid
} from './videos'
function isRootActivityValid (activity: any) {
return Array.isArray(activity['@context']) &&
(
(activity.type === 'Collection' || activity.type === 'OrderedCollection') &&
validator.isInt(activity.totalItems, { min: 0 }) &&
Array.isArray(activity.items)
) ||
(
validator.isURL(activity.id) &&
validator.isURL(activity.actor)
)
}
function isActivityValid (activity: any) {
return isVideoTorrentAddActivityValid(activity) ||
isVideoChannelCreateActivityValid(activity) ||
isVideoTorrentUpdateActivityValid(activity) ||
isVideoChannelUpdateActivityValid(activity)
}
// ---------------------------------------------------------------------------
export {
isRootActivityValid,
isActivityValid
}

View file

@ -1,4 +1,5 @@
export * from './account'
export * from './activity'
export * from './signature'
export * from './misc'
export * from './videos'

View file

@ -12,6 +12,16 @@ function isActivityPubUrlValid (url: string) {
return exists(url) && validator.isURL(url, isURLOptions)
}
export {
isActivityPubUrlValid
function isBaseActivityValid (activity: any, type: string) {
return Array.isArray(activity['@context']) &&
activity.type === type &&
validator.isURL(activity.id) &&
validator.isURL(activity.actor) &&
Array.isArray(activity.to) &&
activity.to.every(t => validator.isURL(t))
}
export {
isActivityPubUrlValid,
isBaseActivityValid
}

View file

@ -1,184 +1,117 @@
import 'express-validator'
import { has, values } from 'lodash'
import * as validator from 'validator'
import {
REQUEST_ENDPOINTS,
REQUEST_ENDPOINT_ACTIONS,
REQUEST_VIDEO_EVENT_TYPES
ACTIVITY_PUB
} from '../../../initializers'
import { isArray, isDateValid, isUUIDValid } from '../misc'
import { isDateValid, isUUIDValid } from '../misc'
import {
isVideoThumbnailDataValid,
isVideoAbuseReasonValid,
isVideoAbuseReporterUsernameValid,
isVideoViewsValid,
isVideoLikesValid,
isVideoDislikesValid,
isVideoEventCountValid,
isRemoteVideoCategoryValid,
isRemoteVideoLicenceValid,
isRemoteVideoLanguageValid,
isVideoNSFWValid,
isVideoTruncatedDescriptionValid,
isVideoDurationValid,
isVideoFileInfoHashValid,
isVideoNameValid,
isVideoTagsValid,
isVideoFileExtnameValid,
isVideoFileResolutionValid
isVideoTagValid
} from '../videos'
import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels'
import { isVideoAuthorNameValid } from '../video-authors'
import { isBaseActivityValid } from './misc'
const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS]
const checkers: { [ id: string ]: (obj: any) => boolean } = {}
checkers[ENDPOINT_ACTIONS.ADD_VIDEO] = checkAddVideo
checkers[ENDPOINT_ACTIONS.UPDATE_VIDEO] = checkUpdateVideo
checkers[ENDPOINT_ACTIONS.REMOVE_VIDEO] = checkRemoveVideo
checkers[ENDPOINT_ACTIONS.REPORT_ABUSE] = checkReportVideo
checkers[ENDPOINT_ACTIONS.ADD_CHANNEL] = checkAddVideoChannel
checkers[ENDPOINT_ACTIONS.UPDATE_CHANNEL] = checkUpdateVideoChannel
checkers[ENDPOINT_ACTIONS.REMOVE_CHANNEL] = checkRemoveVideoChannel
checkers[ENDPOINT_ACTIONS.ADD_AUTHOR] = checkAddAuthor
checkers[ENDPOINT_ACTIONS.REMOVE_AUTHOR] = checkRemoveAuthor
function removeBadRequestVideos (requests: any[]) {
for (let i = requests.length - 1; i >= 0 ; i--) {
const request = requests[i]
const video = request.data
if (
!video ||
checkers[request.type] === undefined ||
checkers[request.type](video) === false
) {
requests.splice(i, 1)
}
}
function isVideoTorrentAddActivityValid (activity: any) {
return isBaseActivityValid(activity, 'Add') &&
isVideoTorrentObjectValid(activity.object)
}
function removeBadRequestVideosQadu (requests: any[]) {
for (let i = requests.length - 1; i >= 0 ; i--) {
const request = requests[i]
const video = request.data
if (
!video ||
(
isUUIDValid(video.uuid) &&
(has(video, 'views') === false || isVideoViewsValid(video.views)) &&
(has(video, 'likes') === false || isVideoLikesValid(video.likes)) &&
(has(video, 'dislikes') === false || isVideoDislikesValid(video.dislikes))
) === false
) {
requests.splice(i, 1)
}
}
function isVideoTorrentUpdateActivityValid (activity: any) {
return isBaseActivityValid(activity, 'Update') &&
isVideoTorrentObjectValid(activity.object)
}
function removeBadRequestVideosEvents (requests: any[]) {
for (let i = requests.length - 1; i >= 0 ; i--) {
const request = requests[i]
const eventData = request.data
function isVideoTorrentObjectValid (video: any) {
return video.type === 'Video' &&
isVideoNameValid(video.name) &&
isVideoDurationValid(video.duration) &&
isUUIDValid(video.uuid) &&
setValidRemoteTags(video) &&
isRemoteIdentifierValid(video.category) &&
isRemoteIdentifierValid(video.licence) &&
isRemoteIdentifierValid(video.language) &&
isVideoViewsValid(video.video) &&
isVideoNSFWValid(video.nsfw) &&
isDateValid(video.published) &&
isDateValid(video.updated) &&
isRemoteVideoContentValid(video.mediaType, video.content) &&
isRemoteVideoIconValid(video.icon) &&
setValidRemoteVideoUrls(video.url)
}
if (
!eventData ||
(
isUUIDValid(eventData.uuid) &&
values(REQUEST_VIDEO_EVENT_TYPES).indexOf(eventData.eventType) !== -1 &&
isVideoEventCountValid(eventData.count)
) === false
) {
requests.splice(i, 1)
}
}
function isVideoChannelCreateActivityValid (activity: any) {
return isBaseActivityValid(activity, 'Create') &&
isVideoChannelObjectValid(activity.object)
}
function isVideoChannelUpdateActivityValid (activity: any) {
return isBaseActivityValid(activity, 'Update') &&
isVideoChannelObjectValid(activity.object)
}
function isVideoChannelObjectValid (videoChannel: any) {
return videoChannel.type === 'VideoChannel' &&
isVideoChannelNameValid(videoChannel.name) &&
isVideoChannelDescriptionValid(videoChannel.description) &&
isUUIDValid(videoChannel.uuid)
}
// ---------------------------------------------------------------------------
export {
removeBadRequestVideos,
removeBadRequestVideosQadu,
removeBadRequestVideosEvents
isVideoTorrentAddActivityValid,
isVideoChannelCreateActivityValid,
isVideoTorrentUpdateActivityValid,
isVideoChannelUpdateActivityValid
}
// ---------------------------------------------------------------------------
function isCommonVideoAttributesValid (video: any) {
return isDateValid(video.createdAt) &&
isDateValid(video.updatedAt) &&
isRemoteVideoCategoryValid(video.category) &&
isRemoteVideoLicenceValid(video.licence) &&
isRemoteVideoLanguageValid(video.language) &&
isVideoNSFWValid(video.nsfw) &&
isVideoTruncatedDescriptionValid(video.truncatedDescription) &&
isVideoDurationValid(video.duration) &&
isVideoNameValid(video.name) &&
isVideoTagsValid(video.tags) &&
isUUIDValid(video.uuid) &&
isVideoViewsValid(video.views) &&
isVideoLikesValid(video.likes) &&
isVideoDislikesValid(video.dislikes) &&
isArray(video.files) &&
video.files.every(videoFile => {
if (!videoFile) return false
function setValidRemoteTags (video: any) {
if (Array.isArray(video.tag) === false) return false
return (
isVideoFileInfoHashValid(videoFile.infoHash) &&
isVideoFileExtnameValid(videoFile.extname) &&
isVideoFileResolutionValid(videoFile.resolution)
)
})
const newTag = video.tag.filter(t => {
return t.type === 'Hashtag' &&
isVideoTagValid(t.name)
})
video.tag = newTag
return true
}
function checkAddVideo (video: any) {
return isCommonVideoAttributesValid(video) &&
isUUIDValid(video.channelUUID) &&
isVideoThumbnailDataValid(video.thumbnailData)
function isRemoteIdentifierValid (data: any) {
return validator.isInt(data.identifier, { min: 0 })
}
function checkUpdateVideo (video: any) {
return isCommonVideoAttributesValid(video)
function isRemoteVideoContentValid (mediaType: string, content: string) {
return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content)
}
function checkRemoveVideo (video: any) {
return isUUIDValid(video.uuid)
function isRemoteVideoIconValid (icon: any) {
return icon.type === 'Image' &&
validator.isURL(icon.url) &&
icon.mediaType === 'image/jpeg' &&
validator.isInt(icon.width, { min: 0 }) &&
validator.isInt(icon.height, { min: 0 })
}
function checkReportVideo (abuse: any) {
return isUUIDValid(abuse.videoUUID) &&
isVideoAbuseReasonValid(abuse.reportReason) &&
isVideoAbuseReporterUsernameValid(abuse.reporterUsername)
function setValidRemoteVideoUrls (video: any) {
if (Array.isArray(video.url) === false) return false
const newUrl = video.url.filter(u => isRemoteVideoUrlValid(u))
video.url = newUrl
return true
}
function checkAddVideoChannel (videoChannel: any) {
return isUUIDValid(videoChannel.uuid) &&
isVideoChannelNameValid(videoChannel.name) &&
isVideoChannelDescriptionValid(videoChannel.description) &&
isDateValid(videoChannel.createdAt) &&
isDateValid(videoChannel.updatedAt) &&
isUUIDValid(videoChannel.ownerUUID)
}
function checkUpdateVideoChannel (videoChannel: any) {
return isUUIDValid(videoChannel.uuid) &&
isVideoChannelNameValid(videoChannel.name) &&
isVideoChannelDescriptionValid(videoChannel.description) &&
isDateValid(videoChannel.createdAt) &&
isDateValid(videoChannel.updatedAt) &&
isUUIDValid(videoChannel.ownerUUID)
}
function checkRemoveVideoChannel (videoChannel: any) {
return isUUIDValid(videoChannel.uuid)
}
function checkAddAuthor (author: any) {
return isUUIDValid(author.uuid) &&
isVideoAuthorNameValid(author.name)
}
function checkRemoveAuthor (author: any) {
return isUUIDValid(author.uuid)
function isRemoteVideoUrlValid (url: any) {
return url.type === 'Link' &&
ACTIVITY_PUB.VIDEO_URL_MIME_TYPES.indexOf(url.mimeType) !== -1 &&
validator.isURL(url.url) &&
validator.isInt(url.width, { min: 0 }) &&
validator.isInt(url.size, { min: 0 })
}

View file

@ -3,6 +3,5 @@ export * from './misc'
export * from './pods'
export * from './pods'
export * from './users'
export * from './video-authors'
export * from './video-channels'
export * from './videos'

View file

@ -1,45 +0,0 @@
import * as Promise from 'bluebird'
import * as validator from 'validator'
import * as express from 'express'
import 'express-validator'
import { database as db } from '../../initializers'
import { AuthorInstance } from '../../models'
import { logger } from '../logger'
import { isUserUsernameValid } from './users'
function isVideoAuthorNameValid (value: string) {
return isUserUsernameValid(value)
}
function checkVideoAuthorExists (id: string, res: express.Response, callback: () => void) {
let promise: Promise<AuthorInstance>
if (validator.isInt(id)) {
promise = db.Author.load(+id)
} else { // UUID
promise = db.Author.loadByUUID(id)
}
promise.then(author => {
if (!author) {
return res.status(404)
.json({ error: 'Video author not found' })
.end()
}
res.locals.author = author
callback()
})
.catch(err => {
logger.error('Error in video author request validator.', err)
return res.sendStatus(500)
})
}
// ---------------------------------------------------------------------------
export {
checkVideoAuthorExists,
isVideoAuthorNameValid
}

View file

@ -73,19 +73,26 @@ function isVideoDescriptionValid (value: string) {
}
function isVideoDurationValid (value: string) {
return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
// https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
return exists(value) &&
typeof value === 'string' &&
value.startsWith('PT') &&
value.endsWith('S') &&
validator.isInt(value.replace(/[^0-9]+/, ''), VIDEOS_CONSTRAINTS_FIELDS.DURATION)
}
function isVideoNameValid (value: string) {
return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
}
function isVideoTagValid (tag: string) {
return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
}
function isVideoTagsValid (tags: string[]) {
return isArray(tags) &&
validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
tags.every(tag => {
return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
})
tags.every(tag => isVideoTagValid(tag))
}
function isVideoThumbnailValid (value: string) {
@ -209,6 +216,7 @@ export {
isRemoteVideoPrivacyValid,
isVideoFileResolutionValid,
checkVideoExists,
isVideoTagValid,
isRemoteVideoCategoryValid,
isRemoteVideoLicenceValid,
isRemoteVideoLanguageValid