]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/activitypub/account.ts
Add follow tests
[github/Chocobozzz/PeerTube.git] / server / lib / activitypub / account.ts
CommitLineData
0f91ae62 1import * as Bluebird from 'bluebird'
892211e8
C
2import * as url from 'url'
3import { ActivityPubActor } from '../../../shared/models/activitypub/activitypub-actor'
4import { isRemoteAccountValid } from '../../helpers/custom-validators/activitypub/account'
0f91ae62 5import { retryTransactionWrapper } from '../../helpers/database-utils'
892211e8
C
6import { logger } from '../../helpers/logger'
7import { doRequest } from '../../helpers/requests'
8import { ACTIVITY_PUB } from '../../initializers/constants'
9import { database as db } from '../../initializers/database'
0f91ae62
C
10import { AccountInstance } from '../../models/account/account-interface'
11import { Transaction } from 'sequelize'
892211e8 12
0f91ae62 13async function getOrCreateAccountAndServer (accountUrl: string) {
892211e8
C
14 let account = await db.Account.loadByUrl(accountUrl)
15
16 // We don't have this account in our database, fetch it on remote
17 if (!account) {
0f91ae62
C
18 account = await fetchRemoteAccount(accountUrl)
19 if (account === undefined) throw new Error('Cannot fetch remote account.')
892211e8 20
0f91ae62
C
21 const options = {
22 arguments: [ account ],
23 errorMessage: 'Cannot save account and server with many retries.'
24 }
25 account = await retryTransactionWrapper(saveAccountAndServerIfNotExist, options)
892211e8
C
26 }
27
28 return account
29}
30
0f91ae62
C
31function saveAccountAndServerIfNotExist (account: AccountInstance, t?: Transaction): Bluebird<AccountInstance> | Promise<AccountInstance> {
32 if (t !== undefined) {
33 return save(t)
34 } else {
35 return db.sequelize.transaction(t => {
36 return save(t)
37 })
38 }
39
40 async function save (t: Transaction) {
41 const accountHost = url.parse(account.url).host
42
43 const serverOptions = {
44 where: {
45 host: accountHost
46 },
47 defaults: {
48 host: accountHost
49 },
50 transaction: t
51 }
52 const [ server ] = await db.Server.findOrCreate(serverOptions)
53
54 // Save our new account in database
55 account.set('serverId', server.id)
56 account = await account.save({ transaction: t })
57
58 return account
59 }
60}
61
62async function fetchRemoteAccount (accountUrl: string) {
892211e8
C
63 const options = {
64 uri: accountUrl,
65 method: 'GET',
66 headers: {
67 'Accept': ACTIVITY_PUB.ACCEPT_HEADER
68 }
69 }
70
71 logger.info('Fetching remote account %s.', accountUrl)
72
73 let requestResult
74 try {
75 requestResult = await doRequest(options)
76 } catch (err) {
77 logger.warn('Cannot fetch remote account %s.', accountUrl, err)
78 return undefined
79 }
80
81 const accountJSON: ActivityPubActor = JSON.parse(requestResult.body)
82 if (isRemoteAccountValid(accountJSON) === false) {
83 logger.debug('Remote account JSON is not valid.', { accountJSON })
84 return undefined
85 }
86
87 const followersCount = await fetchAccountCount(accountJSON.followers)
88 const followingCount = await fetchAccountCount(accountJSON.following)
89
90 const account = db.Account.build({
91 uuid: accountJSON.uuid,
92 name: accountJSON.preferredUsername,
93 url: accountJSON.url,
94 publicKey: accountJSON.publicKey.publicKeyPem,
95 privateKey: null,
96 followersCount: followersCount,
97 followingCount: followingCount,
98 inboxUrl: accountJSON.inbox,
99 outboxUrl: accountJSON.outbox,
100 sharedInboxUrl: accountJSON.endpoints.sharedInbox,
101 followersUrl: accountJSON.followers,
102 followingUrl: accountJSON.following
103 })
104
0f91ae62 105 return account
892211e8
C
106}
107
108export {
0f91ae62
C
109 getOrCreateAccountAndServer,
110 fetchRemoteAccount,
111 saveAccountAndServerIfNotExist
892211e8
C
112}
113
114// ---------------------------------------------------------------------------
115
116async function fetchAccountCount (url: string) {
117 const options = {
118 uri: url,
119 method: 'GET'
120 }
121
122 let requestResult
123 try {
124 requestResult = await doRequest(options)
125 } catch (err) {
126 logger.warn('Cannot fetch remote account count %s.', url, err)
127 return undefined
128 }
129
130 return requestResult.totalItems ? requestResult.totalItems : 0
131}