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