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

Put ap:public in cc for unlisted data

This commit is contained in:
Chocobozzz 2025-06-16 11:00:47 +02:00
parent 24b59a2560
commit 0c7a89a70a
No known key found for this signature in database
GPG key ID: 583A612D890159BE
15 changed files with 90 additions and 69 deletions

View file

@ -1,11 +1,4 @@
import {
HttpStatusCode,
VideoChaptersObject,
VideoCommentObject,
VideoPlaylistPrivacy,
VideoPrivacy,
VideoRateType
} from '@peertube/peertube-models'
import { HttpStatusCode, VideoChaptersObject, VideoCommentObject, VideoRateType } from '@peertube/peertube-models'
import { activityPubCollectionPagination } from '@server/lib/activitypub/collection.js'
import { getContextFilter } from '@server/lib/activitypub/context.js'
import { buildChaptersAPHasPart } from '@server/lib/activitypub/video-chapters.js'
@ -17,7 +10,7 @@ import cors from 'cors'
import express from 'express'
import { activityPubContextify } from '../../helpers/activity-pub-utils.js'
import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../../initializers/constants.js'
import { audiencify, getAudience } from '../../lib/activitypub/audience.js'
import { audiencify, getPlaylistAudience, getPublicAudience, getVideoAudience } from '../../lib/activitypub/audience.js'
import { buildAnnounceWithVideoAudience, buildApprovalActivity, buildLikeActivity } from '../../lib/activitypub/send/index.js'
import { buildCreateActivity } from '../../lib/activitypub/send/send-create.js'
import { buildDislikeActivity } from '../../lib/activitypub/send/send-dislike.js'
@ -330,7 +323,7 @@ async function videoController (req: express.Request, res: express.Response) {
// We need captions to render AP object
const videoAP = await video.lightAPToFullAP(undefined)
const audience = getAudience(videoAP.VideoChannel.Account.Actor, videoAP.privacy === VideoPrivacy.PUBLIC)
const audience = getVideoAudience(videoAP.VideoChannel.Account.Actor, videoAP.privacy)
const videoObject = audiencify(await videoAP.toActivityPubObject(), audience)
if (req.path.endsWith('/activity')) {
@ -434,11 +427,10 @@ async function videoCommentController (req: express.Request, res: express.Respon
const threadParentComments = await VideoCommentModel.listThreadParentComments({ comment: videoComment })
const isPublic = true // Comments are always public
let videoCommentObject = videoComment.toActivityPubObject(threadParentComments)
if (videoComment.Account) {
const audience = getAudience(videoComment.Account.Actor, isPublic)
const audience = getPublicAudience(videoComment.Account.Actor)
videoCommentObject = audiencify(videoCommentObject, audience)
if (req.path.endsWith('/activity')) {
@ -482,7 +474,7 @@ async function videoRedundancyController (req: express.Request, res: express.Res
const serverActor = await getServerActor()
const audience = getAudience(serverActor)
const audience = getPublicAudience(serverActor)
const object = audiencify(videoRedundancy.toActivityPubObject(), audience)
if (req.path.endsWith('/activity')) {
@ -502,7 +494,7 @@ async function videoPlaylistController (req: express.Request, res: express.Respo
playlist.OwnerAccount = await AccountModel.load(playlist.ownerAccountId)
const json = await playlist.toActivityPubObject(req.query.page, null)
const audience = getAudience(playlist.OwnerAccount.Actor, playlist.privacy === VideoPlaylistPrivacy.PUBLIC)
const audience = getPlaylistAudience(playlist.OwnerAccount.Actor, playlist.privacy)
const object = audiencify(json, audience)
return activityPubResponse(activityPubContextify(object, 'Playlist', getContextFilter()), res)

View file

@ -1,11 +1,11 @@
import { Activity, VideoPrivacy } from '@peertube/peertube-models'
import { Activity } from '@peertube/peertube-models'
import { activityPubContextify } from '@server/helpers/activity-pub-utils.js'
import { activityPubCollectionPagination } from '@server/lib/activitypub/collection.js'
import { getContextFilter } from '@server/lib/activitypub/context.js'
import { MActorLight } from '@server/types/models/index.js'
import express from 'express'
import { logger } from '../../helpers/logger.js'
import { buildAudience } from '../../lib/activitypub/audience.js'
import { getVideoAudience } from '../../lib/activitypub/audience.js'
import { buildAnnounceActivity, buildCreateActivity } from '../../lib/activitypub/send/index.js'
import {
accountHandleGetValidatorFactory,
@ -62,7 +62,7 @@ async function buildActivities (actor: MActorLight, start: number, count: number
for (const video of data.data) {
const byActor = video.VideoChannel.Account.Actor
const createActivityAudience = buildAudience([ byActor.followersUrl ], video.privacy === VideoPrivacy.PUBLIC)
const createActivityAudience = getVideoAudience(byActor, video.privacy)
// This is a shared video
if (video.VideoShares !== undefined && video.VideoShares.length !== 0) {

View file

@ -54,10 +54,10 @@ export function getAPPublicValue (): 'https://www.w3.org/ns/activitystreams#Publ
return 'https://www.w3.org/ns/activitystreams#Public'
}
export function hasAPPublic (toOrCC: string[] | string) {
export function hasAPPublic (collection: string[] | string) {
const publicValue = getAPPublicValue()
return arrayify(toOrCC).some(f => f === 'as:Public' || publicValue)
return arrayify(collection).some(f => f === 'as:Public' || publicValue)
}
// ---------------------------------------------------------------------------

View file

@ -24,7 +24,7 @@ function sanitizeAndCheckVideoCommentObject (comment: VideoCommentObject | Activ
isDateValid(comment.published) &&
isActivityPubUrlValid(comment.url) &&
(!exists(comment.replyApproval) || isActivityPubUrlValid(comment.replyApproval)) &&
(hasAPPublic(comment.to) || hasAPPublic(comment.cc)) // Only accept public comments
(hasAPPublic(comment.to) || hasAPPublic(comment.cc)) // Only accept public or unlisted comments
}
// ---------------------------------------------------------------------------

View file

@ -1,26 +1,57 @@
import { ActivityAudience } from '@peertube/peertube-models'
import { ActivityAudience, VideoPlaylistPrivacy, VideoPlaylistPrivacyType, VideoPrivacy, VideoPrivacyType } from '@peertube/peertube-models'
import { getAPPublicValue } from '@server/helpers/activity-pub-utils.js'
import { MActorFollowersUrl } from '../../types/models/index.js'
export function getAudience (actorSender: MActorFollowersUrl, isPublic = true) {
return buildAudience([ actorSender.followersUrl ], isPublic)
export function getPublicAudience (actorSender: MActorFollowersUrl) {
return buildAudience([ actorSender.followersUrl ], 'public')
}
export function buildAudience (followerUrls: string[], isPublic = true) {
export function getVideoAudience (actorSender: MActorFollowersUrl, privacy: VideoPrivacyType, options: {
skipPrivacyCheck?: boolean // default false
} = {}) {
const { skipPrivacyCheck = false } = options
const followerUrls = [ actorSender.followersUrl ]
if (privacy === VideoPrivacy.PUBLIC) return buildAudience(followerUrls, 'public')
else if (privacy === VideoPrivacy.UNLISTED) return buildAudience(followerUrls, 'unlisted')
if (skipPrivacyCheck) return buildAudience(followerUrls, 'private')
throw new Error(`Cannot get audience of non public/unlisted video privacy type (${privacy})`)
}
export function getPlaylistAudience (actorSender: MActorFollowersUrl, privacy: VideoPlaylistPrivacyType) {
const followerUrls = [ actorSender.followersUrl ]
if (privacy === VideoPlaylistPrivacy.PUBLIC) return buildAudience(followerUrls, 'public')
else if (privacy === VideoPlaylistPrivacy.UNLISTED) return buildAudience(followerUrls, 'unlisted')
throw new Error(`Cannot get audience of non public/unlisted playlist privacy type (${privacy})`)
}
export function audiencify<T> (object: T, audience: ActivityAudience) {
return { ...audience, ...object }
}
// ---------------------------------------------------------------------------
// Private
// ---------------------------------------------------------------------------
function buildAudience (followerUrls: string[], type: 'public' | 'unlisted' | 'private') {
let to: string[] = []
let cc: string[] = []
if (isPublic) {
if (type === 'public') {
to = [ getAPPublicValue() ]
cc = followerUrls
} else { // Unlisted
} else if (type === 'unlisted') {
to = []
cc = [ getAPPublicValue() ]
} else {
to = []
cc = []
}
return { to, cc }
}
export function audiencify<T> (object: T, audience: ActivityAudience) {
return { ...audience, ...object }
}

View file

@ -3,7 +3,7 @@ import { ActivityAnnounce, ActivityAudience } from '@peertube/peertube-models'
import { logger } from '../../../helpers/logger.js'
import { MActorLight, MVideo } from '../../../types/models/index.js'
import { MVideoShare } from '../../../types/models/video/index.js'
import { audiencify, getAudience } from '../audience.js'
import { audiencify, getPublicAudience } from '../audience.js'
import { getActorsInvolvedInVideo, getAudienceFromFollowersOf } from './shared/index.js'
import { broadcastToFollowers } from './shared/send-utils.js'
@ -39,7 +39,7 @@ async function sendVideoAnnounce (byActor: MActorLight, videoShare: MVideoShare,
}
function buildAnnounceActivity (url: string, byActor: MActorLight, object: string, audience?: ActivityAudience): ActivityAnnounce {
if (!audience) audience = getAudience(byActor)
if (!audience) audience = getPublicAudience(byActor)
return audiencify({
type: 'Announce' as 'Announce',

View file

@ -4,8 +4,7 @@ import {
ActivityCreateObject,
ContextType,
VideoCommentObject,
VideoPlaylistPrivacy,
VideoPrivacy
VideoPlaylistPrivacy
} from '@peertube/peertube-models'
import { AccountModel } from '@server/models/account/account.js'
import { getServerActor } from '@server/models/application/application.js'
@ -17,11 +16,12 @@ import {
MActorLight,
MCommentOwnerVideoReply,
MLocalVideoViewerWithWatchSections,
MVideoAP, MVideoAccountLight,
MVideoAP,
MVideoAccountLight,
MVideoPlaylistFull,
MVideoRedundancyStreamingPlaylistVideo
} from '../../../types/models/index.js'
import { audiencify, getAudience } from '../audience.js'
import { audiencify, getPlaylistAudience, getPublicAudience, getVideoAudience } from '../audience.js'
import { canVideoBeFederated } from '../videos/federate.js'
import {
broadcastToActors,
@ -44,7 +44,7 @@ export async function sendCreateVideo (video: MVideoAP, transaction: Transaction
const byActor = video.VideoChannel.Account.Actor
const videoObject = await video.toActivityPubObject()
const audience = getAudience(byActor, video.privacy === VideoPrivacy.PUBLIC)
const audience = getVideoAudience(byActor, video.privacy)
const createActivity = buildCreateActivity(video.url, byActor, videoObject, audience)
return broadcastToFollowers({
@ -90,7 +90,7 @@ export async function sendCreateVideoPlaylist (playlist: MVideoPlaylistFull, tra
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 audience = getPlaylistAudience(byActor, playlist.privacy)
const object = await playlist.toActivityPubObject(null, transaction)
const createActivity = buildCreateActivity(playlist.url, byActor, object, audience)
@ -139,7 +139,7 @@ export async function sendCreateVideoCommentIfNeeded (comment: MCommentOwnerVide
actorsInvolvedInComment.push(byActor)
const parentsCommentActors = threadParentComments.filter(c => !c.isDeleted() && !c.heldForReview)
.map(c => c.Account.Actor)
.map(c => c.Account.Actor)
let audience: ActivityAudience
if (isOrigin) {
@ -193,13 +193,13 @@ export async function sendCreateVideoCommentIfNeeded (comment: MCommentOwnerVide
})
}
export function buildCreateActivity <T extends ActivityCreateObject> (
export function buildCreateActivity<T extends ActivityCreateObject> (
url: string,
byActor: MActorLight,
object: T,
audience?: ActivityAudience
): ActivityCreate<T> {
if (!audience) audience = getAudience(byActor)
if (!audience) audience = getPublicAudience(byActor)
return audiencify(
{

View file

@ -2,7 +2,7 @@ import { Transaction } from 'sequelize'
import { ActivityAudience, ActivityDislike } from '@peertube/peertube-models'
import { logger } from '../../../helpers/logger.js'
import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../types/models/index.js'
import { audiencify, getAudience } from '../audience.js'
import { audiencify, getPublicAudience } from '../audience.js'
import { getVideoDislikeActivityPubUrlByLocalActor } from '../url.js'
import { sendVideoActivityToOrigin } from './shared/send-utils.js'
@ -19,7 +19,7 @@ function sendDislike (byActor: MActor, video: MVideoAccountLight, transaction: T
}
function buildDislikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityDislike {
if (!audience) audience = getAudience(byActor)
if (!audience) audience = getPublicAudience(byActor)
return audiencify(
{

View file

@ -2,7 +2,7 @@ import { Transaction } from 'sequelize'
import { ActivityAudience, ActivityFlag } from '@peertube/peertube-models'
import { logger } from '../../../helpers/logger.js'
import { MAbuseAP, MAccountLight, MActor } from '../../../types/models/index.js'
import { audiencify, getAudience } from '../audience.js'
import { audiencify, getPublicAudience } from '../audience.js'
import { getLocalAbuseActivityPubUrl } from '../url.js'
import { unicastTo } from './shared/send-utils.js'
@ -28,7 +28,7 @@ function sendAbuse (byActor: MActor, abuse: MAbuseAP, flaggedAccount: MAccountLi
}
function buildFlagActivity (url: string, byActor: MActor, abuse: MAbuseAP, audience: ActivityAudience): ActivityFlag {
if (!audience) audience = getAudience(byActor)
if (!audience) audience = getPublicAudience(byActor)
const activity = { id: url, actor: byActor.url, ...abuse.toActivityPubObject() }

View file

@ -2,7 +2,7 @@ import { Transaction } from 'sequelize'
import { ActivityAudience, ActivityLike } from '@peertube/peertube-models'
import { logger } from '../../../helpers/logger.js'
import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../types/models/index.js'
import { audiencify, getAudience } from '../audience.js'
import { audiencify, getPublicAudience } from '../audience.js'
import { getVideoLikeActivityPubUrlByLocalActor } from '../url.js'
import { sendVideoActivityToOrigin } from './shared/send-utils.js'
@ -19,7 +19,7 @@ function sendLike (byActor: MActor, video: MVideoAccountLight, transaction: Tran
}
function buildLikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityLike {
if (!audience) audience = getAudience(byActor)
if (!audience) audience = getPublicAudience(byActor)
return audiencify(
{

View file

@ -12,7 +12,7 @@ import {
MVideoRedundancyVideo,
MVideoShare
} from '../../../types/models/index.js'
import { audiencify, getAudience } from '../audience.js'
import { audiencify, getPublicAudience } from '../audience.js'
import { getUndoActivityPubUrl, getVideoDislikeActivityPubUrlByLocalActor, getVideoLikeActivityPubUrlByLocalActor } from '../url.js'
import { buildAnnounceWithVideoAudience } from './send-announce.js'
import { buildCreateActivity } from './send-create.js'
@ -119,13 +119,13 @@ export {
// ---------------------------------------------------------------------------
function undoActivityData <T extends ActivityUndoObject> (
function undoActivityData<T extends ActivityUndoObject> (
url: string,
byActor: MActorAudience,
object: T,
audience?: ActivityAudience
): ActivityUndo<T> {
if (!audience) audience = getAudience(byActor)
if (!audience) audience = getPublicAudience(byActor)
return audiencify(
{

View file

@ -1,4 +1,4 @@
import { ActivityAudience, ActivityUpdate, ActivityUpdateObject, VideoPlaylistPrivacy, VideoPrivacy } from '@peertube/peertube-models'
import { ActivityAudience, ActivityUpdate, ActivityUpdateObject, VideoPlaylistPrivacy } from '@peertube/peertube-models'
import { getServerActor } from '@server/models/application/application.js'
import { Transaction } from 'sequelize'
import { logger } from '../../../helpers/logger.js'
@ -14,7 +14,7 @@ import {
MVideoPlaylistFull,
MVideoRedundancyVideo
} from '../../../types/models/index.js'
import { audiencify, getAudience } from '../audience.js'
import { audiencify, getPlaylistAudience, getPublicAudience, getVideoAudience } from '../audience.js'
import { getUpdateActivityPubUrl } from '../url.js'
import { canVideoBeFederated } from '../videos/federate.js'
import { getActorsInvolvedInVideo } from './shared/index.js'
@ -32,7 +32,7 @@ export async function sendUpdateVideo (videoArg: MVideoAPLight, transaction: Tra
const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString())
const videoObject = await video.toActivityPubObject()
const audience = getAudience(byActor, video.privacy === VideoPrivacy.PUBLIC)
const audience = getVideoAudience(byActor, video.privacy)
const updateActivity = buildUpdateActivity(url, byActor, videoObject, audience)
@ -55,7 +55,7 @@ export async function sendUpdateActor (accountOrChannel: MChannelDefault | MAcco
const url = getUpdateActivityPubUrl(byActor.url, byActor.updatedAt.toISOString())
const accountOrChannelObject = await (accountOrChannel as any).toActivityPubObject() // FIXME: typescript bug?
const audience = getAudience(byActor)
const audience = getPublicAudience(byActor)
const updateActivity = buildUpdateActivity(url, byActor, accountOrChannelObject, audience)
let actorsInvolved: MActor[]
@ -109,7 +109,7 @@ export async function sendUpdateVideoPlaylist (videoPlaylist: MVideoPlaylistFull
const url = getUpdateActivityPubUrl(videoPlaylist.url, videoPlaylist.updatedAt.toISOString())
const object = await videoPlaylist.toActivityPubObject(null, transaction)
const audience = getAudience(byActor, videoPlaylist.privacy === VideoPlaylistPrivacy.PUBLIC)
const audience = getPlaylistAudience(byActor, videoPlaylist.privacy)
const updateActivity = buildUpdateActivity(url, byActor, object, audience)
@ -137,7 +137,7 @@ function buildUpdateActivity (
object: ActivityUpdateObject,
audience?: ActivityAudience
): ActivityUpdate<ActivityUpdateObject> {
if (!audience) audience = getAudience(byActor)
if (!audience) audience = getPublicAudience(byActor)
return audiencify(
{

View file

@ -3,7 +3,7 @@ import { VideoViewsManager } from '@server/lib/views/video-views-manager.js'
import { MActorAudience, MActorLight, MVideoImmutable, MVideoUrl } from '@server/types/models/index.js'
import { Transaction } from 'sequelize'
import { logger } from '../../../helpers/logger.js'
import { audiencify, getAudience } from '../audience.js'
import { audiencify, getPublicAudience } from '../audience.js'
import { getLocalVideoViewActivityPubUrl } from '../url.js'
import { sendVideoRelatedActivity } from './shared/send-utils.js'
@ -42,7 +42,7 @@ function buildViewActivity (options: {
viewersCount?: number
audience?: ActivityAudience
}): ActivityView {
const { url, byActor, viewersCount, video, audience = getAudience(byActor) } = options
const { url, byActor, viewersCount, video, audience = getPublicAudience(byActor) } = options
const base = {
id: url,

View file

@ -1,13 +1,12 @@
import { AbstractUserExporter } from './abstract-user-exporter.js'
import { MCommentExport } from '@server/types/models/index.js'
import { CommentsExportJSON, VideoCommentObject } from '@peertube/peertube-models'
import { VideoCommentModel } from '@server/models/video/video-comment.js'
import Bluebird from 'bluebird'
import { audiencify, getAudience } from '@server/lib/activitypub/audience.js'
import { audiencify, getPublicAudience } from '@server/lib/activitypub/audience.js'
import { buildCreateActivity } from '@server/lib/activitypub/send/send-create.js'
import { VideoCommentModel } from '@server/models/video/video-comment.js'
import { MCommentExport } from '@server/types/models/index.js'
import Bluebird from 'bluebird'
import { AbstractUserExporter } from './abstract-user-exporter.js'
export class CommentsExporter extends AbstractUserExporter <CommentsExportJSON> {
export class CommentsExporter extends AbstractUserExporter<CommentsExportJSON> {
async export () {
const comments = await VideoCommentModel.listForExport(this.user.Account.id)
@ -39,8 +38,7 @@ export class CommentsExporter extends AbstractUserExporter <CommentsExportJSON>
const threadParentComments = await VideoCommentModel.listThreadParentComments({ comment })
let commentObject = comment.toActivityPubObject(threadParentComments) as VideoCommentObject
const isPublic = true // Comments are always public
const audience = getAudience(comment.Account.Actor, isPublic)
const audience = getPublicAudience(comment.Account.Actor)
commentObject = audiencify(commentObject, audience)

View file

@ -2,7 +2,7 @@ import { pick } from '@peertube/peertube-core-utils'
import { ActivityCreate, FileStorage, VideoCommentPolicy, VideoExportJSON, VideoObject, VideoPrivacy } from '@peertube/peertube-models'
import { logger } from '@server/helpers/logger.js'
import { USER_EXPORT_MAX_ITEMS } from '@server/initializers/constants.js'
import { audiencify, getAudience } from '@server/lib/activitypub/audience.js'
import { audiencify, getVideoAudience } from '@server/lib/activitypub/audience.js'
import { buildCreateActivity } from '@server/lib/activitypub/send/send-create.js'
import { buildChaptersAPHasPart } from '@server/lib/activitypub/video-chapters.js'
import {
@ -266,7 +266,7 @@ export class VideosExporter extends AbstractUserExporter<VideoExportJSON> {
): Promise<ActivityCreate<VideoObject>> {
const icon = video.getPreview()
const audience = getAudience(video.VideoChannel.Account.Actor, video.privacy === VideoPrivacy.PUBLIC)
const audience = getVideoAudience(video.VideoChannel.Account.Actor, video.privacy, { skipPrivacyCheck: true })
const videoObject = {
...audiencify(await video.toActivityPubObject(), audience),