]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/helpers/custom-validators/activitypub/actor.ts
Merge branch 'release/v1.2.0'
[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 sanitizeAndCheckActorObject (object: any) {
77 normalizeActor(object)
78
79 return isActorObjectValid(object)
80}
81
82function normalizeActor (actor: any) {
83 if (!actor || !actor.url) return
84
85 if (typeof actor.url !== 'string') {
86 actor.url = actor.url.href || actor.url.url
87 }
88
89 if (actor.summary && typeof actor.summary === 'string') {
90 actor.summary = truncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max })
91
92 if (actor.summary.length < CONSTRAINTS_FIELDS.USERS.DESCRIPTION.min) {
93 actor.summary = null
94 }
95 }
96
97 return
98}
99
100function isValidActorHandle (handle: string) {
101 if (!exists(handle)) return false
102
103 const parts = handle.split('@')
104 if (parts.length !== 2) return false
105
106 return isHostValid(parts[1])
107}
108
109function areValidActorHandles (handles: string[]) {
110 return isArray(handles) && handles.every(h => isValidActorHandle(h))
111}
112
113// ---------------------------------------------------------------------------
114
115export {
116 normalizeActor,
117 actorNameAlphabet,
118 areValidActorHandles,
119 isActorEndpointsObjectValid,
120 isActorPublicKeyObjectValid,
121 isActorTypeValid,
122 isActorPublicKeyValid,
123 isActorPreferredUsernameValid,
124 isActorPrivateKeyValid,
125 isActorObjectValid,
126 isActorFollowingCountValid,
127 isActorFollowersCountValid,
128 isActorDeleteActivityValid,
129 sanitizeAndCheckActorObject,
130 isValidActorHandle
131}