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