]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/helpers/custom-validators/activitypub/actor.ts
Add welcome modal
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / activitypub / actor.ts
... / ...
CommitLineData
1import * as validator from 'validator'
2import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
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.inbox) &&
50 isActorPreferredUsernameValid(actor.preferredUsername) &&
51 isActivityPubUrlValid(actor.url) &&
52 isActorPublicKeyObjectValid(actor.publicKey) &&
53 isActorEndpointsObjectValid(actor.endpoints) &&
54
55 (!actor.outbox || isActivityPubUrlValid(actor.outbox)) &&
56 (!actor.following || isActivityPubUrlValid(actor.following)) &&
57 (!actor.followers || isActivityPubUrlValid(actor.followers)) &&
58
59 setValidAttributedTo(actor) &&
60 // If this is a group (a channel), it should be attributed to an account
61 // In PeerTube we use this to attach a video channel to a specific account
62 (actor.type !== 'Group' || actor.attributedTo.length !== 0)
63}
64
65function isActorFollowingCountValid (value: string) {
66 return exists(value) && validator.isInt('' + value, { min: 0 })
67}
68
69function isActorFollowersCountValid (value: string) {
70 return exists(value) && validator.isInt('' + value, { min: 0 })
71}
72
73function isActorDeleteActivityValid (activity: any) {
74 return isBaseActivityValid(activity, 'Delete')
75}
76
77function sanitizeAndCheckActorObject (object: any) {
78 normalizeActor(object)
79
80 return isActorObjectValid(object)
81}
82
83function normalizeActor (actor: any) {
84 if (!actor || !actor.url) return
85
86 if (typeof actor.url !== 'string') {
87 actor.url = actor.url.href || actor.url.url
88 }
89
90 if (actor.summary && typeof actor.summary === 'string') {
91 actor.summary = truncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max })
92
93 if (actor.summary.length < CONSTRAINTS_FIELDS.USERS.DESCRIPTION.min) {
94 actor.summary = null
95 }
96 }
97
98 return
99}
100
101function isValidActorHandle (handle: string) {
102 if (!exists(handle)) return false
103
104 const parts = handle.split('@')
105 if (parts.length !== 2) return false
106
107 return isHostValid(parts[1])
108}
109
110function areValidActorHandles (handles: string[]) {
111 return isArray(handles) && handles.every(h => isValidActorHandle(h))
112}
113
114// ---------------------------------------------------------------------------
115
116export {
117 normalizeActor,
118 actorNameAlphabet,
119 areValidActorHandles,
120 isActorEndpointsObjectValid,
121 isActorPublicKeyObjectValid,
122 isActorTypeValid,
123 isActorPublicKeyValid,
124 isActorPreferredUsernameValid,
125 isActorPrivateKeyValid,
126 isActorObjectValid,
127 isActorFollowingCountValid,
128 isActorFollowersCountValid,
129 isActorDeleteActivityValid,
130 sanitizeAndCheckActorObject,
131 isValidActorHandle
132}