]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/helpers/custom-validators/activitypub/actor.ts
Use height instead of width to represent the video resolution
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / activitypub / actor.ts
... / ...
CommitLineData
1import * as validator from 'validator'
2import { CONSTRAINTS_FIELDS } from '../../../initializers'
3import { exists } 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 actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+')
31function isActorPreferredUsernameValid (preferredUsername: string) {
32 return exists(preferredUsername) && validator.matches(preferredUsername, actorNameRegExp)
33}
34
35function isActorPrivateKeyValid (privateKey: string) {
36 return exists(privateKey) &&
37 typeof privateKey === 'string' &&
38 privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') &&
39 // Sometimes there is a \n at the end, so just assert the string contains the end mark
40 privateKey.indexOf('-----END RSA PRIVATE KEY-----') !== -1 &&
41 validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY)
42}
43
44function isActorObjectValid (actor: any) {
45 return exists(actor) &&
46 isActivityPubUrlValid(actor.id) &&
47 isActorTypeValid(actor.type) &&
48 isActivityPubUrlValid(actor.following) &&
49 isActivityPubUrlValid(actor.followers) &&
50 isActivityPubUrlValid(actor.inbox) &&
51 isActivityPubUrlValid(actor.outbox) &&
52 isActorPreferredUsernameValid(actor.preferredUsername) &&
53 isActivityPubUrlValid(actor.url) &&
54 isActorPublicKeyObjectValid(actor.publicKey) &&
55 isActorEndpointsObjectValid(actor.endpoints) &&
56 setValidAttributedTo(actor) &&
57
58 // If this is not an account, it should be attributed to an account
59 // In PeerTube we use this to attach a video channel to a specific account
60 (actor.type === 'Person' || actor.attributedTo.length !== 0)
61}
62
63function isActorFollowingCountValid (value: string) {
64 return exists(value) && validator.isInt('' + value, { min: 0 })
65}
66
67function isActorFollowersCountValid (value: string) {
68 return exists(value) && validator.isInt('' + value, { min: 0 })
69}
70
71function isActorDeleteActivityValid (activity: any) {
72 return isBaseActivityValid(activity, 'Delete')
73}
74
75function isActorFollowActivityValid (activity: any) {
76 return isBaseActivityValid(activity, 'Follow') &&
77 isActivityPubUrlValid(activity.object)
78}
79
80function isActorAcceptActivityValid (activity: any) {
81 return isBaseActivityValid(activity, 'Accept')
82}
83
84function isActorRejectActivityValid (activity: any) {
85 return isBaseActivityValid(activity, 'Reject')
86}
87
88function isActorUpdateActivityValid (activity: any) {
89 normalizeActor(activity.object)
90
91 return isBaseActivityValid(activity, 'Update') &&
92 isActorObjectValid(activity.object)
93}
94
95function normalizeActor (actor: any) {
96 if (!actor || !actor.url) return
97
98 if (typeof actor.url !== 'string') {
99 actor.url = actor.url.href || actor.url.url
100 }
101
102 if (actor.summary && typeof actor.summary === 'string') {
103 actor.summary = truncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max })
104
105 if (actor.summary.length < CONSTRAINTS_FIELDS.USERS.DESCRIPTION.min) {
106 actor.summary = null
107 }
108 }
109
110 return
111}
112
113function isValidActorHandle (handle: string) {
114 if (!exists(handle)) return false
115
116 const parts = handle.split('@')
117 if (parts.length !== 2) return false
118
119 return isHostValid(parts[1])
120}
121
122// ---------------------------------------------------------------------------
123
124export {
125 normalizeActor,
126 isActorEndpointsObjectValid,
127 isActorPublicKeyObjectValid,
128 isActorTypeValid,
129 isActorPublicKeyValid,
130 isActorPreferredUsernameValid,
131 isActorPrivateKeyValid,
132 isActorObjectValid,
133 isActorFollowingCountValid,
134 isActorFollowersCountValid,
135 isActorFollowActivityValid,
136 isActorAcceptActivityValid,
137 isActorRejectActivityValid,
138 isActorDeleteActivityValid,
139 isActorUpdateActivityValid,
140 isValidActorHandle
141}