function accountController (req: express.Request, res: express.Response) {
const account = res.locals.account
- return activityPubResponse(activityPubContextify(account.toActivityPubObject()), res)
+ return activityPubResponse(activityPubContextify(account.toActivityPubObject(), 'Actor'), res)
}
async function accountFollowersController (req: express.Request, res: express.Response) {
const account = res.locals.account
const activityPubResult = await actorFollowers(req, account.Actor)
- return activityPubResponse(activityPubContextify(activityPubResult), res)
+ return activityPubResponse(activityPubContextify(activityPubResult, 'Collection'), res)
}
async function accountFollowingController (req: express.Request, res: express.Response) {
const account = res.locals.account
const activityPubResult = await actorFollowing(req, account.Actor)
- return activityPubResponse(activityPubContextify(activityPubResult), res)
+ return activityPubResponse(activityPubContextify(activityPubResult, 'Collection'), res)
}
async function accountPlaylistsController (req: express.Request, res: express.Response) {
const account = res.locals.account
const activityPubResult = await actorPlaylists(req, { account })
- return activityPubResponse(activityPubContextify(activityPubResult), res)
+ return activityPubResponse(activityPubContextify(activityPubResult, 'Collection'), res)
}
async function videoChannelPlaylistsController (req: express.Request, res: express.Response) {
const channel = res.locals.videoChannel
const activityPubResult = await actorPlaylists(req, { channel })
- return activityPubResponse(activityPubContextify(activityPubResult), res)
+ return activityPubResponse(activityPubContextify(activityPubResult, 'Collection'), res)
}
function getAccountVideoRateFactory (rateType: VideoRateType) {
? buildLikeActivity(accountVideoRate.url, byActor, accountVideoRate.Video)
: buildDislikeActivity(accountVideoRate.url, byActor, accountVideoRate.Video)
- return activityPubResponse(activityPubContextify(APObject), res)
+ return activityPubResponse(activityPubContextify(APObject, 'Rate'), res)
}
}
if (req.path.endsWith('/activity')) {
const data = buildCreateActivity(videoWithCaptions.url, video.VideoChannel.Account.Actor, videoObject, audience)
- return activityPubResponse(activityPubContextify(data), res)
+ return activityPubResponse(activityPubContextify(data, 'Video'), res)
}
- return activityPubResponse(activityPubContextify(videoObject), res)
+ return activityPubResponse(activityPubContextify(videoObject, 'Video'), res)
}
async function videoAnnounceController (req: express.Request, res: express.Response) {
}
const json = await activityPubCollectionPagination(getLocalVideoSharesActivityPubUrl(video), handler, req.query.page)
- return activityPubResponse(activityPubContextify(json), res)
+ return activityPubResponse(activityPubContextify(json, 'Collection'), res)
}
async function videoLikesController (req: express.Request, res: express.Response) {
const json = await videoRates(req, 'like', video, getLocalVideoLikesActivityPubUrl(video))
- return activityPubResponse(activityPubContextify(json), res)
+ return activityPubResponse(activityPubContextify(json, 'Collection'), res)
}
async function videoDislikesController (req: express.Request, res: express.Response) {
const json = await videoRates(req, 'dislike', video, getLocalVideoDislikesActivityPubUrl(video))
- return activityPubResponse(activityPubContextify(json), res)
+ return activityPubResponse(activityPubContextify(json, 'Collection'), res)
}
async function videoCommentsController (req: express.Request, res: express.Response) {
}
const json = await activityPubCollectionPagination(getLocalVideoCommentsActivityPubUrl(video), handler, req.query.page)
- return activityPubResponse(activityPubContextify(json), res)
+ return activityPubResponse(activityPubContextify(json, 'Collection'), res)
}
function videoChannelController (req: express.Request, res: express.Response) {
const videoChannel = res.locals.videoChannel
- return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res)
+ return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject(), 'Actor'), res)
}
async function videoChannelFollowersController (req: express.Request, res: express.Response) {
const videoChannel = res.locals.videoChannel
const activityPubResult = await actorFollowers(req, videoChannel.Actor)
- return activityPubResponse(activityPubContextify(activityPubResult), res)
+ return activityPubResponse(activityPubContextify(activityPubResult, 'Collection'), res)
}
async function videoChannelFollowingController (req: express.Request, res: express.Response) {
const videoChannel = res.locals.videoChannel
const activityPubResult = await actorFollowing(req, videoChannel.Actor)
- return activityPubResponse(activityPubContextify(activityPubResult), res)
+ return activityPubResponse(activityPubContextify(activityPubResult, 'Collection'), res)
}
async function videoCommentController (req: express.Request, res: express.Response) {
if (req.path.endsWith('/activity')) {
const data = buildCreateActivity(videoComment.url, videoComment.Account.Actor, videoCommentObject, audience)
- return activityPubResponse(activityPubContextify(data), res)
+ return activityPubResponse(activityPubContextify(data, 'Comment'), res)
}
}
- return activityPubResponse(activityPubContextify(videoCommentObject), res)
+ return activityPubResponse(activityPubContextify(videoCommentObject, 'Comment'), res)
}
async function videoRedundancyController (req: express.Request, res: express.Response) {
const audience = getAudience(playlist.OwnerAccount.Actor, playlist.privacy === VideoPlaylistPrivacy.PUBLIC)
const object = audiencify(json, audience)
- return activityPubResponse(activityPubContextify(object), res)
+ return activityPubResponse(activityPubContextify(object, 'Playlist'), res)
}
function videoPlaylistElementController (req: express.Request, res: express.Response) {
if (redirectIfNotOwned(videoPlaylistElement.url, res)) return
const json = videoPlaylistElement.toActivityPubObject()
- return activityPubResponse(activityPubContextify(json), res)
+ return activityPubResponse(activityPubContextify(json, 'Playlist'), res)
}
// ---------------------------------------------------------------------------
const handler = (start: number, count: number) => buildActivities(actor, start, count)
const json = await activityPubCollectionPagination(actorOutboxUrl, handler, req.query.page, req.query.size)
- return activityPubResponse(activityPubContextify(json), res)
+ return activityPubResponse(activityPubContextify(json, 'Collection'), res)
}
async function buildActivities (actor: MActorLight, start: number, count: number) {
-import { signJsonLDObject } from '@server/helpers/peertube-crypto'
-import { MActor } from '@server/types/models'
-import { ContextType } from '@shared/models'
-import { activityPubContextify } from './context'
-
-function buildSignedActivity <T> (byActor: MActor, data: T, contextType?: ContextType) {
- const activity = activityPubContextify(data, contextType)
-
- return signJsonLDObject(byActor, activity)
-}
-
function getAPId (object: string | { id: string }) {
if (typeof object === 'string') return object
}
export {
- buildSignedActivity,
getAPId
}
}
function audiencify<T> (object: T, audience: ActivityAudience) {
- return Object.assign(object, audience)
+ return { ...audience, ...object }
}
// ---------------------------------------------------------------------------
import { ContextType } from '@shared/models'
-function getContextData (type: ContextType) {
- const context: any[] = [
- 'https://www.w3.org/ns/activitystreams',
- 'https://w3id.org/security/v1',
- {
- RsaSignature2017: 'https://w3id.org/security#RsaSignature2017'
+function activityPubContextify <T> (data: T, type: ContextType) {
+ return { ...getContextData(type), ...data }
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+ getContextData,
+ activityPubContextify
+}
+
+// ---------------------------------------------------------------------------
+
+type ContextValue = { [ id: string ]: (string | { '@type': string, '@id': string }) }
+
+const contextStore = {
+ Video: buildContext({
+ Hashtag: 'as:Hashtag',
+ uuid: 'sc:identifier',
+ category: 'sc:category',
+ licence: 'sc:license',
+ subtitleLanguage: 'sc:subtitleLanguage',
+ sensitive: 'as:sensitive',
+ language: 'sc:inLanguage',
+
+ // TODO: remove in a few versions, introduced in 4.2
+ icons: 'as:icon',
+
+ isLiveBroadcast: 'sc:isLiveBroadcast',
+ liveSaveReplay: {
+ '@type': 'sc:Boolean',
+ '@id': 'pt:liveSaveReplay'
+ },
+ permanentLive: {
+ '@type': 'sc:Boolean',
+ '@id': 'pt:permanentLive'
+ },
+ latencyMode: {
+ '@type': 'sc:Number',
+ '@id': 'pt:latencyMode'
+ },
+
+ Infohash: 'pt:Infohash',
+
+ originallyPublishedAt: 'sc:datePublished',
+ views: {
+ '@type': 'sc:Number',
+ '@id': 'pt:views'
+ },
+ state: {
+ '@type': 'sc:Number',
+ '@id': 'pt:state'
+ },
+ size: {
+ '@type': 'sc:Number',
+ '@id': 'pt:size'
+ },
+ fps: {
+ '@type': 'sc:Number',
+ '@id': 'pt:fps'
+ },
+ commentsEnabled: {
+ '@type': 'sc:Boolean',
+ '@id': 'pt:commentsEnabled'
+ },
+ downloadEnabled: {
+ '@type': 'sc:Boolean',
+ '@id': 'pt:downloadEnabled'
+ },
+ waitTranscoding: {
+ '@type': 'sc:Boolean',
+ '@id': 'pt:waitTranscoding'
+ },
+ support: {
+ '@type': 'sc:Text',
+ '@id': 'pt:support'
+ },
+ likes: {
+ '@id': 'as:likes',
+ '@type': '@id'
+ },
+ dislikes: {
+ '@id': 'as:dislikes',
+ '@type': '@id'
+ },
+ shares: {
+ '@id': 'as:shares',
+ '@type': '@id'
+ },
+ comments: {
+ '@id': 'as:comments',
+ '@type': '@id'
}
- ]
+ }),
- if (type !== 'View' && type !== 'Announce') {
- const additional = {
- pt: 'https://joinpeertube.org/ns#',
- sc: 'http://schema.org#'
+ Playlist: buildContext({
+ Playlist: 'pt:Playlist',
+ PlaylistElement: 'pt:PlaylistElement',
+ position: {
+ '@type': 'sc:Number',
+ '@id': 'pt:position'
+ },
+ startTimestamp: {
+ '@type': 'sc:Number',
+ '@id': 'pt:startTimestamp'
+ },
+ stopTimestamp: {
+ '@type': 'sc:Number',
+ '@id': 'pt:stopTimestamp'
}
+ }),
+
+ CacheFile: buildContext({
+ expires: 'sc:expires',
+ CacheFile: 'pt:CacheFile'
+ }),
- if (type === 'CacheFile') {
- Object.assign(additional, {
- expires: 'sc:expires',
- CacheFile: 'pt:CacheFile'
- })
- } else {
- Object.assign(additional, {
- Hashtag: 'as:Hashtag',
- uuid: 'sc:identifier',
- category: 'sc:category',
- licence: 'sc:license',
- subtitleLanguage: 'sc:subtitleLanguage',
- sensitive: 'as:sensitive',
- language: 'sc:inLanguage',
-
- // TODO: remove in a few versions, introduced in 4.2
- icons: 'as:icon',
-
- isLiveBroadcast: 'sc:isLiveBroadcast',
- liveSaveReplay: {
- '@type': 'sc:Boolean',
- '@id': 'pt:liveSaveReplay'
- },
- permanentLive: {
- '@type': 'sc:Boolean',
- '@id': 'pt:permanentLive'
- },
- latencyMode: {
- '@type': 'sc:Number',
- '@id': 'pt:latencyMode'
- },
-
- Infohash: 'pt:Infohash',
- Playlist: 'pt:Playlist',
- PlaylistElement: 'pt:PlaylistElement',
-
- originallyPublishedAt: 'sc:datePublished',
- views: {
- '@type': 'sc:Number',
- '@id': 'pt:views'
- },
- state: {
- '@type': 'sc:Number',
- '@id': 'pt:state'
- },
- size: {
- '@type': 'sc:Number',
- '@id': 'pt:size'
- },
- fps: {
- '@type': 'sc:Number',
- '@id': 'pt:fps'
- },
- startTimestamp: {
- '@type': 'sc:Number',
- '@id': 'pt:startTimestamp'
- },
- stopTimestamp: {
- '@type': 'sc:Number',
- '@id': 'pt:stopTimestamp'
- },
- position: {
- '@type': 'sc:Number',
- '@id': 'pt:position'
- },
- commentsEnabled: {
- '@type': 'sc:Boolean',
- '@id': 'pt:commentsEnabled'
- },
- downloadEnabled: {
- '@type': 'sc:Boolean',
- '@id': 'pt:downloadEnabled'
- },
- waitTranscoding: {
- '@type': 'sc:Boolean',
- '@id': 'pt:waitTranscoding'
- },
- support: {
- '@type': 'sc:Text',
- '@id': 'pt:support'
- },
- likes: {
- '@id': 'as:likes',
- '@type': '@id'
- },
- dislikes: {
- '@id': 'as:dislikes',
- '@type': '@id'
- },
- playlists: {
- '@id': 'pt:playlists',
- '@type': '@id'
- },
- shares: {
- '@id': 'as:shares',
- '@type': '@id'
- },
- comments: {
- '@id': 'as:comments',
- '@type': '@id'
- }
- })
+ Flag: buildContext({
+ Hashtag: 'as:Hashtag'
+ }),
+
+ Actor: buildContext({
+ playlists: {
+ '@id': 'pt:playlists',
+ '@type': '@id'
}
+ }),
- context.push(additional)
- }
+ Follow: buildContext(),
+ Reject: buildContext(),
+ Accept: buildContext(),
+ View: buildContext(),
+ Announce: buildContext(),
+ Comment: buildContext(),
+ Delete: buildContext(),
+ Rate: buildContext()
+}
+function getContextData (type: ContextType) {
return {
- '@context': context
+ '@context': contextStore[type]
}
}
-function activityPubContextify <T> (data: T, type: ContextType = 'All') {
- return Object.assign({}, data, getContextData(type))
-}
+function buildContext (contextValue?: ContextValue) {
+ const baseContext = [
+ 'https://www.w3.org/ns/activitystreams',
+ 'https://w3id.org/security/v1',
+ {
+ RsaSignature2017: 'https://w3id.org/security#RsaSignature2017'
+ }
+ ]
-export {
- getContextData,
- activityPubContextify
+ if (!contextValue) return baseContext
+
+ return [
+ ...baseContext,
+
+ {
+ pt: 'https://joinpeertube.org/ns#',
+ sc: 'http://schema.org#',
+
+ ...contextValue
+ }
+ ]
}
-import { buildDigest } from '@server/helpers/peertube-crypto'
-import { buildSignedActivity } from '@server/lib/activitypub/activity'
+import { buildDigest, signJsonLDObject } from '@server/helpers/peertube-crypto'
+import { ACTIVITY_PUB, HTTP_SIGNATURE } from '@server/initializers/constants'
+import { ActorModel } from '@server/models/actor/actor'
import { getServerActor } from '@server/models/application/application'
+import { MActor } from '@server/types/models'
import { ContextType } from '@shared/models/activitypub/context'
-import { ACTIVITY_PUB, HTTP_SIGNATURE } from '../../../../initializers/constants'
-import { ActorModel } from '../../../../models/actor/actor'
-import { MActor } from '../../../../types/models'
+import { activityPubContextify } from '../context'
-type Payload <T> = { body: T, contextType?: ContextType, signatureActorId?: number }
+type Payload <T> = { body: T, contextType: ContextType, signatureActorId?: number }
async function computeBody <T> (
payload: Payload<T>
const actorSignature = await ActorModel.load(payload.signatureActorId)
if (!actorSignature) throw new Error('Unknown signature actor id.')
- body = await buildSignedActivity(actorSignature, payload.body, payload.contextType)
+ body = await signAndContextify(actorSignature, payload.body, payload.contextType)
}
return body
}
}
+function signAndContextify <T> (byActor: MActor, data: T, contextType: ContextType | null) {
+ const activity = contextType
+ ? activityPubContextify(data, contextType)
+ : data
+
+ return signJsonLDObject(byActor, activity)
+}
+
export {
buildGlobalHeaders,
computeBody,
- buildSignedRequestOptions
+ buildSignedRequestOptions,
+ signAndContextify
}
-export * from './send-accept'
+export * from './http'
export * from './send-accept'
export * from './send-announce'
export * from './send-create'
const url = getLocalActorFollowAcceptActivityPubUrl(actorFollow)
const data = buildAcceptActivity(url, me, followData)
- return unicastTo(data, me, follower.inboxUrl)
+ return unicastTo({
+ data,
+ byActor: me,
+ toActorUrl: follower.inboxUrl,
+ contextType: 'Accept'
+ })
}
// ---------------------------------------------------------------------------
return { activity, actorsInvolvedInVideo }
}
-async function sendVideoAnnounce (byActor: MActorLight, videoShare: MVideoShare, video: MVideo, t: Transaction) {
- const { activity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, t)
+async function sendVideoAnnounce (byActor: MActorLight, videoShare: MVideoShare, video: MVideo, transaction: Transaction) {
+ const { activity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, transaction)
logger.info('Creating job to send announce %s.', videoShare.url)
- const followersException = [ byActor ]
- return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException, 'Announce')
+ return broadcastToFollowers({
+ data: activity,
+ byActor,
+ toFollowersOf: actorsInvolvedInVideo,
+ transaction,
+ actorsException: [ byActor ],
+ contextType: 'Announce'
+ })
}
function buildAnnounceActivity (url: string, byActor: MActorLight, object: string, audience?: ActivityAudience): ActivityAnnounce {
const lTags = loggerTagsFactory('ap', 'create')
-async function sendCreateVideo (video: MVideoAP, t: Transaction) {
+async function sendCreateVideo (video: MVideoAP, transaction: Transaction) {
if (!video.hasPrivacyForFederation()) return undefined
logger.info('Creating job to send video creation of %s.', video.url, lTags(video.uuid))
const audience = getAudience(byActor, video.privacy === VideoPrivacy.PUBLIC)
const createActivity = buildCreateActivity(video.url, byActor, videoObject, audience)
- return broadcastToFollowers(createActivity, byActor, [ byActor ], t)
+ return broadcastToFollowers({
+ data: createActivity,
+ byActor,
+ toFollowersOf: [ byActor ],
+ transaction,
+ contextType: 'Video'
+ })
}
async function sendCreateCacheFile (
})
}
-async function sendCreateVideoPlaylist (playlist: MVideoPlaylistFull, t: Transaction) {
+async function sendCreateVideoPlaylist (playlist: MVideoPlaylistFull, transaction: Transaction) {
if (playlist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined
logger.info('Creating job to send create video playlist of %s.', playlist.url, lTags(playlist.uuid))
const byActor = playlist.OwnerAccount.Actor
const audience = getAudience(byActor, playlist.privacy === VideoPlaylistPrivacy.PUBLIC)
- const object = await playlist.toActivityPubObject(null, t)
+ const object = await playlist.toActivityPubObject(null, transaction)
const createActivity = buildCreateActivity(playlist.url, byActor, object, audience)
const serverActor = await getServerActor()
if (playlist.VideoChannel) toFollowersOf.push(playlist.VideoChannel.Actor)
- return broadcastToFollowers(createActivity, byActor, toFollowersOf, t)
+ return broadcastToFollowers({
+ data: createActivity,
+ byActor,
+ toFollowersOf,
+ transaction,
+ contextType: 'Playlist'
+ })
}
-async function sendCreateVideoComment (comment: MCommentOwnerVideo, t: Transaction) {
+async function sendCreateVideoComment (comment: MCommentOwnerVideo, transaction: Transaction) {
logger.info('Creating job to send comment %s.', comment.url)
const isOrigin = comment.Video.isOwned()
const byActor = comment.Account.Actor
- const threadParentComments = await VideoCommentModel.listThreadParentComments(comment, t)
+ const threadParentComments = await VideoCommentModel.listThreadParentComments(comment, transaction)
const commentObject = comment.toActivityPubObject(threadParentComments)
- const actorsInvolvedInComment = await getActorsInvolvedInVideo(comment.Video, t)
+ const actorsInvolvedInComment = await getActorsInvolvedInVideo(comment.Video, transaction)
// Add the actor that commented too
actorsInvolvedInComment.push(byActor)
// This was a reply, send it to the parent actors
const actorsException = [ byActor ]
- await broadcastToActors(createActivity, byActor, parentsCommentActors, t, actorsException)
+ await broadcastToActors({
+ data: createActivity,
+ byActor,
+ toActors: parentsCommentActors,
+ transaction,
+ actorsException,
+ contextType: 'Comment'
+ })
// Broadcast to our followers
- await broadcastToFollowers(createActivity, byActor, [ byActor ], t)
+ await broadcastToFollowers({
+ data: createActivity,
+ byActor,
+ toFollowersOf: [ byActor ],
+ transaction,
+ contextType: 'Comment'
+ })
// Send to actors involved in the comment
- if (isOrigin) return broadcastToFollowers(createActivity, byActor, actorsInvolvedInComment, t, actorsException)
+ if (isOrigin) {
+ return broadcastToFollowers({
+ data: createActivity,
+ byActor,
+ toFollowersOf: actorsInvolvedInComment,
+ transaction,
+ actorsException,
+ contextType: 'Comment'
+ })
+ }
// Send to origin
- t.afterCommit(() => unicastTo(createActivity, byActor, comment.Video.VideoChannel.Account.Actor.getSharedInbox()))
+ return transaction.afterCommit(() => {
+ return unicastTo({
+ data: createActivity,
+ byActor,
+ toActorUrl: comment.Video.VideoChannel.Account.Actor.getSharedInbox(),
+ contextType: 'Comment'
+ })
+ })
}
function buildCreateActivity (url: string, byActor: MActorLight, object: any, audience?: ActivityAudience): ActivityCreate {
video: MVideoAccountLight
url: string
object: any
+ contextType: ContextType
transaction?: Transaction
- contextType?: ContextType
}) {
const activityBuilder = (audience: ActivityAudience) => {
return buildCreateActivity(options.url, options.byActor, options.object, audience)
return buildDeleteActivity(url, video.url, byActor, audience)
}
- return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction })
+ return sendVideoRelatedActivity(activityBuilder, { byActor, video, contextType: 'Delete', transaction })
}
-async function sendDeleteActor (byActor: ActorModel, t: Transaction) {
+async function sendDeleteActor (byActor: ActorModel, transaction: Transaction) {
logger.info('Creating job to broadcast delete of actor %s.', byActor.url)
const url = getDeleteActivityPubUrl(byActor.url)
const activity = buildDeleteActivity(url, byActor.url, byActor)
- const actorsInvolved = await VideoShareModel.loadActorsWhoSharedVideosOf(byActor.id, t)
+ const actorsInvolved = await VideoShareModel.loadActorsWhoSharedVideosOf(byActor.id, transaction)
// In case the actor did not have any videos
const serverActor = await getServerActor()
actorsInvolved.push(byActor)
- return broadcastToFollowers(activity, byActor, actorsInvolved, t)
+ return broadcastToFollowers({
+ data: activity,
+ byActor,
+ toFollowersOf: actorsInvolved,
+ contextType: 'Delete',
+ transaction
+ })
}
-async function sendDeleteVideoComment (videoComment: MCommentOwnerVideo, t: Transaction) {
+async function sendDeleteVideoComment (videoComment: MCommentOwnerVideo, transaction: Transaction) {
logger.info('Creating job to send delete of comment %s.', videoComment.url)
const isVideoOrigin = videoComment.Video.isOwned()
? videoComment.Account.Actor
: videoComment.Video.VideoChannel.Account.Actor
- const threadParentComments = await VideoCommentModel.listThreadParentComments(videoComment, t)
+ const threadParentComments = await VideoCommentModel.listThreadParentComments(videoComment, transaction)
const threadParentCommentsFiltered = threadParentComments.filter(c => !c.isDeleted())
- const actorsInvolvedInComment = await getActorsInvolvedInVideo(videoComment.Video, t)
+ const actorsInvolvedInComment = await getActorsInvolvedInVideo(videoComment.Video, transaction)
actorsInvolvedInComment.push(byActor) // Add the actor that commented the video
const audience = getVideoCommentAudience(videoComment, threadParentCommentsFiltered, actorsInvolvedInComment, isVideoOrigin)
// This was a reply, send it to the parent actors
const actorsException = [ byActor ]
- await broadcastToActors(activity, byActor, threadParentCommentsFiltered.map(c => c.Account.Actor), t, actorsException)
+ await broadcastToActors({
+ data: activity,
+ byActor,
+ toActors: threadParentCommentsFiltered.map(c => c.Account.Actor),
+ transaction,
+ contextType: 'Delete',
+ actorsException
+ })
// Broadcast to our followers
- await broadcastToFollowers(activity, byActor, [ byActor ], t)
+ await broadcastToFollowers({
+ data: activity,
+ byActor,
+ toFollowersOf: [ byActor ],
+ contextType: 'Delete',
+ transaction
+ })
// Send to actors involved in the comment
- if (isVideoOrigin) return broadcastToFollowers(activity, byActor, actorsInvolvedInComment, t, actorsException)
+ if (isVideoOrigin) {
+ return broadcastToFollowers({
+ data: activity,
+ byActor,
+ toFollowersOf: actorsInvolvedInComment,
+ transaction,
+ contextType: 'Delete',
+ actorsException
+ })
+ }
// Send to origin
- t.afterCommit(() => unicastTo(activity, byActor, videoComment.Video.VideoChannel.Account.Actor.getSharedInbox()))
+ return transaction.afterCommit(() => {
+ return unicastTo({
+ data: activity,
+ byActor,
+ toActorUrl: videoComment.Video.VideoChannel.Account.Actor.getSharedInbox(),
+ contextType: 'Delete'
+ })
+ })
}
-async function sendDeleteVideoPlaylist (videoPlaylist: MVideoPlaylistFullSummary, t: Transaction) {
+async function sendDeleteVideoPlaylist (videoPlaylist: MVideoPlaylistFullSummary, transaction: Transaction) {
logger.info('Creating job to send delete of playlist %s.', videoPlaylist.url)
const byActor = videoPlaylist.OwnerAccount.Actor
if (videoPlaylist.VideoChannel) toFollowersOf.push(videoPlaylist.VideoChannel.Actor)
- return broadcastToFollowers(activity, byActor, toFollowersOf, t)
+ return broadcastToFollowers({
+ data: activity,
+ byActor,
+ toFollowersOf,
+ contextType: 'Delete',
+ transaction
+ })
}
// ---------------------------------------------------------------------------
import { getVideoDislikeActivityPubUrlByLocalActor } from '../url'
import { sendVideoActivityToOrigin } from './shared/send-utils'
-function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
+function sendDislike (byActor: MActor, video: MVideoAccountLight, transaction: Transaction) {
logger.info('Creating job to dislike %s.', video.url)
const activityBuilder = (audience: ActivityAudience) => {
return buildDislikeActivity(url, byActor, video, audience)
}
- return sendVideoActivityToOrigin(activityBuilder, { byActor, video, transaction: t })
+ return sendVideoActivityToOrigin(activityBuilder, { byActor, video, transaction, contextType: 'Rate' })
}
function buildDislikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityDislike {
const audience = { to: [ flaggedAccount.Actor.url ], cc: [] }
const flagActivity = buildFlagActivity(url, byActor, abuse, audience)
- t.afterCommit(() => unicastTo(flagActivity, byActor, flaggedAccount.Actor.getSharedInbox()))
+ return t.afterCommit(() => {
+ return unicastTo({
+ data: flagActivity,
+ byActor,
+ toActorUrl: flaggedAccount.Actor.getSharedInbox(),
+ contextType: 'Flag'
+ })
+ })
}
function buildFlagActivity (url: string, byActor: MActor, abuse: MAbuseAP, audience: ActivityAudience): ActivityFlag {
if (!audience) audience = getAudience(byActor)
- const activity = Object.assign(
- { id: url, actor: byActor.url },
- abuse.toActivityPubObject()
- )
+ const activity = { id: url, actor: byActor.url, ...abuse.toActivityPubObject() }
return audiencify(activity, audience)
}
const data = buildFollowActivity(actorFollow.url, me, following)
- t.afterCommit(() => unicastTo(data, me, following.inboxUrl))
+ return t.afterCommit(() => {
+ return unicastTo({ data, byActor: me, toActorUrl: following.inboxUrl, contextType: 'Follow' })
+ })
}
function buildFollowActivity (url: string, byActor: MActor, targetActor: MActor): ActivityFollow {
import { getVideoLikeActivityPubUrlByLocalActor } from '../url'
import { sendVideoActivityToOrigin } from './shared/send-utils'
-function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
+function sendLike (byActor: MActor, video: MVideoAccountLight, transaction: Transaction) {
logger.info('Creating job to like %s.', video.url)
const activityBuilder = (audience: ActivityAudience) => {
return buildLikeActivity(url, byActor, video, audience)
}
- return sendVideoActivityToOrigin(activityBuilder, { byActor, video, transaction: t })
+ return sendVideoActivityToOrigin(activityBuilder, { byActor, video, transaction, contextType: 'Rate' })
}
function buildLikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityLike {
const url = getLocalActorFollowRejectActivityPubUrl(follower, following)
const data = buildRejectActivity(url, following, followData)
- return unicastTo(data, following, follower.inboxUrl)
+ return unicastTo({ data, byActor: following, toActorUrl: follower.inboxUrl, contextType: 'Reject' })
}
// ---------------------------------------------------------------------------
ActivityDislike,
ActivityFollow,
ActivityLike,
- ActivityUndo
+ ActivityUndo,
+ ContextType
} from '@shared/models'
import { logger } from '../../../helpers/logger'
import { VideoModel } from '../../../models/video/video'
const followActivity = buildFollowActivity(actorFollow.url, me, following)
const undoActivity = undoActivityData(undoUrl, me, followActivity)
- t.afterCommit(() => unicastTo(undoActivity, me, following.inboxUrl))
+ return t.afterCommit(() => {
+ return unicastTo({
+ data: undoActivity,
+ byActor: me,
+ toActorUrl: following.inboxUrl,
+ contextType: 'Follow'
+ })
+ })
}
// ---------------------------------------------------------------------------
-async function sendUndoAnnounce (byActor: MActorLight, videoShare: MVideoShare, video: MVideo, t: Transaction) {
+async function sendUndoAnnounce (byActor: MActorLight, videoShare: MVideoShare, video: MVideo, transaction: Transaction) {
logger.info('Creating job to undo announce %s.', videoShare.url)
const undoUrl = getUndoActivityPubUrl(videoShare.url)
- const { activity: announceActivity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, t)
- const undoActivity = undoActivityData(undoUrl, byActor, announceActivity)
-
- const followersException = [ byActor ]
- return broadcastToFollowers(undoActivity, byActor, actorsInvolvedInVideo, t, followersException)
+ const { activity: announce, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, transaction)
+ const undoActivity = undoActivityData(undoUrl, byActor, announce)
+
+ return broadcastToFollowers({
+ data: undoActivity,
+ byActor,
+ toFollowersOf: actorsInvolvedInVideo,
+ transaction,
+ actorsException: [ byActor ],
+ contextType: 'Announce'
+ })
}
-async function sendUndoCacheFile (byActor: MActor, redundancyModel: MVideoRedundancyVideo, t: Transaction) {
+async function sendUndoCacheFile (byActor: MActor, redundancyModel: MVideoRedundancyVideo, transaction: Transaction) {
logger.info('Creating job to undo cache file %s.', redundancyModel.url)
const associatedVideo = redundancyModel.getVideo()
const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(associatedVideo.id)
const createActivity = buildCreateActivity(redundancyModel.url, byActor, redundancyModel.toActivityPubObject())
- return sendUndoVideoRelatedActivity({ byActor, video, url: redundancyModel.url, activity: createActivity, transaction: t })
+ return sendUndoVideoRelatedActivity({
+ byActor,
+ video,
+ url: redundancyModel.url,
+ activity: createActivity,
+ contextType: 'CacheFile',
+ transaction
+ })
}
// ---------------------------------------------------------------------------
const likeUrl = getVideoLikeActivityPubUrlByLocalActor(byActor, video)
const likeActivity = buildLikeActivity(likeUrl, byActor, video)
- return sendUndoVideoToOriginActivity({ byActor, video, url: likeUrl, activity: likeActivity, transaction: t })
+ return sendUndoVideoRateToOriginActivity({ byActor, video, url: likeUrl, activity: likeActivity, transaction: t })
}
async function sendUndoDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
const dislikeUrl = getVideoDislikeActivityPubUrlByLocalActor(byActor, video)
const dislikeActivity = buildDislikeActivity(dislikeUrl, byActor, video)
- return sendUndoVideoToOriginActivity({ byActor, video, url: dislikeUrl, activity: dislikeActivity, transaction: t })
+ return sendUndoVideoRateToOriginActivity({ byActor, video, url: dislikeUrl, activity: dislikeActivity, transaction: t })
}
// ---------------------------------------------------------------------------
video: MVideoAccountLight
url: string
activity: ActivityFollow | ActivityCreate | ActivityAnnounce
+ contextType: ContextType
transaction: Transaction
}) {
const activityBuilder = (audience: ActivityAudience) => {
return sendVideoRelatedActivity(activityBuilder, options)
}
-async function sendUndoVideoToOriginActivity (options: {
+async function sendUndoVideoRateToOriginActivity (options: {
byActor: MActor
video: MVideoAccountLight
url: string
return undoActivityData(undoUrl, options.byActor, options.activity, audience)
}
- return sendVideoActivityToOrigin(activityBuilder, options)
+ return sendVideoActivityToOrigin(activityBuilder, { ...options, contextType: 'Rate' })
}
import { getActorsInvolvedInVideo } from './shared'
import { broadcastToFollowers, sendVideoRelatedActivity } from './shared/send-utils'
-async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, t: Transaction, overrodeByActor?: MActor) {
+async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, transaction: Transaction, overriddenByActor?: MActor) {
const video = videoArg as MVideoAP
if (!video.hasPrivacyForFederation()) return undefined
logger.info('Creating job to update video %s.', video.url)
- const byActor = overrodeByActor || video.VideoChannel.Account.Actor
+ const byActor = overriddenByActor || video.VideoChannel.Account.Actor
const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString())
// Needed to build the AP object
if (!video.VideoCaptions) {
- video.VideoCaptions = await video.$get('VideoCaptions', { transaction: t })
+ video.VideoCaptions = await video.$get('VideoCaptions', { transaction })
}
const videoObject = video.toActivityPubObject()
const updateActivity = buildUpdateActivity(url, byActor, videoObject, audience)
- const actorsInvolved = await getActorsInvolvedInVideo(video, t)
- if (overrodeByActor) actorsInvolved.push(overrodeByActor)
+ const actorsInvolved = await getActorsInvolvedInVideo(video, transaction)
+ if (overriddenByActor) actorsInvolved.push(overriddenByActor)
- return broadcastToFollowers(updateActivity, byActor, actorsInvolved, t)
+ return broadcastToFollowers({
+ data: updateActivity,
+ byActor,
+ toFollowersOf: actorsInvolved,
+ contextType: 'Video',
+ transaction
+ })
}
-async function sendUpdateActor (accountOrChannel: MChannelDefault | MAccountDefault, t: Transaction) {
+async function sendUpdateActor (accountOrChannel: MChannelDefault | MAccountDefault, transaction: Transaction) {
const byActor = accountOrChannel.Actor
logger.info('Creating job to update actor %s.', byActor.url)
let actorsInvolved: MActor[]
if (accountOrChannel instanceof AccountModel) {
// Actors that shared my videos are involved too
- actorsInvolved = await VideoShareModel.loadActorsWhoSharedVideosOf(byActor.id, t)
+ actorsInvolved = await VideoShareModel.loadActorsWhoSharedVideosOf(byActor.id, transaction)
} else {
// Actors that shared videos of my channel are involved too
- actorsInvolved = await VideoShareModel.loadActorsByVideoChannel(accountOrChannel.id, t)
+ actorsInvolved = await VideoShareModel.loadActorsByVideoChannel(accountOrChannel.id, transaction)
}
actorsInvolved.push(byActor)
- return broadcastToFollowers(updateActivity, byActor, actorsInvolved, t)
+ return broadcastToFollowers({
+ data: updateActivity,
+ byActor,
+ toFollowersOf: actorsInvolved,
+ transaction,
+ contextType: 'Actor'
+ })
}
async function sendUpdateCacheFile (byActor: MActorLight, redundancyModel: MVideoRedundancyVideo) {
return sendVideoRelatedActivity(activityBuilder, { byActor, video, contextType: 'CacheFile' })
}
-async function sendUpdateVideoPlaylist (videoPlaylist: MVideoPlaylistFull, t: Transaction) {
+async function sendUpdateVideoPlaylist (videoPlaylist: MVideoPlaylistFull, transaction: Transaction) {
if (videoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined
const byActor = videoPlaylist.OwnerAccount.Actor
const url = getUpdateActivityPubUrl(videoPlaylist.url, videoPlaylist.updatedAt.toISOString())
- const object = await videoPlaylist.toActivityPubObject(null, t)
+ const object = await videoPlaylist.toActivityPubObject(null, transaction)
const audience = getAudience(byActor, videoPlaylist.privacy === VideoPlaylistPrivacy.PUBLIC)
const updateActivity = buildUpdateActivity(url, byActor, object, audience)
if (videoPlaylist.VideoChannel) toFollowersOf.push(videoPlaylist.VideoChannel.Actor)
- return broadcastToFollowers(updateActivity, byActor, toFollowersOf, t)
+ return broadcastToFollowers({
+ data: updateActivity,
+ byActor,
+ toFollowersOf,
+ transaction,
+ contextType: 'Playlist'
+ })
}
// ---------------------------------------------------------------------------
import { Transaction } from 'sequelize'
import { ActorFollowHealthCache } from '@server/lib/actor-follow-health-cache'
import { getServerActor } from '@server/models/application/application'
-import { Activity, ActivityAudience } from '@shared/models'
+import { Activity, ActivityAudience, ActivitypubHttpBroadcastPayload } from '@shared/models'
import { ContextType } from '@shared/models/activitypub/context'
import { afterCommitIfTransaction } from '../../../../helpers/database-utils'
import { logger } from '../../../../helpers/logger'
async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
byActor: MActorLight
video: MVideoImmutable | MVideoAccountLight
+ contextType: ContextType
transaction?: Transaction
- contextType?: ContextType
}) {
const { byActor, video, transaction, contextType } = options
const actorsException = [ byActor ]
- return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException, contextType)
+ return broadcastToFollowers({
+ data: activity,
+ byActor,
+ toFollowersOf: actorsInvolvedInVideo,
+ transaction,
+ actorsException,
+ contextType
+ })
}
async function sendVideoActivityToOrigin (activityBuilder: (audience: ActivityAudience) => Activity, options: {
byActor: MActorLight
video: MVideoImmutable | MVideoAccountLight
+ contextType: ContextType
+
actorsInvolvedInVideo?: MActorLight[]
transaction?: Transaction
- contextType?: ContextType
}) {
const { byActor, video, actorsInvolvedInVideo, transaction, contextType } = options
const activity = activityBuilder(audience)
return afterCommitIfTransaction(transaction, () => {
- return unicastTo(activity, byActor, accountActor.getSharedInbox(), contextType)
+ return unicastTo({
+ data: activity,
+ byActor,
+ toActorUrl: accountActor.getSharedInbox(),
+ contextType
+ })
})
}
logger.debug('Creating forwarding job.', { uris })
- const payload = {
+ const payload: ActivitypubHttpBroadcastPayload = {
uris,
- body: activity
+ body: activity,
+ contextType: null
}
return afterCommitIfTransaction(t, () => JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }))
}
// ---------------------------------------------------------------------------
-async function broadcastToFollowers (
- data: any,
- byActor: MActorId,
- toFollowersOf: MActorId[],
- t: Transaction,
- actorsException: MActorWithInboxes[] = [],
- contextType?: ContextType
-) {
- const uris = await computeFollowerUris(toFollowersOf, actorsException, t)
+async function broadcastToFollowers (options: {
+ data: any
+ byActor: MActorId
+ toFollowersOf: MActorId[]
+ transaction: Transaction
+ contextType: ContextType
+
+ actorsException?: MActorWithInboxes[]
+}) {
+ const { data, byActor, toFollowersOf, transaction, contextType, actorsException = [] } = options
- return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType))
+ const uris = await computeFollowerUris(toFollowersOf, actorsException, transaction)
+
+ return afterCommitIfTransaction(transaction, () => {
+ return broadcastTo({
+ uris,
+ data,
+ byActor,
+ contextType
+ })
+ })
}
-async function broadcastToActors (
- data: any,
- byActor: MActorId,
- toActors: MActor[],
- t?: Transaction,
- actorsException: MActorWithInboxes[] = [],
- contextType?: ContextType
-) {
+async function broadcastToActors (options: {
+ data: any
+ byActor: MActorId
+ toActors: MActor[]
+ transaction: Transaction
+ contextType: ContextType
+ actorsException?: MActorWithInboxes[]
+}) {
+ const { data, byActor, toActors, transaction, contextType, actorsException = [] } = options
+
const uris = await computeUris(toActors, actorsException)
- return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType))
+
+ return afterCommitIfTransaction(transaction, () => {
+ return broadcastTo({
+ uris,
+ data,
+ byActor,
+ contextType
+ })
+ })
}
-function broadcastTo (uris: string[], data: any, byActor: MActorId, contextType?: ContextType) {
+function broadcastTo (options: {
+ uris: string[]
+ data: any
+ byActor: MActorId
+ contextType: ContextType
+}) {
+ const { uris, data, byActor, contextType } = options
+
if (uris.length === 0) return undefined
const broadcastUris: string[] = []
}
}
-function unicastTo (data: any, byActor: MActorId, toActorUrl: string, contextType?: ContextType) {
+function unicastTo (options: {
+ data: any
+ byActor: MActorId
+ toActorUrl: string
+ contextType: ContextType
+}) {
+ const { data, byActor, toActorUrl, contextType } = options
+
logger.debug('Creating unicast job.', { uri: toActorUrl })
const payload = {
import { map } from 'bluebird'
import { Job } from 'bull'
+import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from '@server/lib/activitypub/send'
import { ActorFollowHealthCache } from '@server/lib/actor-follow-health-cache'
import { ActivitypubHttpBroadcastPayload } from '@shared/models'
import { logger } from '../../../helpers/logger'
import { doRequest } from '../../../helpers/requests'
import { BROADCAST_CONCURRENCY } from '../../../initializers/constants'
-import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils'
async function processActivityPubHttpBroadcast (job: Job) {
logger.info('Processing ActivityPub broadcast in job %d.', job.id)
import { Job } from 'bull'
+import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from '@server/lib/activitypub/send'
import { ActivitypubHttpUnicastPayload } from '@shared/models'
import { logger } from '../../../helpers/logger'
import { doRequest } from '../../../helpers/requests'
import { ActorFollowHealthCache } from '../../actor-follow-health-cache'
-import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils'
async function processActivityPubHttpUnicast (job: Job) {
logger.info('Processing ActivityPub unicast in job %d.', job.id)
image
}
- return activityPubContextify(json)
+ return activityPubContextify(json, 'Actor')
}
getFollowerSharedInboxUrls (t: Transaction) {
import 'mocha'
import { expect } from 'chai'
import { cloneDeep } from 'lodash'
+import { signAndContextify } from '@server/lib/activitypub/send'
import { buildRequestStub } from '@server/tests/shared'
import { buildAbsoluteFixturePath } from '@shared/core-utils'
import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../../../helpers/peertube-crypto'
-import { buildSignedActivity } from '../../../lib/activitypub/activity'
describe('Test activity pub helpers', function () {
describe('When checking the Linked Signature', function () {
const body = require(buildAbsoluteFixturePath('./ap-json/peertube/announce-without-context.json'))
const actorSignature = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey }
- const signedBody = await buildSignedActivity(actorSignature as any, body)
+ const signedBody = await signAndContextify(actorSignature as any, body, 'Announce')
const fromActor = { publicKey: keys.publicKey, url: 'http://localhost:9002/accounts/peertube' }
const result = await isJsonLDSignatureVerified(fromActor as any, signedBody)
const body = require(buildAbsoluteFixturePath('./ap-json/peertube/announce-without-context.json'))
const actorSignature = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey }
- const signedBody = await buildSignedActivity(actorSignature as any, body)
+ const signedBody = await signAndContextify(actorSignature as any, body, 'Announce')
const fromActor = { publicKey: keys.publicKey, url: 'http://localhost:9002/accounts/peertube' }
const result = await isJsonLDSignatureVerified(fromActor as any, signedBody)
import * as chai from 'chai'
import { buildDigest } from '@server/helpers/peertube-crypto'
import { HTTP_SIGNATURE } from '@server/initializers/constants'
-import { buildSignedActivity } from '@server/lib/activitypub/activity'
import { activityPubContextify } from '@server/lib/activitypub/context'
-import { buildGlobalHeaders } from '@server/lib/job-queue/handlers/utils/activitypub-http-utils'
+import { buildGlobalHeaders, signAndContextify } from '@server/lib/activitypub/send'
import { makeFollowRequest, makePOSTAPRequest } from '@server/tests/shared'
import { buildAbsoluteFixturePath, wait } from '@shared/core-utils'
import { HttpStatusCode } from '@shared/models'
describe('When checking HTTP signature', function () {
it('Should fail with an invalid digest', async function () {
- const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
+ const body = activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce')
const headers = {
Digest: buildDigest({ hello: 'coucou' })
}
})
it('Should fail with an invalid date', async function () {
- const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
+ const body = activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce')
const headers = buildGlobalHeaders(body)
headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT'
await setKeysOfServer(servers[0], servers[1], invalidKeys.publicKey, invalidKeys.privateKey)
await setKeysOfServer(servers[1], servers[1], invalidKeys.publicKey, invalidKeys.privateKey)
- const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
+ const body = activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce')
const headers = buildGlobalHeaders(body)
try {
await setKeysOfServer(servers[0], servers[1], keys.publicKey, keys.privateKey)
await setKeysOfServer(servers[1], servers[1], keys.publicKey, keys.privateKey)
- const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
+ const body = activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce')
const headers = buildGlobalHeaders(body)
const signatureOptions = baseHttpSignature()
})
it('Should succeed with a valid HTTP signature', async function () {
- const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
+ const body = activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce')
const headers = buildGlobalHeaders(body)
const { statusCode } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
await killallServers([ servers[1] ])
await servers[1].run()
- const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
+ const body = activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce')
const headers = buildGlobalHeaders(body)
try {
body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
const signer: any = { privateKey: invalidKeys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
- const signedBody = await buildSignedActivity(signer, body)
+ const signedBody = await signAndContextify(signer, body, 'Announce')
const headers = buildGlobalHeaders(signedBody)
body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
- const signedBody = await buildSignedActivity(signer, body)
+ const signedBody = await signAndContextify(signer, body, 'Announce')
signedBody.actor = 'http://localhost:' + servers[2].port + '/account/peertube'
body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
- const signedBody = await buildSignedActivity(signer, body)
+ const signedBody = await signAndContextify(signer, body, 'Announce')
const headers = buildGlobalHeaders(signedBody)
body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
- const signedBody = await buildSignedActivity(signer, body)
+ const signedBody = await signAndContextify(signer, body, 'Announce')
const headers = buildGlobalHeaders(signedBody)
object: to.url
}
- const body = activityPubContextify(follow)
+ const body = activityPubContextify(follow, 'Follow')
const httpSignature = {
algorithm: HTTP_SIGNATURE.ALGORITHM,
-export type ContextType = 'All' | 'View' | 'Announce' | 'CacheFile'
+export type ContextType =
+ 'Video' |
+ 'Comment' |
+ 'Playlist' |
+ 'Follow' |
+ 'Reject' |
+ 'Accept' |
+ 'View' |
+ 'Announce' |
+ 'CacheFile' |
+ 'Delete' |
+ 'Rate' |
+ 'Flag' |
+ 'Actor' |
+ 'Collection'
href: string
}
-export type ActivityPlaylistInfohashesObject = {
+export type ActivityStreamingPlaylistInfohashesObject = {
type: 'Infohash'
name: string
}
export type ActivityTagObject =
ActivityPlaylistSegmentHashesObject
- | ActivityPlaylistInfohashesObject
+ | ActivityStreamingPlaylistInfohashesObject
| ActivityVideoUrlObject
| ActivityHashTagObject
| ActivityMentionObject
export type ActivitypubHttpBroadcastPayload = {
uris: string[]
- signatureActorId?: number
+ contextType: ContextType
body: any
- contextType?: ContextType
+ signatureActorId?: number
}
export type ActivitypubFollowPayload = {
export type ActivitypubHttpUnicastPayload = {
uri: string
+ contextType: ContextType
signatureActorId?: number
body: object
- contextType?: ContextType
}
export type RefreshPayload = {