]>
Commit | Line | Data |
---|---|---|
0f91ae62 | 1 | import * as Bluebird from 'bluebird' |
892211e8 C |
2 | import * as url from 'url' |
3 | import { ActivityPubActor } from '../../../shared/models/activitypub/activitypub-actor' | |
4 | import { isRemoteAccountValid } from '../../helpers/custom-validators/activitypub/account' | |
0f91ae62 | 5 | import { retryTransactionWrapper } from '../../helpers/database-utils' |
892211e8 C |
6 | import { logger } from '../../helpers/logger' |
7 | import { doRequest } from '../../helpers/requests' | |
8 | import { ACTIVITY_PUB } from '../../initializers/constants' | |
9 | import { database as db } from '../../initializers/database' | |
0f91ae62 C |
10 | import { AccountInstance } from '../../models/account/account-interface' |
11 | import { Transaction } from 'sequelize' | |
892211e8 | 12 | |
0f91ae62 | 13 | async 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 |
31 | function 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 | ||
62 | async 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 | ||
108 | export { | |
0f91ae62 C |
109 | getOrCreateAccountAndServer, |
110 | fetchRemoteAccount, | |
111 | saveAccountAndServerIfNotExist | |
892211e8 C |
112 | } |
113 | ||
114 | // --------------------------------------------------------------------------- | |
115 | ||
116 | async 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 | } |