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