]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/helpers/custom-validators/activitypub/actor.ts
Add totalLocalVideoFilesSize in stats
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / activitypub / actor.ts
... / ...
CommitLineData
1import * as validator from 'validator'
2import { CONSTRAINTS_FIELDS } from '../../../initializers'
3import { exists, isArray } from '../misc'
4import { truncate } from 'lodash'
5import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc'
6import { isHostValid } from '../servers'
7
8function isActorEndpointsObjectValid (endpointObject: any) {
9 return isActivityPubUrlValid(endpointObject.sharedInbox)
10}
11
12function isActorPublicKeyObjectValid (publicKeyObject: any) {
13 return isActivityPubUrlValid(publicKeyObject.id) &&
14 isActivityPubUrlValid(publicKeyObject.owner) &&
15 isActorPublicKeyValid(publicKeyObject.publicKeyPem)
16}
17
18function isActorTypeValid (type: string) {
19 return type === 'Person' || type === 'Application' || type === 'Group'
20}
21
22function isActorPublicKeyValid (publicKey: string) {
23 return exists(publicKey) &&
24 typeof publicKey === 'string' &&
25 publicKey.startsWith('-----BEGIN PUBLIC KEY-----') &&
26 publicKey.indexOf('-----END PUBLIC KEY-----') !== -1 &&
27 validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY)
28}
29
30const actorNameAlphabet = '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.]'
31const actorNameRegExp = new RegExp(`^${actorNameAlphabet}+$`)
32function isActorPreferredUsernameValid (preferredUsername: string) {
33 return exists(preferredUsername) && validator.matches(preferredUsername, actorNameRegExp)
34}
35
36function isActorPrivateKeyValid (privateKey: string) {
37 return exists(privateKey) &&
38 typeof privateKey === 'string' &&
39 privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') &&
40 // Sometimes there is a \n at the end, so just assert the string contains the end mark
41 privateKey.indexOf('-----END RSA PRIVATE KEY-----') !== -1 &&
42 validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY)
43}
44
45function isActorObjectValid (actor: any) {
46 return exists(actor) &&
47 isActivityPubUrlValid(actor.id) &&
48 isActorTypeValid(actor.type) &&
49 isActivityPubUrlValid(actor.following) &&
50 isActivityPubUrlValid(actor.followers) &&
51 isActivityPubUrlValid(actor.inbox) &&
52 isActivityPubUrlValid(actor.outbox) &&
53 isActorPreferredUsernameValid(actor.preferredUsername) &&
54 isActivityPubUrlValid(actor.url) &&
55 isActorPublicKeyObjectValid(actor.publicKey) &&
56 isActorEndpointsObjectValid(actor.endpoints) &&
57 setValidAttributedTo(actor) &&
58
59 // If this is not an account, it should be attributed to an account
60 // In PeerTube we use this to attach a video channel to a specific account
61 (actor.type === 'Person' || actor.attributedTo.length !== 0)
62}
63
64function isActorFollowingCountValid (value: string) {
65 return exists(value) && validator.isInt('' + value, { min: 0 })
66}
67
68function isActorFollowersCountValid (value: string) {
69 return exists(value) && validator.isInt('' + value, { min: 0 })
70}
71
72function isActorDeleteActivityValid (activity: any) {
73 return isBaseActivityValid(activity, 'Delete')
74}
75
76function isActorFollowActivityValid (activity: any) {
77 return isBaseActivityValid(activity, 'Follow') &&
78 isActivityPubUrlValid(activity.object)
79}
80
81function isActorAcceptActivityValid (activity: any) {
82 return isBaseActivityValid(activity, 'Accept')
83}
84
85function isActorRejectActivityValid (activity: any) {
86 return isBaseActivityValid(activity, 'Reject')
87}
88
89function isActorUpdateActivityValid (activity: any) {
90 normalizeActor(activity.object)
91
92 return isBaseActivityValid(activity, 'Update') &&
93 isActorObjectValid(activity.object)
94}
95
96function normalizeActor (actor: any) {
97 if (!actor || !actor.url) return
98
99 if (typeof actor.url !== 'string') {
100 actor.url = actor.url.href || actor.url.url
101 }
102
103 if (actor.summary && typeof actor.summary === 'string') {
104 actor.summary = truncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max })
105
106 if (actor.summary.length < CONSTRAINTS_FIELDS.USERS.DESCRIPTION.min) {
107 actor.summary = null
108 }
109 }
110
111 return
112}
113
114function isValidActorHandle (handle: string) {
115 if (!exists(handle)) return false
116
117 const parts = handle.split('@')
118 if (parts.length !== 2) return false
119
120 return isHostValid(parts[1])
121}
122
123function areValidActorHandles (handles: string[]) {
124 return isArray(handles) && handles.every(h => isValidActorHandle(h))
125}
126
127// ---------------------------------------------------------------------------
128
129export {
130 normalizeActor,
131 actorNameAlphabet,
132 areValidActorHandles,
133 isActorEndpointsObjectValid,
134 isActorPublicKeyObjectValid,
135 isActorTypeValid,
136 isActorPublicKeyValid,
137 isActorPreferredUsernameValid,
138 isActorPrivateKeyValid,
139 isActorObjectValid,
140 isActorFollowingCountValid,
141 isActorFollowersCountValid,
142 isActorFollowActivityValid,
143 isActorAcceptActivityValid,
144 isActorRejectActivityValid,
145 isActorDeleteActivityValid,
146 isActorUpdateActivityValid,
147 isValidActorHandle
148}