diff options
author | Chocobozzz <me@florianbigard.com> | 2021-05-07 08:59:59 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-05-07 09:00:09 +0200 |
commit | a66c2e3252d6cca8958959966f42494ded564023 (patch) | |
tree | 79e32e2255c7787cfbd127581a4b162552068d66 | |
parent | 64df4b65aee56784f8edad917c44b24453bf4658 (diff) | |
download | PeerTube-a66c2e3252d6cca8958959966f42494ded564023.tar.gz PeerTube-a66c2e3252d6cca8958959966f42494ded564023.tar.zst PeerTube-a66c2e3252d6cca8958959966f42494ded564023.zip |
Fix remote actor creation date
-rw-r--r-- | server/helpers/custom-validators/activitypub/actor.ts | 39 | ||||
-rw-r--r-- | server/initializers/constants.ts | 2 | ||||
-rw-r--r-- | server/initializers/migrations/0645-actor-remote-creation-date.ts | 26 | ||||
-rw-r--r-- | server/lib/activitypub/actor.ts | 4 | ||||
-rw-r--r-- | server/models/account/account.ts | 2 | ||||
-rw-r--r-- | server/models/activitypub/actor.ts | 15 | ||||
-rw-r--r-- | server/models/video/video-channel.ts | 2 | ||||
-rw-r--r-- | server/tests/api/users/users-multiple-servers.ts | 28 | ||||
-rw-r--r-- | server/types/models/account/actor.ts | 2 | ||||
-rw-r--r-- | shared/models/activitypub/activitypub-actor.ts | 2 |
10 files changed, 80 insertions, 42 deletions
diff --git a/server/helpers/custom-validators/activitypub/actor.ts b/server/helpers/custom-validators/activitypub/actor.ts index 877345157..675a7b663 100644 --- a/server/helpers/custom-validators/activitypub/actor.ts +++ b/server/helpers/custom-validators/activitypub/actor.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import validator from 'validator' | 1 | import validator from 'validator' |
2 | import { CONSTRAINTS_FIELDS } from '../../../initializers/constants' | 2 | import { CONSTRAINTS_FIELDS } from '../../../initializers/constants' |
3 | import { exists, isArray } from '../misc' | 3 | import { exists, isArray, isDateValid } from '../misc' |
4 | import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc' | 4 | import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc' |
5 | import { isHostValid } from '../servers' | 5 | import { isHostValid } from '../servers' |
6 | import { peertubeTruncate } from '@server/helpers/core-utils' | 6 | import { peertubeTruncate } from '@server/helpers/core-utils' |
@@ -47,7 +47,21 @@ function isActorPrivateKeyValid (privateKey: string) { | |||
47 | validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY) | 47 | validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY) |
48 | } | 48 | } |
49 | 49 | ||
50 | function isActorObjectValid (actor: any) { | 50 | function isActorFollowingCountValid (value: string) { |
51 | return exists(value) && validator.isInt('' + value, { min: 0 }) | ||
52 | } | ||
53 | |||
54 | function isActorFollowersCountValid (value: string) { | ||
55 | return exists(value) && validator.isInt('' + value, { min: 0 }) | ||
56 | } | ||
57 | |||
58 | function isActorDeleteActivityValid (activity: any) { | ||
59 | return isBaseActivityValid(activity, 'Delete') | ||
60 | } | ||
61 | |||
62 | function sanitizeAndCheckActorObject (actor: any) { | ||
63 | normalizeActor(actor) | ||
64 | |||
51 | return exists(actor) && | 65 | return exists(actor) && |
52 | isActivityPubUrlValid(actor.id) && | 66 | isActivityPubUrlValid(actor.id) && |
53 | isActorTypeValid(actor.type) && | 67 | isActorTypeValid(actor.type) && |
@@ -68,24 +82,6 @@ function isActorObjectValid (actor: any) { | |||
68 | (actor.type !== 'Group' || actor.attributedTo.length !== 0) | 82 | (actor.type !== 'Group' || actor.attributedTo.length !== 0) |
69 | } | 83 | } |
70 | 84 | ||
71 | function isActorFollowingCountValid (value: string) { | ||
72 | return exists(value) && validator.isInt('' + value, { min: 0 }) | ||
73 | } | ||
74 | |||
75 | function isActorFollowersCountValid (value: string) { | ||
76 | return exists(value) && validator.isInt('' + value, { min: 0 }) | ||
77 | } | ||
78 | |||
79 | function isActorDeleteActivityValid (activity: any) { | ||
80 | return isBaseActivityValid(activity, 'Delete') | ||
81 | } | ||
82 | |||
83 | function sanitizeAndCheckActorObject (object: any) { | ||
84 | normalizeActor(object) | ||
85 | |||
86 | return isActorObjectValid(object) | ||
87 | } | ||
88 | |||
89 | function normalizeActor (actor: any) { | 85 | function normalizeActor (actor: any) { |
90 | if (!actor) return | 86 | if (!actor) return |
91 | 87 | ||
@@ -95,6 +91,8 @@ function normalizeActor (actor: any) { | |||
95 | actor.url = actor.url.href || actor.url.url | 91 | actor.url = actor.url.href || actor.url.url |
96 | } | 92 | } |
97 | 93 | ||
94 | if (!isDateValid(actor.published)) actor.published = undefined | ||
95 | |||
98 | if (actor.summary && typeof actor.summary === 'string') { | 96 | if (actor.summary && typeof actor.summary === 'string') { |
99 | actor.summary = peertubeTruncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max }) | 97 | actor.summary = peertubeTruncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max }) |
100 | 98 | ||
@@ -135,7 +133,6 @@ export { | |||
135 | isActorPublicKeyValid, | 133 | isActorPublicKeyValid, |
136 | isActorPreferredUsernameValid, | 134 | isActorPreferredUsernameValid, |
137 | isActorPrivateKeyValid, | 135 | isActorPrivateKeyValid, |
138 | isActorObjectValid, | ||
139 | isActorFollowingCountValid, | 136 | isActorFollowingCountValid, |
140 | isActorFollowersCountValid, | 137 | isActorFollowersCountValid, |
141 | isActorDeleteActivityValid, | 138 | isActorDeleteActivityValid, |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index d390fd95e..f807a1e58 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -24,7 +24,7 @@ import { CONFIG, registerConfigChangedHandler } from './config' | |||
24 | 24 | ||
25 | // --------------------------------------------------------------------------- | 25 | // --------------------------------------------------------------------------- |
26 | 26 | ||
27 | const LAST_MIGRATION_VERSION = 640 | 27 | const LAST_MIGRATION_VERSION = 645 |
28 | 28 | ||
29 | // --------------------------------------------------------------------------- | 29 | // --------------------------------------------------------------------------- |
30 | 30 | ||
diff --git a/server/initializers/migrations/0645-actor-remote-creation-date.ts b/server/initializers/migrations/0645-actor-remote-creation-date.ts new file mode 100644 index 000000000..38b3b881c --- /dev/null +++ b/server/initializers/migrations/0645-actor-remote-creation-date.ts | |||
@@ -0,0 +1,26 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | async function up (utils: { | ||
4 | transaction: Sequelize.Transaction | ||
5 | queryInterface: Sequelize.QueryInterface | ||
6 | sequelize: Sequelize.Sequelize | ||
7 | db: any | ||
8 | }): Promise<void> { | ||
9 | { | ||
10 | const data = { | ||
11 | type: Sequelize.DATE, | ||
12 | defaultValue: null, | ||
13 | allowNull: true | ||
14 | } | ||
15 | await utils.queryInterface.addColumn('actor', 'remoteCreatedAt', data) | ||
16 | } | ||
17 | } | ||
18 | |||
19 | function down (options) { | ||
20 | throw new Error('Not implemented.') | ||
21 | } | ||
22 | |||
23 | export { | ||
24 | up, | ||
25 | down | ||
26 | } | ||
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index eec951d4e..34d53bd52 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -154,6 +154,8 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ | |||
154 | const followersCount = await fetchActorTotalItems(attributes.followers) | 154 | const followersCount = await fetchActorTotalItems(attributes.followers) |
155 | const followingCount = await fetchActorTotalItems(attributes.following) | 155 | const followingCount = await fetchActorTotalItems(attributes.following) |
156 | 156 | ||
157 | logger.info('coucou', { attributes }) | ||
158 | |||
157 | actorInstance.type = attributes.type | 159 | actorInstance.type = attributes.type |
158 | actorInstance.preferredUsername = attributes.preferredUsername | 160 | actorInstance.preferredUsername = attributes.preferredUsername |
159 | actorInstance.url = attributes.id | 161 | actorInstance.url = attributes.id |
@@ -165,6 +167,8 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ | |||
165 | actorInstance.followersUrl = attributes.followers | 167 | actorInstance.followersUrl = attributes.followers |
166 | actorInstance.followingUrl = attributes.following | 168 | actorInstance.followingUrl = attributes.following |
167 | 169 | ||
170 | if (attributes.published) actorInstance.remoteCreatedAt = new Date(attributes.published) | ||
171 | |||
168 | if (attributes.endpoints?.sharedInbox) { | 172 | if (attributes.endpoints?.sharedInbox) { |
169 | actorInstance.sharedInboxUrl = attributes.endpoints.sharedInbox | 173 | actorInstance.sharedInboxUrl = attributes.endpoints.sharedInbox |
170 | } | 174 | } |
diff --git a/server/models/account/account.ts b/server/models/account/account.ts index 312451abe..44be0fd3c 100644 --- a/server/models/account/account.ts +++ b/server/models/account/account.ts | |||
@@ -411,8 +411,6 @@ export class AccountModel extends Model { | |||
411 | id: this.id, | 411 | id: this.id, |
412 | displayName: this.getDisplayName(), | 412 | displayName: this.getDisplayName(), |
413 | description: this.description, | 413 | description: this.description, |
414 | createdAt: this.createdAt, | ||
415 | updatedAt: this.updatedAt, | ||
416 | userId: this.userId ? this.userId : undefined | 414 | userId: this.userId ? this.userId : undefined |
417 | } | 415 | } |
418 | 416 | ||
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts index 19f3f7e04..396a52337 100644 --- a/server/models/activitypub/actor.ts +++ b/server/models/activitypub/actor.ts | |||
@@ -69,9 +69,7 @@ export const unusedActorAttributesForAPI = [ | |||
69 | 'outboxUrl', | 69 | 'outboxUrl', |
70 | 'sharedInboxUrl', | 70 | 'sharedInboxUrl', |
71 | 'followersUrl', | 71 | 'followersUrl', |
72 | 'followingUrl', | 72 | 'followingUrl' |
73 | 'createdAt', | ||
74 | 'updatedAt' | ||
75 | ] | 73 | ] |
76 | 74 | ||
77 | @DefaultScope(() => ({ | 75 | @DefaultScope(() => ({ |
@@ -222,6 +220,10 @@ export class ActorModel extends Model { | |||
222 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) | 220 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) |
223 | followingUrl: string | 221 | followingUrl: string |
224 | 222 | ||
223 | @AllowNull(true) | ||
224 | @Column | ||
225 | remoteCreatedAt: Date | ||
226 | |||
225 | @CreatedAt | 227 | @CreatedAt |
226 | createdAt: Date | 228 | createdAt: Date |
227 | 229 | ||
@@ -555,7 +557,7 @@ export class ActorModel extends Model { | |||
555 | followingCount: this.followingCount, | 557 | followingCount: this.followingCount, |
556 | followersCount: this.followersCount, | 558 | followersCount: this.followersCount, |
557 | banner, | 559 | banner, |
558 | createdAt: this.createdAt, | 560 | createdAt: this.getCreatedAt(), |
559 | updatedAt: this.updatedAt | 561 | updatedAt: this.updatedAt |
560 | }) | 562 | }) |
561 | } | 563 | } |
@@ -608,6 +610,7 @@ export class ActorModel extends Model { | |||
608 | owner: this.url, | 610 | owner: this.url, |
609 | publicKeyPem: this.publicKey | 611 | publicKeyPem: this.publicKey |
610 | }, | 612 | }, |
613 | published: this.getCreatedAt().toISOString(), | ||
611 | icon, | 614 | icon, |
612 | image | 615 | image |
613 | } | 616 | } |
@@ -690,4 +693,8 @@ export class ActorModel extends Model { | |||
690 | 693 | ||
691 | return isOutdated(this, ACTIVITY_PUB.ACTOR_REFRESH_INTERVAL) | 694 | return isOutdated(this, ACTIVITY_PUB.ACTOR_REFRESH_INTERVAL) |
692 | } | 695 | } |
696 | |||
697 | getCreatedAt (this: MActorAPChannel | MActorAPAccount | MActorFormattable) { | ||
698 | return this.remoteCreatedAt || this.createdAt | ||
699 | } | ||
693 | } | 700 | } |
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index b7ffbd3b1..b627595c9 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -653,8 +653,6 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"` | |||
653 | description: this.description, | 653 | description: this.description, |
654 | support: this.support, | 654 | support: this.support, |
655 | isLocal: this.Actor.isOwned(), | 655 | isLocal: this.Actor.isOwned(), |
656 | createdAt: this.createdAt, | ||
657 | updatedAt: this.updatedAt, | ||
658 | ownerAccount: undefined, | 656 | ownerAccount: undefined, |
659 | videosCount, | 657 | videosCount, |
660 | viewsPerDay | 658 | viewsPerDay |
diff --git a/server/tests/api/users/users-multiple-servers.ts b/server/tests/api/users/users-multiple-servers.ts index dcd03879b..f60c66e4b 100644 --- a/server/tests/api/users/users-multiple-servers.ts +++ b/server/tests/api/users/users-multiple-servers.ts | |||
@@ -130,26 +130,32 @@ describe('Test users with multiple servers', function () { | |||
130 | }) | 130 | }) |
131 | 131 | ||
132 | it('Should have updated my profile on other servers too', async function () { | 132 | it('Should have updated my profile on other servers too', async function () { |
133 | let createdAt: string | Date | ||
134 | |||
133 | for (const server of servers) { | 135 | for (const server of servers) { |
134 | const resAccounts = await getAccountsList(server.url, '-createdAt') | 136 | const resAccounts = await getAccountsList(server.url, '-createdAt') |
135 | 137 | ||
136 | const rootServer1List = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:' + servers[0].port) as Account | 138 | const resList = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:' + servers[0].port) as Account |
137 | expect(rootServer1List).not.to.be.undefined | 139 | expect(resList).not.to.be.undefined |
140 | |||
141 | const resAccount = await getAccount(server.url, resList.name + '@' + resList.host) | ||
142 | const account = resAccount.body as Account | ||
143 | |||
144 | if (!createdAt) createdAt = account.createdAt | ||
138 | 145 | ||
139 | const resAccount = await getAccount(server.url, rootServer1List.name + '@' + rootServer1List.host) | 146 | expect(account.name).to.equal('root') |
140 | const rootServer1Get = resAccount.body as Account | 147 | expect(account.host).to.equal('localhost:' + servers[0].port) |
141 | expect(rootServer1Get.name).to.equal('root') | 148 | expect(account.displayName).to.equal('my super display name') |
142 | expect(rootServer1Get.host).to.equal('localhost:' + servers[0].port) | 149 | expect(account.description).to.equal('my super description updated') |
143 | expect(rootServer1Get.displayName).to.equal('my super display name') | 150 | expect(createdAt).to.equal(account.createdAt) |
144 | expect(rootServer1Get.description).to.equal('my super description updated') | ||
145 | 151 | ||
146 | if (server.serverNumber === 1) { | 152 | if (server.serverNumber === 1) { |
147 | expect(rootServer1Get.userId).to.be.a('number') | 153 | expect(account.userId).to.be.a('number') |
148 | } else { | 154 | } else { |
149 | expect(rootServer1Get.userId).to.be.undefined | 155 | expect(account.userId).to.be.undefined |
150 | } | 156 | } |
151 | 157 | ||
152 | await testImage(server.url, 'avatar2-resized', rootServer1Get.avatar.path, '.png') | 158 | await testImage(server.url, 'avatar2-resized', account.avatar.path, '.png') |
153 | } | 159 | } |
154 | }) | 160 | }) |
155 | 161 | ||
diff --git a/server/types/models/account/actor.ts b/server/types/models/account/actor.ts index 8f3f30074..0b620872e 100644 --- a/server/types/models/account/actor.ts +++ b/server/types/models/account/actor.ts | |||
@@ -150,7 +150,7 @@ export type MActorSummaryFormattable = | |||
150 | 150 | ||
151 | export type MActorFormattable = | 151 | export type MActorFormattable = |
152 | MActorSummaryFormattable & | 152 | MActorSummaryFormattable & |
153 | Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt' | 'bannerId' | 'avatarId'> & | 153 | Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt' | 'remoteCreatedAt' | 'bannerId' | 'avatarId'> & |
154 | Use<'Server', MServerHost & Partial<Pick<MServer, 'redundancyAllowed'>>> & | 154 | Use<'Server', MServerHost & Partial<Pick<MServer, 'redundancyAllowed'>>> & |
155 | UseOpt<'Banner', MActorImageFormattable> | 155 | UseOpt<'Banner', MActorImageFormattable> |
156 | 156 | ||
diff --git a/shared/models/activitypub/activitypub-actor.ts b/shared/models/activitypub/activitypub-actor.ts index c59be3f3b..09d4f7402 100644 --- a/shared/models/activitypub/activitypub-actor.ts +++ b/shared/models/activitypub/activitypub-actor.ts | |||
@@ -29,4 +29,6 @@ export interface ActivityPubActor { | |||
29 | 29 | ||
30 | icon?: ActivityIconObject | 30 | icon?: ActivityIconObject |
31 | image?: ActivityIconObject | 31 | image?: ActivityIconObject |
32 | |||
33 | published?: string | ||
32 | } | 34 | } |