]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/helpers/custom-validators/activitypub/actor.ts
Begin moving video channel to actor
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / activitypub / actor.ts
1 import * as Bluebird from 'bluebird'
2 import { Response } from 'express'
3 import * as validator from 'validator'
4 import { CONSTRAINTS_FIELDS } from '../../../initializers'
5 import { ActorModel } from '../../../models/activitypub/actor'
6 import { isAccountNameValid } from '../accounts'
7 import { exists, isUUIDValid } from '../misc'
8 import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels'
9 import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc'
10
11 function isActorEndpointsObjectValid (endpointObject: any) {
12 return isActivityPubUrlValid(endpointObject.sharedInbox)
13 }
14
15 function isActorPublicKeyObjectValid (publicKeyObject: any) {
16 return isActivityPubUrlValid(publicKeyObject.id) &&
17 isActivityPubUrlValid(publicKeyObject.owner) &&
18 isActorPublicKeyValid(publicKeyObject.publicKeyPem)
19 }
20
21 function isActorTypeValid (type: string) {
22 return type === 'Person' || type === 'Application' || type === 'Group'
23 }
24
25 function isActorPublicKeyValid (publicKey: string) {
26 return exists(publicKey) &&
27 typeof publicKey === 'string' &&
28 publicKey.startsWith('-----BEGIN PUBLIC KEY-----') &&
29 publicKey.endsWith('-----END PUBLIC KEY-----') &&
30 validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY)
31 }
32
33 function isActorPreferredUsernameValid (preferredUsername: string) {
34 return isAccountNameValid(preferredUsername) || isVideoChannelNameValid(preferredUsername)
35 }
36
37 const actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+')
38 function isActorNameValid (name: string) {
39 return exists(name) && validator.matches(name, actorNameRegExp)
40 }
41
42 function isActorPrivateKeyValid (privateKey: string) {
43 return exists(privateKey) &&
44 typeof privateKey === 'string' &&
45 privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') &&
46 privateKey.endsWith('-----END RSA PRIVATE KEY-----') &&
47 validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY)
48 }
49
50 function isRemoteActorValid (remoteActor: any) {
51 return isActivityPubUrlValid(remoteActor.id) &&
52 isUUIDValid(remoteActor.uuid) &&
53 isActorTypeValid(remoteActor.type) &&
54 isActivityPubUrlValid(remoteActor.following) &&
55 isActivityPubUrlValid(remoteActor.followers) &&
56 isActivityPubUrlValid(remoteActor.inbox) &&
57 isActivityPubUrlValid(remoteActor.outbox) &&
58 isActorNameValid(remoteActor.name) &&
59 isActorPreferredUsernameValid(remoteActor.preferredUsername) &&
60 isActivityPubUrlValid(remoteActor.url) &&
61 isActorPublicKeyObjectValid(remoteActor.publicKey) &&
62 isActorEndpointsObjectValid(remoteActor.endpoints) &&
63 (!remoteActor.summary || isVideoChannelDescriptionValid(remoteActor.summary)) &&
64 setValidAttributedTo(remoteActor) &&
65 // If this is not an account, it should be attributed to an account
66 // In PeerTube we use this to attach a video channel to a specific account
67 (remoteActor.type === 'Person' || remoteActor.attributedTo.length !== 0)
68 }
69
70 function isActorFollowingCountValid (value: string) {
71 return exists(value) && validator.isInt('' + value, { min: 0 })
72 }
73
74 function isActorFollowersCountValid (value: string) {
75 return exists(value) && validator.isInt('' + value, { min: 0 })
76 }
77
78 function isActorDeleteActivityValid (activity: any) {
79 return isBaseActivityValid(activity, 'Delete')
80 }
81
82 function isActorFollowActivityValid (activity: any) {
83 return isBaseActivityValid(activity, 'Follow') &&
84 isActivityPubUrlValid(activity.object)
85 }
86
87 function isActorAcceptActivityValid (activity: any) {
88 return isBaseActivityValid(activity, 'Accept')
89 }
90
91 function isActorIdExist (id: number | string, res: Response) {
92 let promise: Bluebird<ActorModel>
93
94 if (validator.isInt('' + id)) {
95 promise = ActorModel.load(+id)
96 } else { // UUID
97 promise = ActorModel.loadByUUID('' + id)
98 }
99
100 return isActorExist(promise, res)
101 }
102
103 function isLocalActorNameExist (name: string, res: Response) {
104 const promise = ActorModel.loadLocalByName(name)
105
106 return isActorExist(promise, res)
107 }
108
109 async function isActorExist (p: Bluebird<ActorModel>, res: Response) {
110 const actor = await p
111
112 if (!actor) {
113 res.status(404)
114 .send({ error: 'Actor not found' })
115 .end()
116
117 return false
118 }
119
120 res.locals.actor = actor
121
122 return true
123 }
124
125 // ---------------------------------------------------------------------------
126
127 export {
128 isActorEndpointsObjectValid,
129 isActorPublicKeyObjectValid,
130 isActorTypeValid,
131 isActorPublicKeyValid,
132 isActorPreferredUsernameValid,
133 isActorPrivateKeyValid,
134 isRemoteActorValid,
135 isActorFollowingCountValid,
136 isActorFollowersCountValid,
137 isActorFollowActivityValid,
138 isActorAcceptActivityValid,
139 isActorDeleteActivityValid,
140 isActorIdExist,
141 isLocalActorNameExist,
142 isActorNameValid,
143 isActorExist
144 }