diff options
Diffstat (limited to 'server/helpers/activitypub.ts')
-rw-r--r-- | server/helpers/activitypub.ts | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts new file mode 100644 index 000000000..ecb509b66 --- /dev/null +++ b/server/helpers/activitypub.ts | |||
@@ -0,0 +1,123 @@ | |||
1 | import * as url from 'url' | ||
2 | |||
3 | import { database as db } from '../initializers' | ||
4 | import { logger } from './logger' | ||
5 | import { doRequest } from './requests' | ||
6 | import { isRemoteAccountValid } from './custom-validators' | ||
7 | import { ActivityPubActor } from '../../shared/models/activitypub/activitypub-actor' | ||
8 | import { ResultList } from '../../shared/models/result-list.model' | ||
9 | |||
10 | async function fetchRemoteAccountAndCreatePod (accountUrl: string) { | ||
11 | const options = { | ||
12 | uri: accountUrl, | ||
13 | method: 'GET' | ||
14 | } | ||
15 | |||
16 | let requestResult | ||
17 | try { | ||
18 | requestResult = await doRequest(options) | ||
19 | } catch (err) { | ||
20 | logger.warning('Cannot fetch remote account %s.', accountUrl, err) | ||
21 | return undefined | ||
22 | } | ||
23 | |||
24 | const accountJSON: ActivityPubActor = requestResult.body | ||
25 | if (isRemoteAccountValid(accountJSON) === false) return undefined | ||
26 | |||
27 | const followersCount = await fetchAccountCount(accountJSON.followers) | ||
28 | const followingCount = await fetchAccountCount(accountJSON.following) | ||
29 | |||
30 | const account = db.Account.build({ | ||
31 | uuid: accountJSON.uuid, | ||
32 | name: accountJSON.preferredUsername, | ||
33 | url: accountJSON.url, | ||
34 | publicKey: accountJSON.publicKey.publicKeyPem, | ||
35 | privateKey: null, | ||
36 | followersCount: followersCount, | ||
37 | followingCount: followingCount, | ||
38 | inboxUrl: accountJSON.inbox, | ||
39 | outboxUrl: accountJSON.outbox, | ||
40 | sharedInboxUrl: accountJSON.endpoints.sharedInbox, | ||
41 | followersUrl: accountJSON.followers, | ||
42 | followingUrl: accountJSON.following | ||
43 | }) | ||
44 | |||
45 | const accountHost = url.parse(account.url).host | ||
46 | const podOptions = { | ||
47 | where: { | ||
48 | host: accountHost | ||
49 | }, | ||
50 | defaults: { | ||
51 | host: accountHost | ||
52 | } | ||
53 | } | ||
54 | const pod = await db.Pod.findOrCreate(podOptions) | ||
55 | |||
56 | return { account, pod } | ||
57 | } | ||
58 | |||
59 | function activityPubContextify (data: object) { | ||
60 | return Object.assign(data,{ | ||
61 | '@context': [ | ||
62 | 'https://www.w3.org/ns/activitystreams', | ||
63 | 'https://w3id.org/security/v1', | ||
64 | { | ||
65 | 'Hashtag': 'as:Hashtag', | ||
66 | 'uuid': 'http://schema.org/identifier', | ||
67 | 'category': 'http://schema.org/category', | ||
68 | 'licence': 'http://schema.org/license', | ||
69 | 'nsfw': 'as:sensitive', | ||
70 | 'language': 'http://schema.org/inLanguage', | ||
71 | 'views': 'http://schema.org/Number', | ||
72 | 'size': 'http://schema.org/Number' | ||
73 | } | ||
74 | ] | ||
75 | }) | ||
76 | } | ||
77 | |||
78 | function activityPubCollectionPagination (url: string, page: number, result: ResultList<any>) { | ||
79 | const baseUrl = url.split('?').shift | ||
80 | |||
81 | const obj = { | ||
82 | id: baseUrl, | ||
83 | type: 'Collection', | ||
84 | totalItems: result.total, | ||
85 | first: { | ||
86 | id: baseUrl + '?page=' + page, | ||
87 | type: 'CollectionPage', | ||
88 | totalItems: result.total, | ||
89 | next: baseUrl + '?page=' + (page + 1), | ||
90 | partOf: baseUrl, | ||
91 | items: result.data | ||
92 | } | ||
93 | } | ||
94 | |||
95 | return activityPubContextify(obj) | ||
96 | } | ||
97 | |||
98 | // --------------------------------------------------------------------------- | ||
99 | |||
100 | export { | ||
101 | fetchRemoteAccountAndCreatePod, | ||
102 | activityPubContextify, | ||
103 | activityPubCollectionPagination | ||
104 | } | ||
105 | |||
106 | // --------------------------------------------------------------------------- | ||
107 | |||
108 | async function fetchAccountCount (url: string) { | ||
109 | const options = { | ||
110 | uri: url, | ||
111 | method: 'GET' | ||
112 | } | ||
113 | |||
114 | let requestResult | ||
115 | try { | ||
116 | requestResult = await doRequest(options) | ||
117 | } catch (err) { | ||
118 | logger.warning('Cannot fetch remote account count %s.', url, err) | ||
119 | return undefined | ||
120 | } | ||
121 | |||
122 | return requestResult.totalItems ? requestResult.totalItems : 0 | ||
123 | } | ||