aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/activitypub
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib/activitypub')
-rw-r--r--server/lib/activitypub/actor.ts41
-rw-r--r--server/lib/activitypub/crawl.ts25
-rw-r--r--server/lib/activitypub/playlist.ts54
-rw-r--r--server/lib/activitypub/share.ts9
-rw-r--r--server/lib/activitypub/video-comments.ts14
-rw-r--r--server/lib/activitypub/video-rates.ts22
-rw-r--r--server/lib/activitypub/videos.ts31
7 files changed, 71 insertions, 125 deletions
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts
index a726f9e20..52b6c1f56 100644
--- a/server/lib/activitypub/actor.ts
+++ b/server/lib/activitypub/actor.ts
@@ -1,26 +1,28 @@
1import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
2import { extname } from 'path'
2import { Op, Transaction } from 'sequelize' 3import { Op, Transaction } from 'sequelize'
3import { URL } from 'url' 4import { URL } from 'url'
4import { v4 as uuidv4 } from 'uuid' 5import { v4 as uuidv4 } from 'uuid'
6import { getServerActor } from '@server/models/application/application'
7import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
5import { ActivityPubActor, ActivityPubActorType, ActivityPubOrderedCollection } from '../../../shared/models/activitypub' 8import { ActivityPubActor, ActivityPubActorType, ActivityPubOrderedCollection } from '../../../shared/models/activitypub'
6import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' 9import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects'
7import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' 10import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
11import { ActorFetchByUrlType, fetchActorByUrl } from '../../helpers/actor'
8import { sanitizeAndCheckActorObject } from '../../helpers/custom-validators/activitypub/actor' 12import { sanitizeAndCheckActorObject } from '../../helpers/custom-validators/activitypub/actor'
9import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' 13import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
10import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' 14import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils'
11import { logger } from '../../helpers/logger' 15import { logger } from '../../helpers/logger'
12import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' 16import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
13import { doRequest } from '../../helpers/requests' 17import { doJSONRequest } from '../../helpers/requests'
14import { getUrlFromWebfinger } from '../../helpers/webfinger' 18import { getUrlFromWebfinger } from '../../helpers/webfinger'
15import { MIMETYPES, WEBSERVER } from '../../initializers/constants' 19import { MIMETYPES, WEBSERVER } from '../../initializers/constants'
20import { sequelizeTypescript } from '../../initializers/database'
16import { AccountModel } from '../../models/account/account' 21import { AccountModel } from '../../models/account/account'
17import { ActorModel } from '../../models/activitypub/actor' 22import { ActorModel } from '../../models/activitypub/actor'
18import { AvatarModel } from '../../models/avatar/avatar' 23import { AvatarModel } from '../../models/avatar/avatar'
19import { ServerModel } from '../../models/server/server' 24import { ServerModel } from '../../models/server/server'
20import { VideoChannelModel } from '../../models/video/video-channel' 25import { VideoChannelModel } from '../../models/video/video-channel'
21import { JobQueue } from '../job-queue'
22import { ActorFetchByUrlType, fetchActorByUrl } from '../../helpers/actor'
23import { sequelizeTypescript } from '../../initializers/database'
24import { 26import {
25 MAccount, 27 MAccount,
26 MAccountDefault, 28 MAccountDefault,
@@ -34,9 +36,7 @@ import {
34 MActorId, 36 MActorId,
35 MChannel 37 MChannel
36} from '../../types/models' 38} from '../../types/models'
37import { extname } from 'path' 39import { JobQueue } from '../job-queue'
38import { getServerActor } from '@server/models/application/application'
39import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
40 40
41// Set account keys, this could be long so process after the account creation and do not block the client 41// Set account keys, this could be long so process after the account creation and do not block the client
42async function generateAndSaveActorKeys <T extends MActor> (actor: T) { 42async function generateAndSaveActorKeys <T extends MActor> (actor: T) {
@@ -209,16 +209,10 @@ async function deleteActorAvatarInstance (actor: MActorDefault, t: Transaction)
209} 209}
210 210
211async function fetchActorTotalItems (url: string) { 211async function fetchActorTotalItems (url: string) {
212 const options = {
213 uri: url,
214 method: 'GET',
215 json: true,
216 activityPub: true
217 }
218
219 try { 212 try {
220 const { body } = await doRequest<ActivityPubOrderedCollection<unknown>>(options) 213 const { body } = await doJSONRequest<ActivityPubOrderedCollection<unknown>>(url, { activityPub: true })
221 return body.totalItems ? body.totalItems : 0 214
215 return body.totalItems || 0
222 } catch (err) { 216 } catch (err) {
223 logger.warn('Cannot fetch remote actor count %s.', url, { err }) 217 logger.warn('Cannot fetch remote actor count %s.', url, { err })
224 return 0 218 return 0
@@ -449,26 +443,19 @@ type FetchRemoteActorResult = {
449 attributedTo: ActivityPubAttributedTo[] 443 attributedTo: ActivityPubAttributedTo[]
450} 444}
451async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: number, result: FetchRemoteActorResult }> { 445async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: number, result: FetchRemoteActorResult }> {
452 const options = {
453 uri: actorUrl,
454 method: 'GET',
455 json: true,
456 activityPub: true
457 }
458
459 logger.info('Fetching remote actor %s.', actorUrl) 446 logger.info('Fetching remote actor %s.', actorUrl)
460 447
461 const requestResult = await doRequest<ActivityPubActor>(options) 448 const requestResult = await doJSONRequest<ActivityPubActor>(actorUrl, { activityPub: true })
462 const actorJSON = requestResult.body 449 const actorJSON = requestResult.body
463 450
464 if (sanitizeAndCheckActorObject(actorJSON) === false) { 451 if (sanitizeAndCheckActorObject(actorJSON) === false) {
465 logger.debug('Remote actor JSON is not valid.', { actorJSON }) 452 logger.debug('Remote actor JSON is not valid.', { actorJSON })
466 return { result: undefined, statusCode: requestResult.response.statusCode } 453 return { result: undefined, statusCode: requestResult.statusCode }
467 } 454 }
468 455
469 if (checkUrlsSameHost(actorJSON.id, actorUrl) !== true) { 456 if (checkUrlsSameHost(actorJSON.id, actorUrl) !== true) {
470 logger.warn('Actor url %s has not the same host than its AP id %s', actorUrl, actorJSON.id) 457 logger.warn('Actor url %s has not the same host than its AP id %s', actorUrl, actorJSON.id)
471 return { result: undefined, statusCode: requestResult.response.statusCode } 458 return { result: undefined, statusCode: requestResult.statusCode }
472 } 459 }
473 460
474 const followersCount = await fetchActorTotalItems(actorJSON.followers) 461 const followersCount = await fetchActorTotalItems(actorJSON.followers)
@@ -496,7 +483,7 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe
496 483
497 const name = actorJSON.name || actorJSON.preferredUsername 484 const name = actorJSON.name || actorJSON.preferredUsername
498 return { 485 return {
499 statusCode: requestResult.response.statusCode, 486 statusCode: requestResult.statusCode,
500 result: { 487 result: {
501 actor, 488 actor,
502 name, 489 name,
diff --git a/server/lib/activitypub/crawl.ts b/server/lib/activitypub/crawl.ts
index 1ed105bbe..278abf7de 100644
--- a/server/lib/activitypub/crawl.ts
+++ b/server/lib/activitypub/crawl.ts
@@ -1,27 +1,26 @@
1import { ACTIVITY_PUB, REQUEST_TIMEOUT, WEBSERVER } from '../../initializers/constants'
2import { doRequest } from '../../helpers/requests'
3import { logger } from '../../helpers/logger'
4import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
5import { ActivityPubOrderedCollection } from '../../../shared/models/activitypub'
6import { URL } from 'url' 2import { URL } from 'url'
3import { ActivityPubOrderedCollection } from '../../../shared/models/activitypub'
4import { logger } from '../../helpers/logger'
5import { doJSONRequest } from '../../helpers/requests'
6import { ACTIVITY_PUB, REQUEST_TIMEOUT, WEBSERVER } from '../../initializers/constants'
7 7
8type HandlerFunction<T> = (items: T[]) => (Promise<any> | Bluebird<any>) 8type HandlerFunction<T> = (items: T[]) => (Promise<any> | Bluebird<any>)
9type CleanerFunction = (startedDate: Date) => (Promise<any> | Bluebird<any>) 9type CleanerFunction = (startedDate: Date) => (Promise<any> | Bluebird<any>)
10 10
11async function crawlCollectionPage <T> (uri: string, handler: HandlerFunction<T>, cleaner?: CleanerFunction) { 11async function crawlCollectionPage <T> (argUrl: string, handler: HandlerFunction<T>, cleaner?: CleanerFunction) {
12 logger.info('Crawling ActivityPub data on %s.', uri) 12 let url = argUrl
13
14 logger.info('Crawling ActivityPub data on %s.', url)
13 15
14 const options = { 16 const options = {
15 method: 'GET',
16 uri,
17 json: true,
18 activityPub: true, 17 activityPub: true,
19 timeout: REQUEST_TIMEOUT 18 timeout: REQUEST_TIMEOUT
20 } 19 }
21 20
22 const startDate = new Date() 21 const startDate = new Date()
23 22
24 const response = await doRequest<ActivityPubOrderedCollection<T>>(options) 23 const response = await doJSONRequest<ActivityPubOrderedCollection<T>>(url, options)
25 const firstBody = response.body 24 const firstBody = response.body
26 25
27 const limit = ACTIVITY_PUB.FETCH_PAGE_LIMIT 26 const limit = ACTIVITY_PUB.FETCH_PAGE_LIMIT
@@ -35,9 +34,9 @@ async function crawlCollectionPage <T> (uri: string, handler: HandlerFunction<T>
35 const remoteHost = new URL(nextLink).host 34 const remoteHost = new URL(nextLink).host
36 if (remoteHost === WEBSERVER.HOST) continue 35 if (remoteHost === WEBSERVER.HOST) continue
37 36
38 options.uri = nextLink 37 url = nextLink
39 38
40 const res = await doRequest<ActivityPubOrderedCollection<T>>(options) 39 const res = await doJSONRequest<ActivityPubOrderedCollection<T>>(url, options)
41 body = res.body 40 body = res.body
42 } else { 41 } else {
43 // nextLink is already the object we want 42 // nextLink is already the object we want
@@ -49,7 +48,7 @@ async function crawlCollectionPage <T> (uri: string, handler: HandlerFunction<T>
49 48
50 if (Array.isArray(body.orderedItems)) { 49 if (Array.isArray(body.orderedItems)) {
51 const items = body.orderedItems 50 const items = body.orderedItems
52 logger.info('Processing %i ActivityPub items for %s.', items.length, options.uri) 51 logger.info('Processing %i ActivityPub items for %s.', items.length, url)
53 52
54 await handler(items) 53 await handler(items)
55 } 54 }
diff --git a/server/lib/activitypub/playlist.ts b/server/lib/activitypub/playlist.ts
index d5a3ef7c8..795be60d7 100644
--- a/server/lib/activitypub/playlist.ts
+++ b/server/lib/activitypub/playlist.ts
@@ -1,24 +1,24 @@
1import * as Bluebird from 'bluebird'
2import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
3import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object'
1import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object' 4import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object'
2import { crawlCollectionPage } from './crawl' 5import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model'
3import { ACTIVITY_PUB, CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' 6import { checkUrlsSameHost } from '../../helpers/activitypub'
7import { isPlaylistElementObjectValid, isPlaylistObjectValid } from '../../helpers/custom-validators/activitypub/playlist'
4import { isArray } from '../../helpers/custom-validators/misc' 8import { isArray } from '../../helpers/custom-validators/misc'
5import { getOrCreateActorAndServerAndModel } from './actor'
6import { logger } from '../../helpers/logger' 9import { logger } from '../../helpers/logger'
10import { doJSONRequest } from '../../helpers/requests'
11import { ACTIVITY_PUB, CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants'
12import { sequelizeTypescript } from '../../initializers/database'
7import { VideoPlaylistModel } from '../../models/video/video-playlist' 13import { VideoPlaylistModel } from '../../models/video/video-playlist'
8import { doRequest } from '../../helpers/requests'
9import { checkUrlsSameHost } from '../../helpers/activitypub'
10import * as Bluebird from 'bluebird'
11import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object'
12import { getOrCreateVideoAndAccountAndChannel } from './videos'
13import { isPlaylistElementObjectValid, isPlaylistObjectValid } from '../../helpers/custom-validators/activitypub/playlist'
14import { VideoPlaylistElementModel } from '../../models/video/video-playlist-element' 14import { VideoPlaylistElementModel } from '../../models/video/video-playlist-element'
15import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model'
16import { sequelizeTypescript } from '../../initializers/database'
17import { createPlaylistMiniatureFromUrl } from '../thumbnail'
18import { FilteredModelAttributes } from '../../types/sequelize'
19import { MAccountDefault, MAccountId, MVideoId } from '../../types/models' 15import { MAccountDefault, MAccountId, MVideoId } from '../../types/models'
20import { MVideoPlaylist, MVideoPlaylistId, MVideoPlaylistOwner } from '../../types/models/video/video-playlist' 16import { MVideoPlaylist, MVideoPlaylistId, MVideoPlaylistOwner } from '../../types/models/video/video-playlist'
21import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' 17import { FilteredModelAttributes } from '../../types/sequelize'
18import { createPlaylistMiniatureFromUrl } from '../thumbnail'
19import { getOrCreateActorAndServerAndModel } from './actor'
20import { crawlCollectionPage } from './crawl'
21import { getOrCreateVideoAndAccountAndChannel } from './videos'
22 22
23function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: MAccountId, to: string[]) { 23function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: MAccountId, to: string[]) {
24 const privacy = to.includes(ACTIVITY_PUB.PUBLIC) 24 const privacy = to.includes(ACTIVITY_PUB.PUBLIC)
@@ -56,11 +56,7 @@ async function createAccountPlaylists (playlistUrls: string[], account: MAccount
56 if (exists === true) return 56 if (exists === true) return
57 57
58 // Fetch url 58 // Fetch url
59 const { body } = await doRequest<PlaylistObject>({ 59 const { body } = await doJSONRequest<PlaylistObject>(playlistUrl, { activityPub: true })
60 uri: playlistUrl,
61 json: true,
62 activityPub: true
63 })
64 60
65 if (!isPlaylistObjectValid(body)) { 61 if (!isPlaylistObjectValid(body)) {
66 throw new Error(`Invalid playlist object when fetch account playlists: ${JSON.stringify(body)}`) 62 throw new Error(`Invalid playlist object when fetch account playlists: ${JSON.stringify(body)}`)
@@ -164,12 +160,7 @@ async function resetVideoPlaylistElements (elementUrls: string[], playlist: MVid
164 160
165 await Bluebird.map(elementUrls, async elementUrl => { 161 await Bluebird.map(elementUrls, async elementUrl => {
166 try { 162 try {
167 // Fetch url 163 const { body } = await doJSONRequest<PlaylistElementObject>(elementUrl, { activityPub: true })
168 const { body } = await doRequest<PlaylistElementObject>({
169 uri: elementUrl,
170 json: true,
171 activityPub: true
172 })
173 164
174 if (!isPlaylistElementObjectValid(body)) throw new Error(`Invalid body in video get playlist element ${elementUrl}`) 165 if (!isPlaylistElementObjectValid(body)) throw new Error(`Invalid body in video get playlist element ${elementUrl}`)
175 166
@@ -199,21 +190,14 @@ async function resetVideoPlaylistElements (elementUrls: string[], playlist: MVid
199} 190}
200 191
201async function fetchRemoteVideoPlaylist (playlistUrl: string): Promise<{ statusCode: number, playlistObject: PlaylistObject }> { 192async function fetchRemoteVideoPlaylist (playlistUrl: string): Promise<{ statusCode: number, playlistObject: PlaylistObject }> {
202 const options = {
203 uri: playlistUrl,
204 method: 'GET',
205 json: true,
206 activityPub: true
207 }
208
209 logger.info('Fetching remote playlist %s.', playlistUrl) 193 logger.info('Fetching remote playlist %s.', playlistUrl)
210 194
211 const { response, body } = await doRequest<any>(options) 195 const { body, statusCode } = await doJSONRequest<any>(playlistUrl, { activityPub: true })
212 196
213 if (isPlaylistObjectValid(body) === false || checkUrlsSameHost(body.id, playlistUrl) !== true) { 197 if (isPlaylistObjectValid(body) === false || checkUrlsSameHost(body.id, playlistUrl) !== true) {
214 logger.debug('Remote video playlist JSON is not valid.', { body }) 198 logger.debug('Remote video playlist JSON is not valid.', { body })
215 return { statusCode: response.statusCode, playlistObject: undefined } 199 return { statusCode, playlistObject: undefined }
216 } 200 }
217 201
218 return { statusCode: response.statusCode, playlistObject: body } 202 return { statusCode, playlistObject: body }
219} 203}
diff --git a/server/lib/activitypub/share.ts b/server/lib/activitypub/share.ts
index dde0c628e..c22fa0893 100644
--- a/server/lib/activitypub/share.ts
+++ b/server/lib/activitypub/share.ts
@@ -3,7 +3,7 @@ import { Transaction } from 'sequelize'
3import { getServerActor } from '@server/models/application/application' 3import { getServerActor } from '@server/models/application/application'
4import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' 4import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
5import { logger, loggerTagsFactory } from '../../helpers/logger' 5import { logger, loggerTagsFactory } from '../../helpers/logger'
6import { doRequest } from '../../helpers/requests' 6import { doJSONRequest } from '../../helpers/requests'
7import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' 7import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants'
8import { VideoShareModel } from '../../models/video/video-share' 8import { VideoShareModel } from '../../models/video/video-share'
9import { MChannelActorLight, MVideo, MVideoAccountLight, MVideoId } from '../../types/models/video' 9import { MChannelActorLight, MVideo, MVideoAccountLight, MVideoId } from '../../types/models/video'
@@ -40,12 +40,7 @@ async function changeVideoChannelShare (
40async function addVideoShares (shareUrls: string[], video: MVideoId) { 40async function addVideoShares (shareUrls: string[], video: MVideoId) {
41 await Bluebird.map(shareUrls, async shareUrl => { 41 await Bluebird.map(shareUrls, async shareUrl => {
42 try { 42 try {
43 // Fetch url 43 const { body } = await doJSONRequest<any>(shareUrl, { activityPub: true })
44 const { body } = await doRequest<any>({
45 uri: shareUrl,
46 json: true,
47 activityPub: true
48 })
49 if (!body || !body.actor) throw new Error('Body or body actor is invalid') 44 if (!body || !body.actor) throw new Error('Body or body actor is invalid')
50 45
51 const actorUrl = getAPId(body.actor) 46 const actorUrl = getAPId(body.actor)
diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts
index d025ed7f1..f1edfb0ac 100644
--- a/server/lib/activitypub/video-comments.ts
+++ b/server/lib/activitypub/video-comments.ts
@@ -1,13 +1,13 @@
1import * as Bluebird from 'bluebird'
2import { checkUrlsSameHost } from '../../helpers/activitypub'
1import { sanitizeAndCheckVideoCommentObject } from '../../helpers/custom-validators/activitypub/video-comments' 3import { sanitizeAndCheckVideoCommentObject } from '../../helpers/custom-validators/activitypub/video-comments'
2import { logger } from '../../helpers/logger' 4import { logger } from '../../helpers/logger'
3import { doRequest } from '../../helpers/requests' 5import { doJSONRequest } from '../../helpers/requests'
4import { ACTIVITY_PUB, CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' 6import { ACTIVITY_PUB, CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants'
5import { VideoCommentModel } from '../../models/video/video-comment' 7import { VideoCommentModel } from '../../models/video/video-comment'
8import { MCommentOwner, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../types/models/video'
6import { getOrCreateActorAndServerAndModel } from './actor' 9import { getOrCreateActorAndServerAndModel } from './actor'
7import { getOrCreateVideoAndAccountAndChannel } from './videos' 10import { getOrCreateVideoAndAccountAndChannel } from './videos'
8import * as Bluebird from 'bluebird'
9import { checkUrlsSameHost } from '../../helpers/activitypub'
10import { MCommentOwner, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../types/models/video'
11 11
12type ResolveThreadParams = { 12type ResolveThreadParams = {
13 url: string 13 url: string
@@ -126,11 +126,7 @@ async function resolveRemoteParentComment (params: ResolveThreadParams) {
126 throw new Error('Recursion limit reached when resolving a thread') 126 throw new Error('Recursion limit reached when resolving a thread')
127 } 127 }
128 128
129 const { body } = await doRequest<any>({ 129 const { body } = await doJSONRequest<any>(url, { activityPub: true })
130 uri: url,
131 json: true,
132 activityPub: true
133 })
134 130
135 if (sanitizeAndCheckVideoCommentObject(body) === false) { 131 if (sanitizeAndCheckVideoCommentObject(body) === false) {
136 throw new Error(`Remote video comment JSON ${url} is not valid:` + JSON.stringify(body)) 132 throw new Error(`Remote video comment JSON ${url} is not valid:` + JSON.stringify(body))
diff --git a/server/lib/activitypub/video-rates.ts b/server/lib/activitypub/video-rates.ts
index e246b1313..f40c07fea 100644
--- a/server/lib/activitypub/video-rates.ts
+++ b/server/lib/activitypub/video-rates.ts
@@ -1,26 +1,22 @@
1import * as Bluebird from 'bluebird'
1import { Transaction } from 'sequelize' 2import { Transaction } from 'sequelize'
2import { sendLike, sendUndoDislike, sendUndoLike } from './send' 3import { doJSONRequest } from '@server/helpers/requests'
3import { VideoRateType } from '../../../shared/models/videos' 4import { VideoRateType } from '../../../shared/models/videos'
4import * as Bluebird from 'bluebird' 5import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
5import { getOrCreateActorAndServerAndModel } from './actor'
6import { AccountVideoRateModel } from '../../models/account/account-video-rate'
7import { logger } from '../../helpers/logger' 6import { logger } from '../../helpers/logger'
8import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' 7import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants'
9import { doRequest } from '../../helpers/requests' 8import { AccountVideoRateModel } from '../../models/account/account-video-rate'
10import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
11import { getVideoDislikeActivityPubUrlByLocalActor, getVideoLikeActivityPubUrlByLocalActor } from './url'
12import { sendDislike } from './send/send-dislike'
13import { MAccountActor, MActorUrl, MVideo, MVideoAccountLight, MVideoId } from '../../types/models' 9import { MAccountActor, MActorUrl, MVideo, MVideoAccountLight, MVideoId } from '../../types/models'
10import { getOrCreateActorAndServerAndModel } from './actor'
11import { sendLike, sendUndoDislike, sendUndoLike } from './send'
12import { sendDislike } from './send/send-dislike'
13import { getVideoDislikeActivityPubUrlByLocalActor, getVideoLikeActivityPubUrlByLocalActor } from './url'
14 14
15async function createRates (ratesUrl: string[], video: MVideo, rate: VideoRateType) { 15async function createRates (ratesUrl: string[], video: MVideo, rate: VideoRateType) {
16 await Bluebird.map(ratesUrl, async rateUrl => { 16 await Bluebird.map(ratesUrl, async rateUrl => {
17 try { 17 try {
18 // Fetch url 18 // Fetch url
19 const { body } = await doRequest<any>({ 19 const { body } = await doJSONRequest<any>(rateUrl, { activityPub: true })
20 uri: rateUrl,
21 json: true,
22 activityPub: true
23 })
24 if (!body || !body.actor) throw new Error('Body or body actor is invalid') 20 if (!body || !body.actor) throw new Error('Body or body actor is invalid')
25 21
26 const actorUrl = getAPId(body.actor) 22 const actorUrl = getAPId(body.actor)
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts
index c02578aad..a5f58dd01 100644
--- a/server/lib/activitypub/videos.ts
+++ b/server/lib/activitypub/videos.ts
@@ -2,7 +2,6 @@ import * as Bluebird from 'bluebird'
2import { maxBy, minBy } from 'lodash' 2import { maxBy, minBy } from 'lodash'
3import * as magnetUtil from 'magnet-uri' 3import * as magnetUtil from 'magnet-uri'
4import { basename, join } from 'path' 4import { basename, join } from 'path'
5import * as request from 'request'
6import { Transaction } from 'sequelize/types' 5import { Transaction } from 'sequelize/types'
7import { TrackerModel } from '@server/models/server/tracker' 6import { TrackerModel } from '@server/models/server/tracker'
8import { VideoLiveModel } from '@server/models/video/video-live' 7import { VideoLiveModel } from '@server/models/video/video-live'
@@ -31,7 +30,7 @@ import { isArray } from '../../helpers/custom-validators/misc'
31import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' 30import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos'
32import { deleteNonExistingModels, resetSequelizeInstance, retryTransactionWrapper } from '../../helpers/database-utils' 31import { deleteNonExistingModels, resetSequelizeInstance, retryTransactionWrapper } from '../../helpers/database-utils'
33import { logger } from '../../helpers/logger' 32import { logger } from '../../helpers/logger'
34import { doRequest } from '../../helpers/requests' 33import { doJSONRequest } from '../../helpers/requests'
35import { fetchVideoByUrl, getExtFromMimetype, VideoFetchByUrlType } from '../../helpers/video' 34import { fetchVideoByUrl, getExtFromMimetype, VideoFetchByUrlType } from '../../helpers/video'
36import { 35import {
37 ACTIVITY_PUB, 36 ACTIVITY_PUB,
@@ -115,36 +114,26 @@ async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVid
115 } 114 }
116} 115}
117 116
118async function fetchRemoteVideo (videoUrl: string): Promise<{ response: request.RequestResponse, videoObject: VideoObject }> { 117async function fetchRemoteVideo (videoUrl: string): Promise<{ statusCode: number, videoObject: VideoObject }> {
119 const options = {
120 uri: videoUrl,
121 method: 'GET',
122 json: true,
123 activityPub: true
124 }
125
126 logger.info('Fetching remote video %s.', videoUrl) 118 logger.info('Fetching remote video %s.', videoUrl)
127 119
128 const { response, body } = await doRequest<any>(options) 120 const { statusCode, body } = await doJSONRequest<any>(videoUrl, { activityPub: true })
129 121
130 if (sanitizeAndCheckVideoTorrentObject(body) === false || checkUrlsSameHost(body.id, videoUrl) !== true) { 122 if (sanitizeAndCheckVideoTorrentObject(body) === false || checkUrlsSameHost(body.id, videoUrl) !== true) {
131 logger.debug('Remote video JSON is not valid.', { body }) 123 logger.debug('Remote video JSON is not valid.', { body })
132 return { response, videoObject: undefined } 124 return { statusCode, videoObject: undefined }
133 } 125 }
134 126
135 return { response, videoObject: body } 127 return { statusCode, videoObject: body }
136} 128}
137 129
138async function fetchRemoteVideoDescription (video: MVideoAccountLight) { 130async function fetchRemoteVideoDescription (video: MVideoAccountLight) {
139 const host = video.VideoChannel.Account.Actor.Server.host 131 const host = video.VideoChannel.Account.Actor.Server.host
140 const path = video.getDescriptionAPIPath() 132 const path = video.getDescriptionAPIPath()
141 const options = { 133 const url = REMOTE_SCHEME.HTTP + '://' + host + path
142 uri: REMOTE_SCHEME.HTTP + '://' + host + path,
143 json: true
144 }
145 134
146 const { body } = await doRequest<any>(options) 135 const { body } = await doJSONRequest<any>(url)
147 return body.description ? body.description : '' 136 return body.description || ''
148} 137}
149 138
150function getOrCreateVideoChannelFromVideoObject (videoObject: VideoObject) { 139function getOrCreateVideoChannelFromVideoObject (videoObject: VideoObject) {
@@ -534,8 +523,8 @@ async function refreshVideoIfNeeded (options: {
534 : await VideoModel.loadByUrlAndPopulateAccount(options.video.url) 523 : await VideoModel.loadByUrlAndPopulateAccount(options.video.url)
535 524
536 try { 525 try {
537 const { response, videoObject } = await fetchRemoteVideo(video.url) 526 const { statusCode, videoObject } = await fetchRemoteVideo(video.url)
538 if (response.statusCode === HttpStatusCode.NOT_FOUND_404) { 527 if (statusCode === HttpStatusCode.NOT_FOUND_404) {
539 logger.info('Cannot refresh remote video %s: video does not exist anymore. Deleting it.', video.url) 528 logger.info('Cannot refresh remote video %s: video does not exist anymore. Deleting it.', video.url)
540 529
541 // Video does not exist anymore 530 // Video does not exist anymore