Status are sent to mastodon
This commit is contained in:
parent
ce33ee01cd
commit
e12a009254
|
@ -1,8 +1,8 @@
|
|||
import * as validator from 'validator'
|
||||
import { CONSTRAINTS_FIELDS } from '../../../initializers'
|
||||
import { isAccountNameValid } from '../accounts'
|
||||
import { exists, isUUIDValid } from '../misc'
|
||||
import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels'
|
||||
import { exists } from '../misc'
|
||||
import { isVideoChannelNameValid } from '../video-channels'
|
||||
import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc'
|
||||
|
||||
function isActorEndpointsObjectValid (endpointObject: any) {
|
||||
|
@ -23,41 +23,39 @@ function isActorPublicKeyValid (publicKey: string) {
|
|||
return exists(publicKey) &&
|
||||
typeof publicKey === 'string' &&
|
||||
publicKey.startsWith('-----BEGIN PUBLIC KEY-----') &&
|
||||
publicKey.endsWith('-----END PUBLIC KEY-----') &&
|
||||
publicKey.indexOf('-----END PUBLIC KEY-----') !== -1 &&
|
||||
validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY)
|
||||
}
|
||||
|
||||
const actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+')
|
||||
function isActorPreferredUsernameValid (preferredUsername: string) {
|
||||
return isAccountNameValid(preferredUsername) || isVideoChannelNameValid(preferredUsername)
|
||||
return exists(preferredUsername) && validator.matches(preferredUsername, actorNameRegExp)
|
||||
}
|
||||
|
||||
const actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+')
|
||||
function isActorNameValid (name: string) {
|
||||
return exists(name) && validator.matches(name, actorNameRegExp)
|
||||
return isAccountNameValid(name) || isVideoChannelNameValid(name)
|
||||
}
|
||||
|
||||
function isActorPrivateKeyValid (privateKey: string) {
|
||||
return exists(privateKey) &&
|
||||
typeof privateKey === 'string' &&
|
||||
privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') &&
|
||||
privateKey.endsWith('-----END RSA PRIVATE KEY-----') &&
|
||||
// Sometimes there is a \n at the end, so just assert the string contains the end mark
|
||||
privateKey.indexOf('-----END RSA PRIVATE KEY-----') !== -1 &&
|
||||
validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY)
|
||||
}
|
||||
|
||||
function isRemoteActorValid (remoteActor: any) {
|
||||
return isActivityPubUrlValid(remoteActor.id) &&
|
||||
isUUIDValid(remoteActor.uuid) &&
|
||||
isActorTypeValid(remoteActor.type) &&
|
||||
isActivityPubUrlValid(remoteActor.following) &&
|
||||
isActivityPubUrlValid(remoteActor.followers) &&
|
||||
isActivityPubUrlValid(remoteActor.inbox) &&
|
||||
isActivityPubUrlValid(remoteActor.outbox) &&
|
||||
isActorNameValid(remoteActor.name) &&
|
||||
isActorPreferredUsernameValid(remoteActor.preferredUsername) &&
|
||||
isActivityPubUrlValid(remoteActor.url) &&
|
||||
isActorPublicKeyObjectValid(remoteActor.publicKey) &&
|
||||
isActorEndpointsObjectValid(remoteActor.endpoints) &&
|
||||
(!remoteActor.summary || isVideoChannelDescriptionValid(remoteActor.summary)) &&
|
||||
setValidAttributedTo(remoteActor) &&
|
||||
// If this is not an account, it should be attributed to an account
|
||||
// In PeerTube we use this to attach a video channel to a specific account
|
||||
|
|
|
@ -316,7 +316,7 @@ const CACHE = {
|
|||
}
|
||||
}
|
||||
|
||||
const ACCEPT_HEADERS = ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS.concat('html', 'application/json')
|
||||
const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ async function up (utils: {
|
|||
id integer NOT NULL,
|
||||
type enum_actor_type NOT NULL,
|
||||
uuid uuid NOT NULL,
|
||||
name character varying(255) NOT NULL,
|
||||
"preferredUsername" character varying(255) NOT NULL,
|
||||
url character varying(2000) NOT NULL,
|
||||
"publicKey" character varying(5000),
|
||||
"privateKey" character varying(5000),
|
||||
|
@ -50,7 +50,7 @@ async function up (utils: {
|
|||
`ALTER SEQUENCE actor_id_seq OWNED BY actor.id`,
|
||||
`ALTER TABLE ONLY actor ALTER COLUMN id SET DEFAULT nextval('actor_id_seq'::regclass)`,
|
||||
`ALTER TABLE ONLY actor ADD CONSTRAINT actor_pkey PRIMARY KEY (id);`,
|
||||
`CREATE UNIQUE INDEX actor_name_server_id ON actor USING btree (name, "serverId")`,
|
||||
`CREATE UNIQUE INDEX actor_preferred_username_server_id ON actor USING btree ("preferredUsername", "serverId")`,
|
||||
`ALTER TABLE ONLY actor
|
||||
ADD CONSTRAINT "actor_avatarId_fkey" FOREIGN KEY ("avatarId") REFERENCES avatar(id) ON UPDATE CASCADE ON DELETE CASCADE`,
|
||||
`ALTER TABLE ONLY actor
|
||||
|
@ -68,7 +68,7 @@ async function up (utils: {
|
|||
`
|
||||
INSERT INTO "actor"
|
||||
(
|
||||
type, uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
|
||||
type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
|
||||
"sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
|
||||
)
|
||||
SELECT
|
||||
|
@ -83,7 +83,7 @@ async function up (utils: {
|
|||
`
|
||||
INSERT INTO "actor"
|
||||
(
|
||||
type, uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
|
||||
type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
|
||||
"sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
|
||||
)
|
||||
SELECT
|
||||
|
@ -119,7 +119,7 @@ async function up (utils: {
|
|||
const query = `
|
||||
INSERT INTO actor
|
||||
(
|
||||
type, uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
|
||||
type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
|
||||
"sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
|
||||
)
|
||||
SELECT
|
||||
|
|
|
@ -107,7 +107,7 @@ function saveActorAndServerAndModelIfNotExist (
|
|||
|
||||
type FetchRemoteActorResult = {
|
||||
actor: ActorModel
|
||||
preferredUsername: string
|
||||
name: string
|
||||
summary: string
|
||||
attributedTo: ActivityPubAttributedTo[]
|
||||
}
|
||||
|
@ -142,8 +142,8 @@ async function fetchRemoteActor (actorUrl: string): Promise<FetchRemoteActorResu
|
|||
const actor = new ActorModel({
|
||||
type: actorJSON.type,
|
||||
uuid: actorJSON.uuid,
|
||||
name: actorJSON.name,
|
||||
url: actorJSON.url,
|
||||
preferredUsername: actorJSON.preferredUsername,
|
||||
url: actorJSON.id,
|
||||
publicKey: actorJSON.publicKey.publicKeyPem,
|
||||
privateKey: null,
|
||||
followersCount: followersCount,
|
||||
|
@ -155,19 +155,20 @@ async function fetchRemoteActor (actorUrl: string): Promise<FetchRemoteActorResu
|
|||
followingUrl: actorJSON.following
|
||||
})
|
||||
|
||||
const name = actorJSON.name || actorJSON.preferredUsername
|
||||
return {
|
||||
actor,
|
||||
preferredUsername: actorJSON.preferredUsername,
|
||||
name,
|
||||
summary: actorJSON.summary,
|
||||
attributedTo: actorJSON.attributedTo
|
||||
}
|
||||
}
|
||||
|
||||
function buildActorInstance (type: ActivityPubActorType, url: string, name: string, uuid?: string) {
|
||||
function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) {
|
||||
return new ActorModel({
|
||||
type,
|
||||
url,
|
||||
name,
|
||||
preferredUsername,
|
||||
uuid,
|
||||
publicKey: null,
|
||||
privateKey: null,
|
||||
|
@ -210,7 +211,7 @@ async function fetchActorTotalItems (url: string) {
|
|||
|
||||
function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t: Transaction) {
|
||||
const account = new AccountModel({
|
||||
name: result.preferredUsername,
|
||||
name: result.name,
|
||||
actorId: actor.id
|
||||
})
|
||||
|
||||
|
@ -219,7 +220,7 @@ function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t: Tran
|
|||
|
||||
async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResult, ownerActor: ActorModel, t: Transaction) {
|
||||
const videoChannel = new VideoChannelModel({
|
||||
name: result.preferredUsername,
|
||||
name: result.name,
|
||||
description: result.summary,
|
||||
actorId: actor.id,
|
||||
accountId: ownerActor.Account.id
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Transaction } from 'sequelize'
|
||||
import { Activity } from '../../../../shared/models/activitypub'
|
||||
import { Activity, ActivityAudience } from '../../../../shared/models/activitypub'
|
||||
import { logger } from '../../../helpers'
|
||||
import { ACTIVITY_PUB } from '../../../initializers'
|
||||
import { ActorModel } from '../../../models/activitypub/actor'
|
||||
|
@ -116,6 +116,10 @@ async function getAudience (actorSender: ActorModel, t: Transaction, isPublic =
|
|||
return { to, cc }
|
||||
}
|
||||
|
||||
function audiencify (object: any, audience: ActivityAudience) {
|
||||
return Object.assign(object, audience)
|
||||
}
|
||||
|
||||
async function computeFollowerUris (toActorFollower: ActorModel[], followersException: ActorModel[], t: Transaction) {
|
||||
const toActorFollowerIds = toActorFollower.map(a => a.id)
|
||||
|
||||
|
@ -133,5 +137,6 @@ export {
|
|||
getOriginVideoAudience,
|
||||
getActorsInvolvedInVideo,
|
||||
getObjectFollowersAudience,
|
||||
forwardActivity
|
||||
forwardActivity,
|
||||
audiencify
|
||||
}
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
import { Transaction } from 'sequelize'
|
||||
import { ActivityAccept } from '../../../../shared/models/activitypub'
|
||||
import { ActivityAccept, ActivityFollow } from '../../../../shared/models/activitypub'
|
||||
import { ActorModel } from '../../../models/activitypub/actor'
|
||||
import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
|
||||
import { getActorFollowAcceptActivityPubUrl } from '../url'
|
||||
import { getActorFollowAcceptActivityPubUrl, getActorFollowActivityPubUrl } from '../url'
|
||||
import { unicastTo } from './misc'
|
||||
import { followActivityData } from './send-follow'
|
||||
|
||||
async function sendAccept (actorFollow: ActorFollowModel, t: Transaction) {
|
||||
const follower = actorFollow.ActorFollower
|
||||
const me = actorFollow.ActorFollowing
|
||||
|
||||
const followUrl = getActorFollowActivityPubUrl(actorFollow)
|
||||
const followData = followActivityData(followUrl, follower, me)
|
||||
|
||||
const url = getActorFollowAcceptActivityPubUrl(actorFollow)
|
||||
const data = acceptActivityData(url, me)
|
||||
const data = acceptActivityData(url, me, followData)
|
||||
|
||||
return unicastTo(data, me, follower.inboxUrl, t)
|
||||
}
|
||||
|
@ -23,10 +27,11 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function acceptActivityData (url: string, byActor: ActorModel): ActivityAccept {
|
||||
function acceptActivityData (url: string, byActor: ActorModel, followActivityData: ActivityFollow): ActivityAccept {
|
||||
return {
|
||||
type: 'Accept',
|
||||
id: url,
|
||||
actor: byActor.url
|
||||
actor: byActor.url,
|
||||
object: followActivityData
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { VideoModel } from '../../../models/video/video'
|
|||
import { VideoAbuseModel } from '../../../models/video/video-abuse'
|
||||
import { getVideoAbuseActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoViewActivityPubUrl } from '../url'
|
||||
import {
|
||||
audiencify,
|
||||
broadcastToFollowers,
|
||||
getActorsInvolvedInVideo,
|
||||
getAudience,
|
||||
|
@ -16,9 +17,11 @@ import {
|
|||
} from './misc'
|
||||
|
||||
async function sendCreateVideo (video: VideoModel, t: Transaction) {
|
||||
const byActor = video.VideoChannel.Account.Actor
|
||||
if (video.privacy === VideoPrivacy.PRIVATE) return
|
||||
|
||||
const byActor = video.VideoChannel.Account.Actor
|
||||
const videoObject = video.toActivityPubObject()
|
||||
|
||||
const audience = await getAudience(byActor, t, video.privacy === VideoPrivacy.PUBLIC)
|
||||
const data = await createActivityData(video.url, byActor, videoObject, t, audience)
|
||||
|
||||
|
@ -93,14 +96,12 @@ async function createActivityData (
|
|||
audience = await getAudience(byActor, t)
|
||||
}
|
||||
|
||||
return {
|
||||
return audiencify({
|
||||
type: 'Create',
|
||||
id: url,
|
||||
actor: byActor.url,
|
||||
to: audience.to,
|
||||
cc: audience.cc,
|
||||
object
|
||||
}
|
||||
object: audiencify(object, audience)
|
||||
}, audience)
|
||||
}
|
||||
|
||||
function createDislikeActivityData (byActor: ActorModel, video: VideoModel) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import { ActorModel } from '../../../models/activitypub/actor'
|
|||
import { VideoModel } from '../../../models/video/video'
|
||||
import { getVideoLikeActivityPubUrl } from '../url'
|
||||
import {
|
||||
audiencify,
|
||||
broadcastToFollowers,
|
||||
getActorsInvolvedInVideo,
|
||||
getAudience,
|
||||
|
@ -44,14 +45,12 @@ async function likeActivityData (
|
|||
audience = await getAudience(byActor, t)
|
||||
}
|
||||
|
||||
return {
|
||||
return audiencify({
|
||||
type: 'Like',
|
||||
id: url,
|
||||
actor: byActor.url,
|
||||
to: audience.to,
|
||||
cc: audience.cc,
|
||||
object: video.url
|
||||
}
|
||||
}, audience)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -11,6 +11,7 @@ import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
|
|||
import { VideoModel } from '../../../models/video/video'
|
||||
import { getActorFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url'
|
||||
import {
|
||||
audiencify,
|
||||
broadcastToFollowers,
|
||||
getActorsInvolvedInVideo,
|
||||
getAudience,
|
||||
|
@ -112,12 +113,10 @@ async function undoActivityData (
|
|||
audience = await getAudience(byActor, t)
|
||||
}
|
||||
|
||||
return {
|
||||
return audiencify({
|
||||
type: 'Undo',
|
||||
id: url,
|
||||
actor: byActor.url,
|
||||
to: audience.to,
|
||||
cc: audience.cc,
|
||||
object
|
||||
}
|
||||
}, audience)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import { ActorModel } from '../../../models/activitypub/actor'
|
|||
import { VideoModel } from '../../../models/video/video'
|
||||
import { VideoShareModel } from '../../../models/video/video-share'
|
||||
import { getUpdateActivityPubUrl } from '../url'
|
||||
import { broadcastToFollowers, getAudience } from './misc'
|
||||
import { audiencify, broadcastToFollowers, getAudience } from './misc'
|
||||
|
||||
async function sendUpdateVideo (video: VideoModel, t: Transaction) {
|
||||
const byActor = video.VideoChannel.Account.Actor
|
||||
|
@ -41,12 +41,10 @@ async function updateActivityData (
|
|||
audience = await getAudience(byActor, t)
|
||||
}
|
||||
|
||||
return {
|
||||
return audiencify({
|
||||
type: 'Update',
|
||||
id: url,
|
||||
actor: byActor.url,
|
||||
to: audience.to,
|
||||
cc: audience.cc,
|
||||
object
|
||||
}
|
||||
object: audiencify(object, audience)
|
||||
}, audience)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import { Transaction } from 'sequelize'
|
||||
import { VideoPrivacy } from '../../../shared/models/videos'
|
||||
import { getServerActor } from '../../helpers'
|
||||
import { VideoModel } from '../../models/video/video'
|
||||
import { VideoShareModel } from '../../models/video/video-share'
|
||||
import { sendVideoAnnounceToFollowers } from './send'
|
||||
|
||||
async function shareVideoByServerAndChannel (video: VideoModel, t: Transaction) {
|
||||
if (video.privacy === VideoPrivacy.PRIVATE) return
|
||||
|
||||
const serverActor = await getServerActor()
|
||||
|
||||
const serverShare = VideoShareModel.create({
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
import { doRequest, logger } from '../../../helpers'
|
||||
import { ActivityPubHttpPayload, computeBody, maybeRetryRequestLater } from './activitypub-http-job-scheduler'
|
||||
import { ActivityPubHttpPayload, buildSignedRequestOptions, computeBody, maybeRetryRequestLater } from './activitypub-http-job-scheduler'
|
||||
|
||||
async function process (payload: ActivityPubHttpPayload, jobId: number) {
|
||||
logger.info('Processing ActivityPub broadcast in job %d.', jobId)
|
||||
|
||||
const body = await computeBody(payload)
|
||||
const httpSignatureOptions = await buildSignedRequestOptions(payload)
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
uri: '',
|
||||
json: body
|
||||
json: body,
|
||||
httpSignature: httpSignatureOptions
|
||||
}
|
||||
|
||||
for (const uri of payload.uris) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { JobCategory } from '../../../../shared'
|
||||
import { buildSignedActivity, logger } from '../../../helpers'
|
||||
import { buildSignedActivity, getServerActor, logger } from '../../../helpers'
|
||||
import { ACTIVITY_PUB } from '../../../initializers'
|
||||
import { ActorModel } from '../../../models/activitypub/actor'
|
||||
import { JobHandler, JobScheduler } from '../job-scheduler'
|
||||
|
@ -46,16 +46,36 @@ async function computeBody (payload: ActivityPubHttpPayload) {
|
|||
|
||||
if (payload.signatureActorId) {
|
||||
const actorSignature = await ActorModel.load(payload.signatureActorId)
|
||||
if (!actorSignature) throw new Error('Unknown signature account id.')
|
||||
if (!actorSignature) throw new Error('Unknown signature actor id.')
|
||||
body = await buildSignedActivity(actorSignature, payload.body)
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
async function buildSignedRequestOptions (payload: ActivityPubHttpPayload) {
|
||||
let actor: ActorModel
|
||||
if (payload.signatureActorId) {
|
||||
actor = await ActorModel.load(payload.signatureActorId)
|
||||
if (!actor) throw new Error('Unknown signature actor id.')
|
||||
} else {
|
||||
// We need to sign the request, so use the server
|
||||
actor = await getServerActor()
|
||||
}
|
||||
|
||||
const keyId = actor.getWebfingerUrl()
|
||||
return {
|
||||
algorithm: 'rsa-sha256',
|
||||
authorizationHeaderName: 'Signature',
|
||||
keyId,
|
||||
key: actor.privateKey
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ActivityPubHttpPayload,
|
||||
activitypubHttpJobScheduler,
|
||||
maybeRetryRequestLater,
|
||||
computeBody
|
||||
computeBody,
|
||||
buildSignedRequestOptions
|
||||
}
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
import { doRequest, logger } from '../../../helpers'
|
||||
import { ActivityPubHttpPayload, computeBody, maybeRetryRequestLater } from './activitypub-http-job-scheduler'
|
||||
import { ActivityPubHttpPayload, buildSignedRequestOptions, computeBody, maybeRetryRequestLater } from './activitypub-http-job-scheduler'
|
||||
|
||||
async function process (payload: ActivityPubHttpPayload, jobId: number) {
|
||||
logger.info('Processing ActivityPub unicast in job %d.', jobId)
|
||||
|
||||
const body = await computeBody(payload)
|
||||
const httpSignatureOptions = await buildSignedRequestOptions(payload)
|
||||
|
||||
const uri = payload.uris[0]
|
||||
const options = {
|
||||
method: 'POST',
|
||||
uri,
|
||||
json: body
|
||||
json: body,
|
||||
httpSignature: httpSignatureOptions
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import * as Bluebird from 'bluebird'
|
||||
import { VideoPrivacy } from '../../../../shared/models/videos'
|
||||
import { computeResolutionsToTranscode, logger } from '../../../helpers'
|
||||
import { sequelizeTypescript } from '../../../initializers'
|
||||
import { VideoModel } from '../../../models/video/video'
|
||||
|
@ -35,9 +36,11 @@ async function onSuccess (jobId: number, video: VideoModel, jobScheduler: JobSch
|
|||
// Video does not exist anymore
|
||||
if (!videoDatabase) return undefined
|
||||
|
||||
if (video.privacy !== VideoPrivacy.PRIVATE) {
|
||||
// Now we'll add the video's meta data to our followers
|
||||
await sendCreateVideo(video, undefined)
|
||||
await shareVideoByServerAndChannel(video, undefined)
|
||||
}
|
||||
|
||||
const originalFileHeight = await videoDatabase.getOriginalFileHeight()
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { VideoResolution } from '../../../../shared'
|
||||
import { VideoPrivacy } from '../../../../shared/models/videos'
|
||||
import { logger } from '../../../helpers'
|
||||
import { VideoModel } from '../../../models/video/video'
|
||||
import { sendUpdateVideo } from '../../activitypub/send'
|
||||
|
@ -31,7 +32,9 @@ async function onSuccess (jobId: number, video: VideoModel) {
|
|||
// Video does not exist anymore
|
||||
if (!videoDatabase) return undefined
|
||||
|
||||
if (video.privacy !== VideoPrivacy.PRIVATE) {
|
||||
await sendUpdateVideo(video, undefined)
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
|
|
@ -9,11 +9,13 @@ import { ActorModel } from '../models/activitypub/actor'
|
|||
async function checkSignature (req: Request, res: Response, next: NextFunction) {
|
||||
const signatureObject: ActivityPubSignature = req.body.signature
|
||||
|
||||
logger.debug('Checking signature of actor %s...', signatureObject.creator)
|
||||
const [ creator ] = signatureObject.creator.split('#')
|
||||
|
||||
logger.debug('Checking signature of actor %s...', creator)
|
||||
|
||||
let actor: ActorModel
|
||||
try {
|
||||
actor = await getOrCreateActorAndServerAndModel(signatureObject.creator)
|
||||
actor = await getOrCreateActorAndServerAndModel(creator)
|
||||
} catch (err) {
|
||||
logger.error('Cannot create remote actor and check signature.', err)
|
||||
return res.sendStatus(403)
|
||||
|
@ -32,6 +34,7 @@ async function checkSignature (req: Request, res: Response, next: NextFunction)
|
|||
function executeIfActivityPub (fun: RequestHandler | RequestHandler[]) {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
const accepted = req.accepts(ACCEPT_HEADERS)
|
||||
console.log(accepted)
|
||||
if (accepted === false || ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS.indexOf(accepted) === -1) {
|
||||
return next()
|
||||
}
|
||||
|
|
|
@ -2,32 +2,15 @@ import { values } from 'lodash'
|
|||
import { join } from 'path'
|
||||
import * as Sequelize from 'sequelize'
|
||||
import {
|
||||
AllowNull,
|
||||
BelongsTo,
|
||||
Column,
|
||||
CreatedAt,
|
||||
DataType,
|
||||
Default, DefaultScope,
|
||||
ForeignKey,
|
||||
HasMany,
|
||||
HasOne,
|
||||
Is,
|
||||
IsUUID,
|
||||
Model,
|
||||
Scopes,
|
||||
Table,
|
||||
UpdatedAt
|
||||
AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, DefaultScope, ForeignKey, HasMany, HasOne, Is, IsUUID, Model, Scopes,
|
||||
Table, UpdatedAt
|
||||
} from 'sequelize-typescript'
|
||||
import { ActivityPubActorType } from '../../../shared/models/activitypub'
|
||||
import { Avatar } from '../../../shared/models/avatars/avatar.model'
|
||||
import { activityPubContextify } from '../../helpers'
|
||||
import {
|
||||
isActivityPubUrlValid,
|
||||
isActorFollowersCountValid,
|
||||
isActorFollowingCountValid,
|
||||
isActorNameValid,
|
||||
isActorPrivateKeyValid,
|
||||
isActorPublicKeyValid
|
||||
isActivityPubUrlValid, isActorFollowersCountValid, isActorFollowingCountValid, isActorPreferredUsernameValid,
|
||||
isActorPrivateKeyValid, isActorPublicKeyValid
|
||||
} from '../../helpers/custom-validators/activitypub'
|
||||
import { ACTIVITY_PUB_ACTOR_TYPES, AVATARS_DIR, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers'
|
||||
import { AccountModel } from '../account/account'
|
||||
|
@ -71,7 +54,7 @@ enum ScopeNames {
|
|||
tableName: 'actor',
|
||||
indexes: [
|
||||
{
|
||||
fields: [ 'name', 'serverId' ],
|
||||
fields: [ 'preferredUsername', 'serverId' ],
|
||||
unique: true
|
||||
}
|
||||
]
|
||||
|
@ -89,9 +72,9 @@ export class ActorModel extends Model<ActorModel> {
|
|||
uuid: string
|
||||
|
||||
@AllowNull(false)
|
||||
@Is('ActorName', value => throwIfNotValid(value, isActorNameValid, 'actor name'))
|
||||
@Is('ActorPreferredUsername', value => throwIfNotValid(value, isActorPreferredUsernameValid, 'actor preferred username'))
|
||||
@Column
|
||||
name: string
|
||||
preferredUsername: string
|
||||
|
||||
@AllowNull(false)
|
||||
@Is('ActorUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
|
||||
|
@ -212,16 +195,6 @@ export class ActorModel extends Model<ActorModel> {
|
|||
return ActorModel.scope(ScopeNames.FULL).findById(id)
|
||||
}
|
||||
|
||||
static loadByUUID (uuid: string) {
|
||||
const query = {
|
||||
where: {
|
||||
uuid
|
||||
}
|
||||
}
|
||||
|
||||
return ActorModel.scope(ScopeNames.FULL).findOne(query)
|
||||
}
|
||||
|
||||
static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) {
|
||||
const query = {
|
||||
where: {
|
||||
|
@ -235,10 +208,10 @@ export class ActorModel extends Model<ActorModel> {
|
|||
return ActorModel.scope(ScopeNames.FULL).findAll(query)
|
||||
}
|
||||
|
||||
static loadLocalByName (name: string) {
|
||||
static loadLocalByName (preferredUsername: string) {
|
||||
const query = {
|
||||
where: {
|
||||
name,
|
||||
preferredUsername,
|
||||
serverId: null
|
||||
}
|
||||
}
|
||||
|
@ -246,10 +219,10 @@ export class ActorModel extends Model<ActorModel> {
|
|||
return ActorModel.scope(ScopeNames.FULL).findOne(query)
|
||||
}
|
||||
|
||||
static loadByNameAndHost (name: string, host: string) {
|
||||
static loadByNameAndHost (preferredUsername: string, host: string) {
|
||||
const query = {
|
||||
where: {
|
||||
name
|
||||
preferredUsername
|
||||
},
|
||||
include: [
|
||||
{
|
||||
|
@ -286,17 +259,15 @@ export class ActorModel extends Model<ActorModel> {
|
|||
}
|
||||
}
|
||||
|
||||
let host = CONFIG.WEBSERVER.HOST
|
||||
let score: number
|
||||
if (this.Server) {
|
||||
host = this.Server.host
|
||||
score = this.Server.score
|
||||
}
|
||||
|
||||
return {
|
||||
id: this.id,
|
||||
uuid: this.uuid,
|
||||
host,
|
||||
host: this.getHost(),
|
||||
score,
|
||||
followingCount: this.followingCount,
|
||||
followersCount: this.followersCount,
|
||||
|
@ -304,7 +275,7 @@ export class ActorModel extends Model<ActorModel> {
|
|||
}
|
||||
}
|
||||
|
||||
toActivityPubObject (preferredUsername: string, type: 'Account' | 'Application' | 'VideoChannel') {
|
||||
toActivityPubObject (name: string, type: 'Account' | 'Application' | 'VideoChannel') {
|
||||
let activityPubType
|
||||
if (type === 'Account') {
|
||||
activityPubType = 'Person' as 'Person'
|
||||
|
@ -321,9 +292,9 @@ export class ActorModel extends Model<ActorModel> {
|
|||
followers: this.getFollowersUrl(),
|
||||
inbox: this.inboxUrl,
|
||||
outbox: this.outboxUrl,
|
||||
preferredUsername,
|
||||
preferredUsername: this.preferredUsername,
|
||||
url: this.url,
|
||||
name: this.name,
|
||||
name,
|
||||
endpoints: {
|
||||
sharedInbox: this.sharedInboxUrl
|
||||
},
|
||||
|
@ -373,4 +344,12 @@ export class ActorModel extends Model<ActorModel> {
|
|||
isOwned () {
|
||||
return this.serverId === null
|
||||
}
|
||||
|
||||
getWebfingerUrl () {
|
||||
return 'acct:' + this.preferredUsername + '@' + this.getHost()
|
||||
}
|
||||
|
||||
getHost () {
|
||||
return this.Server ? this.Server.host : CONFIG.WEBSERVER.HOST
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ export interface ActivityFollow extends BaseActivity {
|
|||
|
||||
export interface ActivityAccept extends BaseActivity {
|
||||
type: 'Accept'
|
||||
object: ActivityFollow
|
||||
}
|
||||
|
||||
export interface ActivityAnnounce extends BaseActivity {
|
||||
|
|
|
@ -2378,9 +2378,9 @@ jsonify@~0.0.0:
|
|||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
|
||||
|
||||
"jsonld-signatures@https://github.com/digitalbazaar/jsonld-signatures#rsa2017":
|
||||
"jsonld-signatures@https://github.com/Chocobozzz/jsonld-signatures#rsa2017":
|
||||
version "1.2.2-2"
|
||||
resolved "https://github.com/digitalbazaar/jsonld-signatures#ccb5ca156d72d7632131080d6ef564681791391e"
|
||||
resolved "https://github.com/Chocobozzz/jsonld-signatures#77660963e722eb4541d2d255f9d9d4216329665f"
|
||||
dependencies:
|
||||
bitcore-message "github:CoMakery/bitcore-message#dist"
|
||||
jsonld "^0.5.12"
|
||||
|
|
Loading…
Reference in New Issue