diff options
author | Chocobozzz <me@florianbigard.com> | 2017-12-19 10:34:56 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2017-12-19 10:53:16 +0100 |
commit | e12a009254de33bcdbd8334992980fa029c3e10d (patch) | |
tree | 85c6b576d9f76fee33b22e1fdbdca5e9daa24d50 /server | |
parent | ce33ee01cd3806201b676c318e9aa930032921b2 (diff) | |
download | PeerTube-e12a009254de33bcdbd8334992980fa029c3e10d.tar.gz PeerTube-e12a009254de33bcdbd8334992980fa029c3e10d.tar.zst PeerTube-e12a009254de33bcdbd8334992980fa029c3e10d.zip |
Status are sent to mastodon
Diffstat (limited to 'server')
18 files changed, 130 insertions, 109 deletions
diff --git a/server/helpers/custom-validators/activitypub/actor.ts b/server/helpers/custom-validators/activitypub/actor.ts index 5930bd5da..ec8da3350 100644 --- a/server/helpers/custom-validators/activitypub/actor.ts +++ b/server/helpers/custom-validators/activitypub/actor.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as validator from 'validator' | 1 | import * as validator from 'validator' |
2 | import { CONSTRAINTS_FIELDS } from '../../../initializers' | 2 | import { CONSTRAINTS_FIELDS } from '../../../initializers' |
3 | import { isAccountNameValid } from '../accounts' | 3 | import { isAccountNameValid } from '../accounts' |
4 | import { exists, isUUIDValid } from '../misc' | 4 | import { exists } from '../misc' |
5 | import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels' | 5 | import { isVideoChannelNameValid } from '../video-channels' |
6 | import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc' | 6 | import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc' |
7 | 7 | ||
8 | function isActorEndpointsObjectValid (endpointObject: any) { | 8 | function isActorEndpointsObjectValid (endpointObject: any) { |
@@ -23,41 +23,39 @@ function isActorPublicKeyValid (publicKey: string) { | |||
23 | return exists(publicKey) && | 23 | return exists(publicKey) && |
24 | typeof publicKey === 'string' && | 24 | typeof publicKey === 'string' && |
25 | publicKey.startsWith('-----BEGIN PUBLIC KEY-----') && | 25 | publicKey.startsWith('-----BEGIN PUBLIC KEY-----') && |
26 | publicKey.endsWith('-----END PUBLIC KEY-----') && | 26 | publicKey.indexOf('-----END PUBLIC KEY-----') !== -1 && |
27 | validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY) | 27 | validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY) |
28 | } | 28 | } |
29 | 29 | ||
30 | const actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+') | ||
30 | function isActorPreferredUsernameValid (preferredUsername: string) { | 31 | function isActorPreferredUsernameValid (preferredUsername: string) { |
31 | return isAccountNameValid(preferredUsername) || isVideoChannelNameValid(preferredUsername) | 32 | return exists(preferredUsername) && validator.matches(preferredUsername, actorNameRegExp) |
32 | } | 33 | } |
33 | 34 | ||
34 | const actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+') | ||
35 | function isActorNameValid (name: string) { | 35 | function isActorNameValid (name: string) { |
36 | return exists(name) && validator.matches(name, actorNameRegExp) | 36 | return isAccountNameValid(name) || isVideoChannelNameValid(name) |
37 | } | 37 | } |
38 | 38 | ||
39 | function isActorPrivateKeyValid (privateKey: string) { | 39 | function isActorPrivateKeyValid (privateKey: string) { |
40 | return exists(privateKey) && | 40 | return exists(privateKey) && |
41 | typeof privateKey === 'string' && | 41 | typeof privateKey === 'string' && |
42 | privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') && | 42 | privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') && |
43 | privateKey.endsWith('-----END RSA PRIVATE KEY-----') && | 43 | // Sometimes there is a \n at the end, so just assert the string contains the end mark |
44 | privateKey.indexOf('-----END RSA PRIVATE KEY-----') !== -1 && | ||
44 | validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY) | 45 | validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY) |
45 | } | 46 | } |
46 | 47 | ||
47 | function isRemoteActorValid (remoteActor: any) { | 48 | function isRemoteActorValid (remoteActor: any) { |
48 | return isActivityPubUrlValid(remoteActor.id) && | 49 | return isActivityPubUrlValid(remoteActor.id) && |
49 | isUUIDValid(remoteActor.uuid) && | ||
50 | isActorTypeValid(remoteActor.type) && | 50 | isActorTypeValid(remoteActor.type) && |
51 | isActivityPubUrlValid(remoteActor.following) && | 51 | isActivityPubUrlValid(remoteActor.following) && |
52 | isActivityPubUrlValid(remoteActor.followers) && | 52 | isActivityPubUrlValid(remoteActor.followers) && |
53 | isActivityPubUrlValid(remoteActor.inbox) && | 53 | isActivityPubUrlValid(remoteActor.inbox) && |
54 | isActivityPubUrlValid(remoteActor.outbox) && | 54 | isActivityPubUrlValid(remoteActor.outbox) && |
55 | isActorNameValid(remoteActor.name) && | ||
56 | isActorPreferredUsernameValid(remoteActor.preferredUsername) && | 55 | isActorPreferredUsernameValid(remoteActor.preferredUsername) && |
57 | isActivityPubUrlValid(remoteActor.url) && | 56 | isActivityPubUrlValid(remoteActor.url) && |
58 | isActorPublicKeyObjectValid(remoteActor.publicKey) && | 57 | isActorPublicKeyObjectValid(remoteActor.publicKey) && |
59 | isActorEndpointsObjectValid(remoteActor.endpoints) && | 58 | isActorEndpointsObjectValid(remoteActor.endpoints) && |
60 | (!remoteActor.summary || isVideoChannelDescriptionValid(remoteActor.summary)) && | ||
61 | setValidAttributedTo(remoteActor) && | 59 | setValidAttributedTo(remoteActor) && |
62 | // If this is not an account, it should be attributed to an account | 60 | // If this is not an account, it should be attributed to an account |
63 | // In PeerTube we use this to attach a video channel to a specific account | 61 | // In PeerTube we use this to attach a video channel to a specific account |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 04b610b7a..4cb54dc93 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -316,7 +316,7 @@ const CACHE = { | |||
316 | } | 316 | } |
317 | } | 317 | } |
318 | 318 | ||
319 | const ACCEPT_HEADERS = ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS.concat('html', 'application/json') | 319 | const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS) |
320 | 320 | ||
321 | // --------------------------------------------------------------------------- | 321 | // --------------------------------------------------------------------------- |
322 | 322 | ||
diff --git a/server/initializers/migrations/0130-video-channel-actor.ts b/server/initializers/migrations/0130-video-channel-actor.ts index 15b67be81..2e4694a75 100644 --- a/server/initializers/migrations/0130-video-channel-actor.ts +++ b/server/initializers/migrations/0130-video-channel-actor.ts | |||
@@ -22,7 +22,7 @@ async function up (utils: { | |||
22 | id integer NOT NULL, | 22 | id integer NOT NULL, |
23 | type enum_actor_type NOT NULL, | 23 | type enum_actor_type NOT NULL, |
24 | uuid uuid NOT NULL, | 24 | uuid uuid NOT NULL, |
25 | name character varying(255) NOT NULL, | 25 | "preferredUsername" character varying(255) NOT NULL, |
26 | url character varying(2000) NOT NULL, | 26 | url character varying(2000) NOT NULL, |
27 | "publicKey" character varying(5000), | 27 | "publicKey" character varying(5000), |
28 | "privateKey" character varying(5000), | 28 | "privateKey" character varying(5000), |
@@ -50,7 +50,7 @@ async function up (utils: { | |||
50 | `ALTER SEQUENCE actor_id_seq OWNED BY actor.id`, | 50 | `ALTER SEQUENCE actor_id_seq OWNED BY actor.id`, |
51 | `ALTER TABLE ONLY actor ALTER COLUMN id SET DEFAULT nextval('actor_id_seq'::regclass)`, | 51 | `ALTER TABLE ONLY actor ALTER COLUMN id SET DEFAULT nextval('actor_id_seq'::regclass)`, |
52 | `ALTER TABLE ONLY actor ADD CONSTRAINT actor_pkey PRIMARY KEY (id);`, | 52 | `ALTER TABLE ONLY actor ADD CONSTRAINT actor_pkey PRIMARY KEY (id);`, |
53 | `CREATE UNIQUE INDEX actor_name_server_id ON actor USING btree (name, "serverId")`, | 53 | `CREATE UNIQUE INDEX actor_preferred_username_server_id ON actor USING btree ("preferredUsername", "serverId")`, |
54 | `ALTER TABLE ONLY actor | 54 | `ALTER TABLE ONLY actor |
55 | ADD CONSTRAINT "actor_avatarId_fkey" FOREIGN KEY ("avatarId") REFERENCES avatar(id) ON UPDATE CASCADE ON DELETE CASCADE`, | 55 | ADD CONSTRAINT "actor_avatarId_fkey" FOREIGN KEY ("avatarId") REFERENCES avatar(id) ON UPDATE CASCADE ON DELETE CASCADE`, |
56 | `ALTER TABLE ONLY actor | 56 | `ALTER TABLE ONLY actor |
@@ -68,7 +68,7 @@ async function up (utils: { | |||
68 | ` | 68 | ` |
69 | INSERT INTO "actor" | 69 | INSERT INTO "actor" |
70 | ( | 70 | ( |
71 | type, uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 71 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
72 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 72 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
73 | ) | 73 | ) |
74 | SELECT | 74 | SELECT |
@@ -83,7 +83,7 @@ async function up (utils: { | |||
83 | ` | 83 | ` |
84 | INSERT INTO "actor" | 84 | INSERT INTO "actor" |
85 | ( | 85 | ( |
86 | type, uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 86 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
87 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 87 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
88 | ) | 88 | ) |
89 | SELECT | 89 | SELECT |
@@ -119,7 +119,7 @@ async function up (utils: { | |||
119 | const query = ` | 119 | const query = ` |
120 | INSERT INTO actor | 120 | INSERT INTO actor |
121 | ( | 121 | ( |
122 | type, uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 122 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
123 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 123 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
124 | ) | 124 | ) |
125 | SELECT | 125 | SELECT |
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index c3de4bdce..ff0a291e8 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -11,7 +11,7 @@ import { ActorModel } from '../../models/activitypub/actor' | |||
11 | import { ServerModel } from '../../models/server/server' | 11 | import { ServerModel } from '../../models/server/server' |
12 | import { VideoChannelModel } from '../../models/video/video-channel' | 12 | import { VideoChannelModel } from '../../models/video/video-channel' |
13 | 13 | ||
14 | // Set account keys, this could be long so process after the account creation and do not block the client | 14 | // Set account keys, this could be long so process after the account creation and do not block the client |
15 | function setAsyncActorKeys (actor: ActorModel) { | 15 | function setAsyncActorKeys (actor: ActorModel) { |
16 | return createPrivateAndPublicKeys() | 16 | return createPrivateAndPublicKeys() |
17 | .then(({ publicKey, privateKey }) => { | 17 | .then(({ publicKey, privateKey }) => { |
@@ -107,7 +107,7 @@ function saveActorAndServerAndModelIfNotExist ( | |||
107 | 107 | ||
108 | type FetchRemoteActorResult = { | 108 | type FetchRemoteActorResult = { |
109 | actor: ActorModel | 109 | actor: ActorModel |
110 | preferredUsername: string | 110 | name: string |
111 | summary: string | 111 | summary: string |
112 | attributedTo: ActivityPubAttributedTo[] | 112 | attributedTo: ActivityPubAttributedTo[] |
113 | } | 113 | } |
@@ -142,8 +142,8 @@ async function fetchRemoteActor (actorUrl: string): Promise<FetchRemoteActorResu | |||
142 | const actor = new ActorModel({ | 142 | const actor = new ActorModel({ |
143 | type: actorJSON.type, | 143 | type: actorJSON.type, |
144 | uuid: actorJSON.uuid, | 144 | uuid: actorJSON.uuid, |
145 | name: actorJSON.name, | 145 | preferredUsername: actorJSON.preferredUsername, |
146 | url: actorJSON.url, | 146 | url: actorJSON.id, |
147 | publicKey: actorJSON.publicKey.publicKeyPem, | 147 | publicKey: actorJSON.publicKey.publicKeyPem, |
148 | privateKey: null, | 148 | privateKey: null, |
149 | followersCount: followersCount, | 149 | followersCount: followersCount, |
@@ -155,19 +155,20 @@ async function fetchRemoteActor (actorUrl: string): Promise<FetchRemoteActorResu | |||
155 | followingUrl: actorJSON.following | 155 | followingUrl: actorJSON.following |
156 | }) | 156 | }) |
157 | 157 | ||
158 | const name = actorJSON.name || actorJSON.preferredUsername | ||
158 | return { | 159 | return { |
159 | actor, | 160 | actor, |
160 | preferredUsername: actorJSON.preferredUsername, | 161 | name, |
161 | summary: actorJSON.summary, | 162 | summary: actorJSON.summary, |
162 | attributedTo: actorJSON.attributedTo | 163 | attributedTo: actorJSON.attributedTo |
163 | } | 164 | } |
164 | } | 165 | } |
165 | 166 | ||
166 | function buildActorInstance (type: ActivityPubActorType, url: string, name: string, uuid?: string) { | 167 | function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { |
167 | return new ActorModel({ | 168 | return new ActorModel({ |
168 | type, | 169 | type, |
169 | url, | 170 | url, |
170 | name, | 171 | preferredUsername, |
171 | uuid, | 172 | uuid, |
172 | publicKey: null, | 173 | publicKey: null, |
173 | privateKey: null, | 174 | privateKey: null, |
@@ -210,7 +211,7 @@ async function fetchActorTotalItems (url: string) { | |||
210 | 211 | ||
211 | function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t: Transaction) { | 212 | function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t: Transaction) { |
212 | const account = new AccountModel({ | 213 | const account = new AccountModel({ |
213 | name: result.preferredUsername, | 214 | name: result.name, |
214 | actorId: actor.id | 215 | actorId: actor.id |
215 | }) | 216 | }) |
216 | 217 | ||
@@ -219,7 +220,7 @@ function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t: Tran | |||
219 | 220 | ||
220 | async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResult, ownerActor: ActorModel, t: Transaction) { | 221 | async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResult, ownerActor: ActorModel, t: Transaction) { |
221 | const videoChannel = new VideoChannelModel({ | 222 | const videoChannel = new VideoChannelModel({ |
222 | name: result.preferredUsername, | 223 | name: result.name, |
223 | description: result.summary, | 224 | description: result.summary, |
224 | actorId: actor.id, | 225 | actorId: actor.id, |
225 | accountId: ownerActor.Account.id | 226 | accountId: ownerActor.Account.id |
diff --git a/server/lib/activitypub/send/misc.ts b/server/lib/activitypub/send/misc.ts index 14101e630..2dc8d3d59 100644 --- a/server/lib/activitypub/send/misc.ts +++ b/server/lib/activitypub/send/misc.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { Activity } from '../../../../shared/models/activitypub' | 2 | import { Activity, ActivityAudience } from '../../../../shared/models/activitypub' |
3 | import { logger } from '../../../helpers' | 3 | import { logger } from '../../../helpers' |
4 | import { ACTIVITY_PUB } from '../../../initializers' | 4 | import { ACTIVITY_PUB } from '../../../initializers' |
5 | import { ActorModel } from '../../../models/activitypub/actor' | 5 | import { ActorModel } from '../../../models/activitypub/actor' |
@@ -116,6 +116,10 @@ async function getAudience (actorSender: ActorModel, t: Transaction, isPublic = | |||
116 | return { to, cc } | 116 | return { to, cc } |
117 | } | 117 | } |
118 | 118 | ||
119 | function audiencify (object: any, audience: ActivityAudience) { | ||
120 | return Object.assign(object, audience) | ||
121 | } | ||
122 | |||
119 | async function computeFollowerUris (toActorFollower: ActorModel[], followersException: ActorModel[], t: Transaction) { | 123 | async function computeFollowerUris (toActorFollower: ActorModel[], followersException: ActorModel[], t: Transaction) { |
120 | const toActorFollowerIds = toActorFollower.map(a => a.id) | 124 | const toActorFollowerIds = toActorFollower.map(a => a.id) |
121 | 125 | ||
@@ -133,5 +137,6 @@ export { | |||
133 | getOriginVideoAudience, | 137 | getOriginVideoAudience, |
134 | getActorsInvolvedInVideo, | 138 | getActorsInvolvedInVideo, |
135 | getObjectFollowersAudience, | 139 | getObjectFollowersAudience, |
136 | forwardActivity | 140 | forwardActivity, |
141 | audiencify | ||
137 | } | 142 | } |
diff --git a/server/lib/activitypub/send/send-accept.ts b/server/lib/activitypub/send/send-accept.ts index 7579884a7..4eaa329d9 100644 --- a/server/lib/activitypub/send/send-accept.ts +++ b/server/lib/activitypub/send/send-accept.ts | |||
@@ -1,16 +1,20 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { ActivityAccept } from '../../../../shared/models/activitypub' | 2 | import { ActivityAccept, ActivityFollow } from '../../../../shared/models/activitypub' |
3 | import { ActorModel } from '../../../models/activitypub/actor' | 3 | import { ActorModel } from '../../../models/activitypub/actor' |
4 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 4 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
5 | import { getActorFollowAcceptActivityPubUrl } from '../url' | 5 | import { getActorFollowAcceptActivityPubUrl, getActorFollowActivityPubUrl } from '../url' |
6 | import { unicastTo } from './misc' | 6 | import { unicastTo } from './misc' |
7 | import { followActivityData } from './send-follow' | ||
7 | 8 | ||
8 | async function sendAccept (actorFollow: ActorFollowModel, t: Transaction) { | 9 | async function sendAccept (actorFollow: ActorFollowModel, t: Transaction) { |
9 | const follower = actorFollow.ActorFollower | 10 | const follower = actorFollow.ActorFollower |
10 | const me = actorFollow.ActorFollowing | 11 | const me = actorFollow.ActorFollowing |
11 | 12 | ||
13 | const followUrl = getActorFollowActivityPubUrl(actorFollow) | ||
14 | const followData = followActivityData(followUrl, follower, me) | ||
15 | |||
12 | const url = getActorFollowAcceptActivityPubUrl(actorFollow) | 16 | const url = getActorFollowAcceptActivityPubUrl(actorFollow) |
13 | const data = acceptActivityData(url, me) | 17 | const data = acceptActivityData(url, me, followData) |
14 | 18 | ||
15 | return unicastTo(data, me, follower.inboxUrl, t) | 19 | return unicastTo(data, me, follower.inboxUrl, t) |
16 | } | 20 | } |
@@ -23,10 +27,11 @@ export { | |||
23 | 27 | ||
24 | // --------------------------------------------------------------------------- | 28 | // --------------------------------------------------------------------------- |
25 | 29 | ||
26 | function acceptActivityData (url: string, byActor: ActorModel): ActivityAccept { | 30 | function acceptActivityData (url: string, byActor: ActorModel, followActivityData: ActivityFollow): ActivityAccept { |
27 | return { | 31 | return { |
28 | type: 'Accept', | 32 | type: 'Accept', |
29 | id: url, | 33 | id: url, |
30 | actor: byActor.url | 34 | actor: byActor.url, |
35 | object: followActivityData | ||
31 | } | 36 | } |
32 | } | 37 | } |
diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts index d26c24838..249dd91dc 100644 --- a/server/lib/activitypub/send/send-create.ts +++ b/server/lib/activitypub/send/send-create.ts | |||
@@ -7,6 +7,7 @@ import { VideoModel } from '../../../models/video/video' | |||
7 | import { VideoAbuseModel } from '../../../models/video/video-abuse' | 7 | import { VideoAbuseModel } from '../../../models/video/video-abuse' |
8 | import { getVideoAbuseActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoViewActivityPubUrl } from '../url' | 8 | import { getVideoAbuseActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoViewActivityPubUrl } from '../url' |
9 | import { | 9 | import { |
10 | audiencify, | ||
10 | broadcastToFollowers, | 11 | broadcastToFollowers, |
11 | getActorsInvolvedInVideo, | 12 | getActorsInvolvedInVideo, |
12 | getAudience, | 13 | getAudience, |
@@ -16,9 +17,11 @@ import { | |||
16 | } from './misc' | 17 | } from './misc' |
17 | 18 | ||
18 | async function sendCreateVideo (video: VideoModel, t: Transaction) { | 19 | async function sendCreateVideo (video: VideoModel, t: Transaction) { |
19 | const byActor = video.VideoChannel.Account.Actor | 20 | if (video.privacy === VideoPrivacy.PRIVATE) return |
20 | 21 | ||
22 | const byActor = video.VideoChannel.Account.Actor | ||
21 | const videoObject = video.toActivityPubObject() | 23 | const videoObject = video.toActivityPubObject() |
24 | |||
22 | const audience = await getAudience(byActor, t, video.privacy === VideoPrivacy.PUBLIC) | 25 | const audience = await getAudience(byActor, t, video.privacy === VideoPrivacy.PUBLIC) |
23 | const data = await createActivityData(video.url, byActor, videoObject, t, audience) | 26 | const data = await createActivityData(video.url, byActor, videoObject, t, audience) |
24 | 27 | ||
@@ -93,14 +96,12 @@ async function createActivityData ( | |||
93 | audience = await getAudience(byActor, t) | 96 | audience = await getAudience(byActor, t) |
94 | } | 97 | } |
95 | 98 | ||
96 | return { | 99 | return audiencify({ |
97 | type: 'Create', | 100 | type: 'Create', |
98 | id: url, | 101 | id: url, |
99 | actor: byActor.url, | 102 | actor: byActor.url, |
100 | to: audience.to, | 103 | object: audiencify(object, audience) |
101 | cc: audience.cc, | 104 | }, audience) |
102 | object | ||
103 | } | ||
104 | } | 105 | } |
105 | 106 | ||
106 | function createDislikeActivityData (byActor: ActorModel, video: VideoModel) { | 107 | function createDislikeActivityData (byActor: ActorModel, video: VideoModel) { |
diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts index 7e0c73796..743646455 100644 --- a/server/lib/activitypub/send/send-like.ts +++ b/server/lib/activitypub/send/send-like.ts | |||
@@ -4,6 +4,7 @@ import { ActorModel } from '../../../models/activitypub/actor' | |||
4 | import { VideoModel } from '../../../models/video/video' | 4 | import { VideoModel } from '../../../models/video/video' |
5 | import { getVideoLikeActivityPubUrl } from '../url' | 5 | import { getVideoLikeActivityPubUrl } from '../url' |
6 | import { | 6 | import { |
7 | audiencify, | ||
7 | broadcastToFollowers, | 8 | broadcastToFollowers, |
8 | getActorsInvolvedInVideo, | 9 | getActorsInvolvedInVideo, |
9 | getAudience, | 10 | getAudience, |
@@ -44,14 +45,12 @@ async function likeActivityData ( | |||
44 | audience = await getAudience(byActor, t) | 45 | audience = await getAudience(byActor, t) |
45 | } | 46 | } |
46 | 47 | ||
47 | return { | 48 | return audiencify({ |
48 | type: 'Like', | 49 | type: 'Like', |
49 | id: url, | 50 | id: url, |
50 | actor: byActor.url, | 51 | actor: byActor.url, |
51 | to: audience.to, | ||
52 | cc: audience.cc, | ||
53 | object: video.url | 52 | object: video.url |
54 | } | 53 | }, audience) |
55 | } | 54 | } |
56 | 55 | ||
57 | // --------------------------------------------------------------------------- | 56 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts index 92271b700..3a0597fba 100644 --- a/server/lib/activitypub/send/send-undo.ts +++ b/server/lib/activitypub/send/send-undo.ts | |||
@@ -11,6 +11,7 @@ import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | |||
11 | import { VideoModel } from '../../../models/video/video' | 11 | import { VideoModel } from '../../../models/video/video' |
12 | import { getActorFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url' | 12 | import { getActorFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url' |
13 | import { | 13 | import { |
14 | audiencify, | ||
14 | broadcastToFollowers, | 15 | broadcastToFollowers, |
15 | getActorsInvolvedInVideo, | 16 | getActorsInvolvedInVideo, |
16 | getAudience, | 17 | getAudience, |
@@ -112,12 +113,10 @@ async function undoActivityData ( | |||
112 | audience = await getAudience(byActor, t) | 113 | audience = await getAudience(byActor, t) |
113 | } | 114 | } |
114 | 115 | ||
115 | return { | 116 | return audiencify({ |
116 | type: 'Undo', | 117 | type: 'Undo', |
117 | id: url, | 118 | id: url, |
118 | actor: byActor.url, | 119 | actor: byActor.url, |
119 | to: audience.to, | ||
120 | cc: audience.cc, | ||
121 | object | 120 | object |
122 | } | 121 | }, audience) |
123 | } | 122 | } |
diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts index 48bbbcac1..b623fec6c 100644 --- a/server/lib/activitypub/send/send-update.ts +++ b/server/lib/activitypub/send/send-update.ts | |||
@@ -5,7 +5,7 @@ import { ActorModel } from '../../../models/activitypub/actor' | |||
5 | import { VideoModel } from '../../../models/video/video' | 5 | import { VideoModel } from '../../../models/video/video' |
6 | import { VideoShareModel } from '../../../models/video/video-share' | 6 | import { VideoShareModel } from '../../../models/video/video-share' |
7 | import { getUpdateActivityPubUrl } from '../url' | 7 | import { getUpdateActivityPubUrl } from '../url' |
8 | import { broadcastToFollowers, getAudience } from './misc' | 8 | import { audiencify, broadcastToFollowers, getAudience } from './misc' |
9 | 9 | ||
10 | async function sendUpdateVideo (video: VideoModel, t: Transaction) { | 10 | async function sendUpdateVideo (video: VideoModel, t: Transaction) { |
11 | const byActor = video.VideoChannel.Account.Actor | 11 | const byActor = video.VideoChannel.Account.Actor |
@@ -41,12 +41,10 @@ async function updateActivityData ( | |||
41 | audience = await getAudience(byActor, t) | 41 | audience = await getAudience(byActor, t) |
42 | } | 42 | } |
43 | 43 | ||
44 | return { | 44 | return audiencify({ |
45 | type: 'Update', | 45 | type: 'Update', |
46 | id: url, | 46 | id: url, |
47 | actor: byActor.url, | 47 | actor: byActor.url, |
48 | to: audience.to, | 48 | object: audiencify(object, audience) |
49 | cc: audience.cc, | 49 | }, audience) |
50 | object | ||
51 | } | ||
52 | } | 50 | } |
diff --git a/server/lib/activitypub/share.ts b/server/lib/activitypub/share.ts index fb01368ec..386ae362a 100644 --- a/server/lib/activitypub/share.ts +++ b/server/lib/activitypub/share.ts | |||
@@ -1,10 +1,13 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { VideoPrivacy } from '../../../shared/models/videos' | ||
2 | import { getServerActor } from '../../helpers' | 3 | import { getServerActor } from '../../helpers' |
3 | import { VideoModel } from '../../models/video/video' | 4 | import { VideoModel } from '../../models/video/video' |
4 | import { VideoShareModel } from '../../models/video/video-share' | 5 | import { VideoShareModel } from '../../models/video/video-share' |
5 | import { sendVideoAnnounceToFollowers } from './send' | 6 | import { sendVideoAnnounceToFollowers } from './send' |
6 | 7 | ||
7 | async function shareVideoByServerAndChannel (video: VideoModel, t: Transaction) { | 8 | async function shareVideoByServerAndChannel (video: VideoModel, t: Transaction) { |
9 | if (video.privacy === VideoPrivacy.PRIVATE) return | ||
10 | |||
8 | const serverActor = await getServerActor() | 11 | const serverActor = await getServerActor() |
9 | 12 | ||
10 | const serverShare = VideoShareModel.create({ | 13 | const serverShare = VideoShareModel.create({ |
diff --git a/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-broadcast-handler.ts b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-broadcast-handler.ts index 8040dde2a..3c4d5556f 100644 --- a/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-broadcast-handler.ts +++ b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-broadcast-handler.ts | |||
@@ -1,15 +1,17 @@ | |||
1 | import { doRequest, logger } from '../../../helpers' | 1 | import { doRequest, logger } from '../../../helpers' |
2 | import { ActivityPubHttpPayload, computeBody, maybeRetryRequestLater } from './activitypub-http-job-scheduler' | 2 | import { ActivityPubHttpPayload, buildSignedRequestOptions, computeBody, maybeRetryRequestLater } from './activitypub-http-job-scheduler' |
3 | 3 | ||
4 | async function process (payload: ActivityPubHttpPayload, jobId: number) { | 4 | async function process (payload: ActivityPubHttpPayload, jobId: number) { |
5 | logger.info('Processing ActivityPub broadcast in job %d.', jobId) | 5 | logger.info('Processing ActivityPub broadcast in job %d.', jobId) |
6 | 6 | ||
7 | const body = await computeBody(payload) | 7 | const body = await computeBody(payload) |
8 | const httpSignatureOptions = await buildSignedRequestOptions(payload) | ||
8 | 9 | ||
9 | const options = { | 10 | const options = { |
10 | method: 'POST', | 11 | method: 'POST', |
11 | uri: '', | 12 | uri: '', |
12 | json: body | 13 | json: body, |
14 | httpSignature: httpSignatureOptions | ||
13 | } | 15 | } |
14 | 16 | ||
15 | for (const uri of payload.uris) { | 17 | for (const uri of payload.uris) { |
diff --git a/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler.ts b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler.ts index 95a5d3ff2..88885cf97 100644 --- a/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler.ts +++ b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { JobCategory } from '../../../../shared' | 1 | import { JobCategory } from '../../../../shared' |
2 | import { buildSignedActivity, logger } from '../../../helpers' | 2 | import { buildSignedActivity, getServerActor, logger } from '../../../helpers' |
3 | import { ACTIVITY_PUB } from '../../../initializers' | 3 | import { ACTIVITY_PUB } from '../../../initializers' |
4 | import { ActorModel } from '../../../models/activitypub/actor' | 4 | import { ActorModel } from '../../../models/activitypub/actor' |
5 | import { JobHandler, JobScheduler } from '../job-scheduler' | 5 | import { JobHandler, JobScheduler } from '../job-scheduler' |
@@ -46,16 +46,36 @@ async function computeBody (payload: ActivityPubHttpPayload) { | |||
46 | 46 | ||
47 | if (payload.signatureActorId) { | 47 | if (payload.signatureActorId) { |
48 | const actorSignature = await ActorModel.load(payload.signatureActorId) | 48 | const actorSignature = await ActorModel.load(payload.signatureActorId) |
49 | if (!actorSignature) throw new Error('Unknown signature account id.') | 49 | if (!actorSignature) throw new Error('Unknown signature actor id.') |
50 | body = await buildSignedActivity(actorSignature, payload.body) | 50 | body = await buildSignedActivity(actorSignature, payload.body) |
51 | } | 51 | } |
52 | 52 | ||
53 | return body | 53 | return body |
54 | } | 54 | } |
55 | 55 | ||
56 | async function buildSignedRequestOptions (payload: ActivityPubHttpPayload) { | ||
57 | let actor: ActorModel | ||
58 | if (payload.signatureActorId) { | ||
59 | actor = await ActorModel.load(payload.signatureActorId) | ||
60 | if (!actor) throw new Error('Unknown signature actor id.') | ||
61 | } else { | ||
62 | // We need to sign the request, so use the server | ||
63 | actor = await getServerActor() | ||
64 | } | ||
65 | |||
66 | const keyId = actor.getWebfingerUrl() | ||
67 | return { | ||
68 | algorithm: 'rsa-sha256', | ||
69 | authorizationHeaderName: 'Signature', | ||
70 | keyId, | ||
71 | key: actor.privateKey | ||
72 | } | ||
73 | } | ||
74 | |||
56 | export { | 75 | export { |
57 | ActivityPubHttpPayload, | 76 | ActivityPubHttpPayload, |
58 | activitypubHttpJobScheduler, | 77 | activitypubHttpJobScheduler, |
59 | maybeRetryRequestLater, | 78 | maybeRetryRequestLater, |
60 | computeBody | 79 | computeBody, |
80 | buildSignedRequestOptions | ||
61 | } | 81 | } |
diff --git a/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-unicast-handler.ts b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-unicast-handler.ts index f16cfcec3..7a5caa679 100644 --- a/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-unicast-handler.ts +++ b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-unicast-handler.ts | |||
@@ -1,16 +1,18 @@ | |||
1 | import { doRequest, logger } from '../../../helpers' | 1 | import { doRequest, logger } from '../../../helpers' |
2 | import { ActivityPubHttpPayload, computeBody, maybeRetryRequestLater } from './activitypub-http-job-scheduler' | 2 | import { ActivityPubHttpPayload, buildSignedRequestOptions, computeBody, maybeRetryRequestLater } from './activitypub-http-job-scheduler' |
3 | 3 | ||
4 | async function process (payload: ActivityPubHttpPayload, jobId: number) { | 4 | async function process (payload: ActivityPubHttpPayload, jobId: number) { |
5 | logger.info('Processing ActivityPub unicast in job %d.', jobId) | 5 | logger.info('Processing ActivityPub unicast in job %d.', jobId) |
6 | 6 | ||
7 | const body = await computeBody(payload) | 7 | const body = await computeBody(payload) |
8 | const httpSignatureOptions = await buildSignedRequestOptions(payload) | ||
8 | 9 | ||
9 | const uri = payload.uris[0] | 10 | const uri = payload.uris[0] |
10 | const options = { | 11 | const options = { |
11 | method: 'POST', | 12 | method: 'POST', |
12 | uri, | 13 | uri, |
13 | json: body | 14 | json: body, |
15 | httpSignature: httpSignatureOptions | ||
14 | } | 16 | } |
15 | 17 | ||
16 | try { | 18 | try { |
diff --git a/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts b/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts index 47b12e66f..d905882be 100644 --- a/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts +++ b/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { VideoPrivacy } from '../../../../shared/models/videos' | ||
2 | import { computeResolutionsToTranscode, logger } from '../../../helpers' | 3 | import { computeResolutionsToTranscode, logger } from '../../../helpers' |
3 | import { sequelizeTypescript } from '../../../initializers' | 4 | import { sequelizeTypescript } from '../../../initializers' |
4 | import { VideoModel } from '../../../models/video/video' | 5 | import { VideoModel } from '../../../models/video/video' |
@@ -35,9 +36,11 @@ async function onSuccess (jobId: number, video: VideoModel, jobScheduler: JobSch | |||
35 | // Video does not exist anymore | 36 | // Video does not exist anymore |
36 | if (!videoDatabase) return undefined | 37 | if (!videoDatabase) return undefined |
37 | 38 | ||
38 | // Now we'll add the video's meta data to our followers | 39 | if (video.privacy !== VideoPrivacy.PRIVATE) { |
39 | await sendCreateVideo(video, undefined) | 40 | // Now we'll add the video's meta data to our followers |
40 | await shareVideoByServerAndChannel(video, undefined) | 41 | await sendCreateVideo(video, undefined) |
42 | await shareVideoByServerAndChannel(video, undefined) | ||
43 | } | ||
41 | 44 | ||
42 | const originalFileHeight = await videoDatabase.getOriginalFileHeight() | 45 | const originalFileHeight = await videoDatabase.getOriginalFileHeight() |
43 | 46 | ||
diff --git a/server/lib/jobs/transcoding-job-scheduler/video-file-transcoder-handler.ts b/server/lib/jobs/transcoding-job-scheduler/video-file-transcoder-handler.ts index 8957b4565..409123bfe 100644 --- a/server/lib/jobs/transcoding-job-scheduler/video-file-transcoder-handler.ts +++ b/server/lib/jobs/transcoding-job-scheduler/video-file-transcoder-handler.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { VideoResolution } from '../../../../shared' | 1 | import { VideoResolution } from '../../../../shared' |
2 | import { VideoPrivacy } from '../../../../shared/models/videos' | ||
2 | import { logger } from '../../../helpers' | 3 | import { logger } from '../../../helpers' |
3 | import { VideoModel } from '../../../models/video/video' | 4 | import { VideoModel } from '../../../models/video/video' |
4 | import { sendUpdateVideo } from '../../activitypub/send' | 5 | import { sendUpdateVideo } from '../../activitypub/send' |
@@ -31,7 +32,9 @@ async function onSuccess (jobId: number, video: VideoModel) { | |||
31 | // Video does not exist anymore | 32 | // Video does not exist anymore |
32 | if (!videoDatabase) return undefined | 33 | if (!videoDatabase) return undefined |
33 | 34 | ||
34 | await sendUpdateVideo(video, undefined) | 35 | if (video.privacy !== VideoPrivacy.PRIVATE) { |
36 | await sendUpdateVideo(video, undefined) | ||
37 | } | ||
35 | 38 | ||
36 | return undefined | 39 | return undefined |
37 | } | 40 | } |
diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts index 37b7c42ec..9113e02a7 100644 --- a/server/middlewares/activitypub.ts +++ b/server/middlewares/activitypub.ts | |||
@@ -9,11 +9,13 @@ import { ActorModel } from '../models/activitypub/actor' | |||
9 | async function checkSignature (req: Request, res: Response, next: NextFunction) { | 9 | async function checkSignature (req: Request, res: Response, next: NextFunction) { |
10 | const signatureObject: ActivityPubSignature = req.body.signature | 10 | const signatureObject: ActivityPubSignature = req.body.signature |
11 | 11 | ||
12 | logger.debug('Checking signature of actor %s...', signatureObject.creator) | 12 | const [ creator ] = signatureObject.creator.split('#') |
13 | |||
14 | logger.debug('Checking signature of actor %s...', creator) | ||
13 | 15 | ||
14 | let actor: ActorModel | 16 | let actor: ActorModel |
15 | try { | 17 | try { |
16 | actor = await getOrCreateActorAndServerAndModel(signatureObject.creator) | 18 | actor = await getOrCreateActorAndServerAndModel(creator) |
17 | } catch (err) { | 19 | } catch (err) { |
18 | logger.error('Cannot create remote actor and check signature.', err) | 20 | logger.error('Cannot create remote actor and check signature.', err) |
19 | return res.sendStatus(403) | 21 | return res.sendStatus(403) |
@@ -32,6 +34,7 @@ async function checkSignature (req: Request, res: Response, next: NextFunction) | |||
32 | function executeIfActivityPub (fun: RequestHandler | RequestHandler[]) { | 34 | function executeIfActivityPub (fun: RequestHandler | RequestHandler[]) { |
33 | return (req: Request, res: Response, next: NextFunction) => { | 35 | return (req: Request, res: Response, next: NextFunction) => { |
34 | const accepted = req.accepts(ACCEPT_HEADERS) | 36 | const accepted = req.accepts(ACCEPT_HEADERS) |
37 | console.log(accepted) | ||
35 | if (accepted === false || ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS.indexOf(accepted) === -1) { | 38 | if (accepted === false || ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS.indexOf(accepted) === -1) { |
36 | return next() | 39 | return next() |
37 | } | 40 | } |
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts index 8cedcc2bc..e7eb35e2c 100644 --- a/server/models/activitypub/actor.ts +++ b/server/models/activitypub/actor.ts | |||
@@ -2,32 +2,15 @@ import { values } from 'lodash' | |||
2 | import { join } from 'path' | 2 | import { join } from 'path' |
3 | import * as Sequelize from 'sequelize' | 3 | import * as Sequelize from 'sequelize' |
4 | import { | 4 | import { |
5 | AllowNull, | 5 | AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, DefaultScope, ForeignKey, HasMany, HasOne, Is, IsUUID, Model, Scopes, |
6 | BelongsTo, | 6 | Table, UpdatedAt |
7 | Column, | ||
8 | CreatedAt, | ||
9 | DataType, | ||
10 | Default, DefaultScope, | ||
11 | ForeignKey, | ||
12 | HasMany, | ||
13 | HasOne, | ||
14 | Is, | ||
15 | IsUUID, | ||
16 | Model, | ||
17 | Scopes, | ||
18 | Table, | ||
19 | UpdatedAt | ||
20 | } from 'sequelize-typescript' | 7 | } from 'sequelize-typescript' |
21 | import { ActivityPubActorType } from '../../../shared/models/activitypub' | 8 | import { ActivityPubActorType } from '../../../shared/models/activitypub' |
22 | import { Avatar } from '../../../shared/models/avatars/avatar.model' | 9 | import { Avatar } from '../../../shared/models/avatars/avatar.model' |
23 | import { activityPubContextify } from '../../helpers' | 10 | import { activityPubContextify } from '../../helpers' |
24 | import { | 11 | import { |
25 | isActivityPubUrlValid, | 12 | isActivityPubUrlValid, isActorFollowersCountValid, isActorFollowingCountValid, isActorPreferredUsernameValid, |
26 | isActorFollowersCountValid, | 13 | isActorPrivateKeyValid, isActorPublicKeyValid |
27 | isActorFollowingCountValid, | ||
28 | isActorNameValid, | ||
29 | isActorPrivateKeyValid, | ||
30 | isActorPublicKeyValid | ||
31 | } from '../../helpers/custom-validators/activitypub' | 14 | } from '../../helpers/custom-validators/activitypub' |
32 | import { ACTIVITY_PUB_ACTOR_TYPES, AVATARS_DIR, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers' | 15 | import { ACTIVITY_PUB_ACTOR_TYPES, AVATARS_DIR, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers' |
33 | import { AccountModel } from '../account/account' | 16 | import { AccountModel } from '../account/account' |
@@ -71,7 +54,7 @@ enum ScopeNames { | |||
71 | tableName: 'actor', | 54 | tableName: 'actor', |
72 | indexes: [ | 55 | indexes: [ |
73 | { | 56 | { |
74 | fields: [ 'name', 'serverId' ], | 57 | fields: [ 'preferredUsername', 'serverId' ], |
75 | unique: true | 58 | unique: true |
76 | } | 59 | } |
77 | ] | 60 | ] |
@@ -89,9 +72,9 @@ export class ActorModel extends Model<ActorModel> { | |||
89 | uuid: string | 72 | uuid: string |
90 | 73 | ||
91 | @AllowNull(false) | 74 | @AllowNull(false) |
92 | @Is('ActorName', value => throwIfNotValid(value, isActorNameValid, 'actor name')) | 75 | @Is('ActorPreferredUsername', value => throwIfNotValid(value, isActorPreferredUsernameValid, 'actor preferred username')) |
93 | @Column | 76 | @Column |
94 | name: string | 77 | preferredUsername: string |
95 | 78 | ||
96 | @AllowNull(false) | 79 | @AllowNull(false) |
97 | @Is('ActorUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) | 80 | @Is('ActorUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) |
@@ -212,16 +195,6 @@ export class ActorModel extends Model<ActorModel> { | |||
212 | return ActorModel.scope(ScopeNames.FULL).findById(id) | 195 | return ActorModel.scope(ScopeNames.FULL).findById(id) |
213 | } | 196 | } |
214 | 197 | ||
215 | static loadByUUID (uuid: string) { | ||
216 | const query = { | ||
217 | where: { | ||
218 | uuid | ||
219 | } | ||
220 | } | ||
221 | |||
222 | return ActorModel.scope(ScopeNames.FULL).findOne(query) | ||
223 | } | ||
224 | |||
225 | static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) { | 198 | static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) { |
226 | const query = { | 199 | const query = { |
227 | where: { | 200 | where: { |
@@ -235,10 +208,10 @@ export class ActorModel extends Model<ActorModel> { | |||
235 | return ActorModel.scope(ScopeNames.FULL).findAll(query) | 208 | return ActorModel.scope(ScopeNames.FULL).findAll(query) |
236 | } | 209 | } |
237 | 210 | ||
238 | static loadLocalByName (name: string) { | 211 | static loadLocalByName (preferredUsername: string) { |
239 | const query = { | 212 | const query = { |
240 | where: { | 213 | where: { |
241 | name, | 214 | preferredUsername, |
242 | serverId: null | 215 | serverId: null |
243 | } | 216 | } |
244 | } | 217 | } |
@@ -246,10 +219,10 @@ export class ActorModel extends Model<ActorModel> { | |||
246 | return ActorModel.scope(ScopeNames.FULL).findOne(query) | 219 | return ActorModel.scope(ScopeNames.FULL).findOne(query) |
247 | } | 220 | } |
248 | 221 | ||
249 | static loadByNameAndHost (name: string, host: string) { | 222 | static loadByNameAndHost (preferredUsername: string, host: string) { |
250 | const query = { | 223 | const query = { |
251 | where: { | 224 | where: { |
252 | name | 225 | preferredUsername |
253 | }, | 226 | }, |
254 | include: [ | 227 | include: [ |
255 | { | 228 | { |
@@ -286,17 +259,15 @@ export class ActorModel extends Model<ActorModel> { | |||
286 | } | 259 | } |
287 | } | 260 | } |
288 | 261 | ||
289 | let host = CONFIG.WEBSERVER.HOST | ||
290 | let score: number | 262 | let score: number |
291 | if (this.Server) { | 263 | if (this.Server) { |
292 | host = this.Server.host | ||
293 | score = this.Server.score | 264 | score = this.Server.score |
294 | } | 265 | } |
295 | 266 | ||
296 | return { | 267 | return { |
297 | id: this.id, | 268 | id: this.id, |
298 | uuid: this.uuid, | 269 | uuid: this.uuid, |
299 | host, | 270 | host: this.getHost(), |
300 | score, | 271 | score, |
301 | followingCount: this.followingCount, | 272 | followingCount: this.followingCount, |
302 | followersCount: this.followersCount, | 273 | followersCount: this.followersCount, |
@@ -304,7 +275,7 @@ export class ActorModel extends Model<ActorModel> { | |||
304 | } | 275 | } |
305 | } | 276 | } |
306 | 277 | ||
307 | toActivityPubObject (preferredUsername: string, type: 'Account' | 'Application' | 'VideoChannel') { | 278 | toActivityPubObject (name: string, type: 'Account' | 'Application' | 'VideoChannel') { |
308 | let activityPubType | 279 | let activityPubType |
309 | if (type === 'Account') { | 280 | if (type === 'Account') { |
310 | activityPubType = 'Person' as 'Person' | 281 | activityPubType = 'Person' as 'Person' |
@@ -321,9 +292,9 @@ export class ActorModel extends Model<ActorModel> { | |||
321 | followers: this.getFollowersUrl(), | 292 | followers: this.getFollowersUrl(), |
322 | inbox: this.inboxUrl, | 293 | inbox: this.inboxUrl, |
323 | outbox: this.outboxUrl, | 294 | outbox: this.outboxUrl, |
324 | preferredUsername, | 295 | preferredUsername: this.preferredUsername, |
325 | url: this.url, | 296 | url: this.url, |
326 | name: this.name, | 297 | name, |
327 | endpoints: { | 298 | endpoints: { |
328 | sharedInbox: this.sharedInboxUrl | 299 | sharedInbox: this.sharedInboxUrl |
329 | }, | 300 | }, |
@@ -373,4 +344,12 @@ export class ActorModel extends Model<ActorModel> { | |||
373 | isOwned () { | 344 | isOwned () { |
374 | return this.serverId === null | 345 | return this.serverId === null |
375 | } | 346 | } |
347 | |||
348 | getWebfingerUrl () { | ||
349 | return 'acct:' + this.preferredUsername + '@' + this.getHost() | ||
350 | } | ||
351 | |||
352 | getHost () { | ||
353 | return this.Server ? this.Server.host : CONFIG.WEBSERVER.HOST | ||
354 | } | ||
376 | } | 355 | } |