]> Untitled Git - lemmy.git/blob - api_tests/src/post.spec.ts
Sanitize html (#3708)
[lemmy.git] / api_tests / src / post.spec.ts
1 jest.setTimeout(120000);
2
3 import { CommunityView } from "lemmy-js-client/dist/types/CommunityView";
4 import {
5   alpha,
6   beta,
7   gamma,
8   delta,
9   epsilon,
10   setupLogins,
11   createPost,
12   editPost,
13   featurePost,
14   lockPost,
15   resolvePost,
16   likePost,
17   followBeta,
18   resolveBetaCommunity,
19   createComment,
20   deletePost,
21   removePost,
22   getPost,
23   unfollowRemotes,
24   resolvePerson,
25   banPersonFromSite,
26   searchPostLocal,
27   followCommunity,
28   banPersonFromCommunity,
29   reportPost,
30   listPostReports,
31   randomString,
32   registerUser,
33   API,
34   getSite,
35   unfollows,
36   resolveCommunity,
37 } from "./shared";
38 import { PostView } from "lemmy-js-client/dist/types/PostView";
39 import { CreatePost } from "lemmy-js-client/dist/types/CreatePost";
40
41 let betaCommunity: CommunityView | undefined;
42
43 beforeAll(async () => {
44   await setupLogins();
45   betaCommunity = (await resolveBetaCommunity(alpha)).community;
46   expect(betaCommunity).toBeDefined();
47   await unfollows();
48 });
49
50 afterAll(async () => {
51   await unfollows();
52 });
53
54 function assertPostFederation(postOne?: PostView, postTwo?: PostView) {
55   expect(postOne?.post.ap_id).toBe(postTwo?.post.ap_id);
56   expect(postOne?.post.name).toBe(postTwo?.post.name);
57   expect(postOne?.post.body).toBe(postTwo?.post.body);
58   // TODO url clears arent working
59   // expect(postOne?.post.url).toBe(postTwo?.post.url);
60   expect(postOne?.post.nsfw).toBe(postTwo?.post.nsfw);
61   expect(postOne?.post.embed_title).toBe(postTwo?.post.embed_title);
62   expect(postOne?.post.embed_description).toBe(postTwo?.post.embed_description);
63   expect(postOne?.post.embed_video_url).toBe(postTwo?.post.embed_video_url);
64   expect(postOne?.post.published).toBe(postTwo?.post.published);
65   expect(postOne?.community.actor_id).toBe(postTwo?.community.actor_id);
66   expect(postOne?.post.locked).toBe(postTwo?.post.locked);
67   expect(postOne?.post.removed).toBe(postTwo?.post.removed);
68   expect(postOne?.post.deleted).toBe(postTwo?.post.deleted);
69 }
70
71 test("Create a post", async () => {
72   if (!betaCommunity) {
73     throw "Missing beta community";
74   }
75
76   let postRes = await createPost(alpha, betaCommunity.community.id);
77   expect(postRes.post_view.post).toBeDefined();
78   expect(postRes.post_view.community.local).toBe(false);
79   expect(postRes.post_view.creator.local).toBe(true);
80   expect(postRes.post_view.counts.score).toBe(1);
81
82   // Make sure that post is liked on beta
83   let betaPost = (await resolvePost(beta, postRes.post_view.post)).post;
84
85   expect(betaPost).toBeDefined();
86   expect(betaPost?.community.local).toBe(true);
87   expect(betaPost?.creator.local).toBe(false);
88   expect(betaPost?.counts.score).toBe(1);
89   assertPostFederation(betaPost, postRes.post_view);
90
91   // Delta only follows beta, so it should not see an alpha ap_id
92   await expect(resolvePost(delta, postRes.post_view.post)).rejects.toBe(
93     "couldnt_find_object",
94   );
95
96   // Epsilon has alpha blocked, it should not see the alpha post
97   await expect(resolvePost(epsilon, postRes.post_view.post)).rejects.toBe(
98     "couldnt_find_object",
99   );
100 });
101
102 test("Create a post in a non-existent community", async () => {
103   await expect(createPost(alpha, -2)).rejects.toBe("couldnt_find_community");
104 });
105
106 test("Unlike a post", async () => {
107   if (!betaCommunity) {
108     throw "Missing beta community";
109   }
110   let postRes = await createPost(alpha, betaCommunity.community.id);
111   let unlike = await likePost(alpha, 0, postRes.post_view.post);
112   expect(unlike.post_view.counts.score).toBe(0);
113
114   // Try to unlike it again, make sure it stays at 0
115   let unlike2 = await likePost(alpha, 0, postRes.post_view.post);
116   expect(unlike2.post_view.counts.score).toBe(0);
117
118   // Make sure that post is unliked on beta
119   let betaPost = (await resolvePost(beta, postRes.post_view.post)).post;
120   expect(betaPost).toBeDefined();
121   expect(betaPost?.community.local).toBe(true);
122   expect(betaPost?.creator.local).toBe(false);
123   expect(betaPost?.counts.score).toBe(0);
124   assertPostFederation(betaPost, postRes.post_view);
125 });
126
127 test("Update a post", async () => {
128   if (!betaCommunity) {
129     throw "Missing beta community";
130   }
131   let postRes = await createPost(alpha, betaCommunity.community.id);
132
133   let updatedName = "A jest test federated post, updated";
134   let updatedPost = await editPost(alpha, postRes.post_view.post);
135   expect(updatedPost.post_view.post.name).toBe(updatedName);
136   expect(updatedPost.post_view.community.local).toBe(false);
137   expect(updatedPost.post_view.creator.local).toBe(true);
138
139   // Make sure that post is updated on beta
140   let betaPost = (await resolvePost(beta, postRes.post_view.post)).post;
141   if (!betaPost) {
142     throw "Missing beta post";
143   }
144   expect(betaPost.community.local).toBe(true);
145   expect(betaPost.creator.local).toBe(false);
146   expect(betaPost.post.name).toBe(updatedName);
147   assertPostFederation(betaPost, updatedPost.post_view);
148
149   // Make sure lemmy beta cannot update the post
150   await expect(editPost(beta, betaPost.post)).rejects.toBe(
151     "no_post_edit_allowed",
152   );
153 });
154
155 test("Sticky a post", async () => {
156   if (!betaCommunity) {
157     throw "Missing beta community";
158   }
159   let postRes = await createPost(alpha, betaCommunity.community.id);
160
161   let betaPost1 = (await resolvePost(beta, postRes.post_view.post)).post;
162   if (!betaPost1) {
163     throw "Missing beta post1";
164   }
165   let stickiedPostRes = await featurePost(beta, true, betaPost1.post);
166   expect(stickiedPostRes.post_view.post.featured_community).toBe(true);
167
168   // Make sure that post is stickied on beta
169   let betaPost = (await resolvePost(beta, postRes.post_view.post)).post;
170   expect(betaPost?.community.local).toBe(true);
171   expect(betaPost?.creator.local).toBe(false);
172   expect(betaPost?.post.featured_community).toBe(true);
173
174   // Unsticky a post
175   let unstickiedPost = await featurePost(beta, false, betaPost1.post);
176   expect(unstickiedPost.post_view.post.featured_community).toBe(false);
177
178   // Make sure that post is unstickied on beta
179   let betaPost2 = (await resolvePost(beta, postRes.post_view.post)).post;
180   expect(betaPost2?.community.local).toBe(true);
181   expect(betaPost2?.creator.local).toBe(false);
182   expect(betaPost2?.post.featured_community).toBe(false);
183
184   // Make sure that gamma cannot sticky the post on beta
185   let gammaPost = (await resolvePost(gamma, postRes.post_view.post)).post;
186   if (!gammaPost) {
187     throw "Missing gamma post";
188   }
189   let gammaTrySticky = await featurePost(gamma, true, gammaPost.post);
190   let betaPost3 = (await resolvePost(beta, postRes.post_view.post)).post;
191   expect(gammaTrySticky.post_view.post.featured_community).toBe(true);
192   expect(betaPost3?.post.featured_community).toBe(false);
193 });
194
195 test("Lock a post", async () => {
196   if (!betaCommunity) {
197     throw "Missing beta community";
198   }
199   await followCommunity(alpha, true, betaCommunity.community.id);
200   let postRes = await createPost(alpha, betaCommunity.community.id);
201
202   // Lock the post
203   let betaPost1 = (await resolvePost(beta, postRes.post_view.post)).post;
204   if (!betaPost1) {
205     throw "Missing beta post1";
206   }
207   let lockedPostRes = await lockPost(beta, true, betaPost1.post);
208   expect(lockedPostRes.post_view.post.locked).toBe(true);
209
210   // Make sure that post is locked on alpha
211   let searchAlpha = await searchPostLocal(alpha, postRes.post_view.post);
212   let alphaPost1 = searchAlpha.posts[0];
213   expect(alphaPost1.post.locked).toBe(true);
214
215   // Try to make a new comment there, on alpha
216   await expect(createComment(alpha, alphaPost1.post.id)).rejects.toBe("locked");
217
218   // Unlock a post
219   let unlockedPost = await lockPost(beta, false, betaPost1.post);
220   expect(unlockedPost.post_view.post.locked).toBe(false);
221
222   // Make sure that post is unlocked on alpha
223   let searchAlpha2 = await searchPostLocal(alpha, postRes.post_view.post);
224   let alphaPost2 = searchAlpha2.posts[0];
225   expect(alphaPost2.community.local).toBe(false);
226   expect(alphaPost2.creator.local).toBe(true);
227   expect(alphaPost2.post.locked).toBe(false);
228
229   // Try to create a new comment, on alpha
230   let commentAlpha = await createComment(alpha, alphaPost1.post.id);
231   expect(commentAlpha).toBeDefined();
232 });
233
234 test("Delete a post", async () => {
235   if (!betaCommunity) {
236     throw "Missing beta community";
237   }
238
239   let postRes = await createPost(alpha, betaCommunity.community.id);
240   expect(postRes.post_view.post).toBeDefined();
241
242   let deletedPost = await deletePost(alpha, true, postRes.post_view.post);
243   expect(deletedPost.post_view.post.deleted).toBe(true);
244   expect(deletedPost.post_view.post.name).toBe(postRes.post_view.post.name);
245
246   // Make sure lemmy beta sees post is deleted
247   // This will be undefined because of the tombstone
248   await expect(resolvePost(beta, postRes.post_view.post)).rejects.toBe(
249     "couldnt_find_object",
250   );
251
252   // Undelete
253   let undeletedPost = await deletePost(alpha, false, postRes.post_view.post);
254   expect(undeletedPost.post_view.post.deleted).toBe(false);
255
256   // Make sure lemmy beta sees post is undeleted
257   let betaPost2 = (await resolvePost(beta, postRes.post_view.post)).post;
258   if (!betaPost2) {
259     throw "Missing beta post 2";
260   }
261   expect(betaPost2.post.deleted).toBe(false);
262   assertPostFederation(betaPost2, undeletedPost.post_view);
263
264   // Make sure lemmy beta cannot delete the post
265   await expect(deletePost(beta, true, betaPost2.post)).rejects.toBe(
266     "no_post_edit_allowed",
267   );
268 });
269
270 test("Remove a post from admin and community on different instance", async () => {
271   if (!betaCommunity) {
272     throw "Missing beta community";
273   }
274
275   let gammaCommunity = (
276     await resolveCommunity(gamma, betaCommunity.community.actor_id)
277   ).community?.community;
278   if (!gammaCommunity) {
279     throw "Missing gamma community";
280   }
281   let postRes = await createPost(gamma, gammaCommunity.id);
282
283   let alphaPost = (await resolvePost(alpha, postRes.post_view.post)).post;
284   if (!alphaPost) {
285     throw "Missing alpha post";
286   }
287   let removedPost = await removePost(alpha, true, alphaPost.post);
288   expect(removedPost.post_view.post.removed).toBe(true);
289   expect(removedPost.post_view.post.name).toBe(postRes.post_view.post.name);
290
291   // Make sure lemmy beta sees post is NOT removed
292   let betaPost = (await resolvePost(beta, postRes.post_view.post)).post;
293   if (!betaPost) {
294     throw "Missing beta post";
295   }
296   expect(betaPost.post.removed).toBe(false);
297
298   // Undelete
299   let undeletedPost = await removePost(alpha, false, alphaPost.post);
300   expect(undeletedPost.post_view.post.removed).toBe(false);
301
302   // Make sure lemmy beta sees post is undeleted
303   let betaPost2 = (await resolvePost(beta, postRes.post_view.post)).post;
304   expect(betaPost2?.post.removed).toBe(false);
305   assertPostFederation(betaPost2, undeletedPost.post_view);
306 });
307
308 test("Remove a post from admin and community on same instance", async () => {
309   if (!betaCommunity) {
310     throw "Missing beta community";
311   }
312   await followBeta(alpha);
313   let postRes = await createPost(alpha, betaCommunity.community.id);
314   expect(postRes.post_view.post).toBeDefined();
315
316   // Get the id for beta
317   let searchBeta = await searchPostLocal(beta, postRes.post_view.post);
318   let betaPost = searchBeta.posts[0];
319   expect(betaPost).toBeDefined();
320
321   // The beta admin removes it (the community lives on beta)
322   let removePostRes = await removePost(beta, true, betaPost.post);
323   expect(removePostRes.post_view.post.removed).toBe(true);
324
325   // Make sure lemmy alpha sees post is removed
326   // let alphaPost = await getPost(alpha, postRes.post_view.post.id);
327   // expect(alphaPost.post_view.post.removed).toBe(true); // TODO this shouldn't be commented
328   // assertPostFederation(alphaPost.post_view, removePostRes.post_view);
329
330   // Undelete
331   let undeletedPost = await removePost(beta, false, betaPost.post);
332   expect(undeletedPost.post_view.post.removed).toBe(false);
333
334   // Make sure lemmy alpha sees post is undeleted
335   let alphaPost2 = await getPost(alpha, postRes.post_view.post.id);
336   expect(alphaPost2.post_view.post.removed).toBe(false);
337   assertPostFederation(alphaPost2.post_view, undeletedPost.post_view);
338   await unfollowRemotes(alpha);
339 });
340
341 test("Search for a post", async () => {
342   if (!betaCommunity) {
343     throw "Missing beta community";
344   }
345   await unfollowRemotes(alpha);
346   let postRes = await createPost(alpha, betaCommunity.community.id);
347   expect(postRes.post_view.post).toBeDefined();
348
349   let betaPost = (await resolvePost(beta, postRes.post_view.post)).post;
350   expect(betaPost?.post.name).toBeDefined();
351 });
352
353 test("Enforce site ban for federated user", async () => {
354   if (!betaCommunity) {
355     throw "Missing beta community";
356   }
357   // create a test user
358   let alphaUserJwt = await registerUser(alpha);
359   expect(alphaUserJwt).toBeDefined();
360   let alpha_user: API = {
361     client: alpha.client,
362     auth: alphaUserJwt.jwt ?? "",
363   };
364   let alphaUserActorId = (await getSite(alpha_user)).my_user?.local_user_view
365     .person.actor_id;
366   if (!alphaUserActorId) {
367     throw "Missing alpha user actor id";
368   }
369   expect(alphaUserActorId).toBeDefined();
370   let alphaPerson = (await resolvePerson(alpha_user, alphaUserActorId)).person;
371   if (!alphaPerson) {
372     throw "Missing alpha person";
373   }
374   expect(alphaPerson).toBeDefined();
375
376   // alpha makes post in beta community, it federates to beta instance
377   let postRes1 = await createPost(alpha_user, betaCommunity.community.id);
378   let searchBeta1 = await searchPostLocal(beta, postRes1.post_view.post);
379   expect(searchBeta1.posts[0]).toBeDefined();
380
381   // ban alpha from its instance
382   let banAlpha = await banPersonFromSite(
383     alpha,
384     alphaPerson.person.id,
385     true,
386     true,
387   );
388   expect(banAlpha.banned).toBe(true);
389
390   // alpha ban should be federated to beta
391   let alphaUserOnBeta1 = await resolvePerson(beta, alphaUserActorId);
392   expect(alphaUserOnBeta1.person?.person.banned).toBe(true);
393
394   // existing alpha post should be removed on beta
395   let searchBeta2 = await getPost(beta, searchBeta1.posts[0].post.id);
396   expect(searchBeta2.post_view.post.removed).toBe(true);
397
398   // Unban alpha
399   let unBanAlpha = await banPersonFromSite(
400     alpha,
401     alphaPerson.person.id,
402     false,
403     false,
404   );
405   expect(unBanAlpha.banned).toBe(false);
406
407   // alpha makes new post in beta community, it federates
408   let postRes2 = await createPost(alpha_user, betaCommunity.community.id);
409   let searchBeta3 = await searchPostLocal(beta, postRes2.post_view.post);
410   expect(searchBeta3.posts[0]).toBeDefined();
411
412   let alphaUserOnBeta2 = await resolvePerson(beta, alphaUserActorId);
413   expect(alphaUserOnBeta2.person?.person.banned).toBe(false);
414 });
415
416 test.skip("Enforce community ban for federated user", async () => {
417   if (!betaCommunity) {
418     throw "Missing beta community";
419   }
420   let alphaShortname = `@lemmy_alpha@lemmy-alpha:8541`;
421   let alphaPerson = (await resolvePerson(beta, alphaShortname)).person;
422   if (!alphaPerson) {
423     throw "Missing alpha person";
424   }
425   expect(alphaPerson).toBeDefined();
426
427   // make a post in beta, it goes through
428   let postRes1 = await createPost(alpha, betaCommunity.community.id);
429   let searchBeta1 = await searchPostLocal(beta, postRes1.post_view.post);
430   expect(searchBeta1.posts[0]).toBeDefined();
431
432   // ban alpha from beta community
433   let banAlpha = await banPersonFromCommunity(
434     beta,
435     alphaPerson.person.id,
436     2,
437     true,
438     true,
439   );
440   expect(banAlpha.banned).toBe(true);
441
442   // ensure that the post by alpha got removed
443   await expect(getPost(alpha, searchBeta1.posts[0].post.id)).rejects.toBe(
444     "unknown",
445   );
446
447   // Alpha tries to make post on beta, but it fails because of ban
448   await expect(createPost(alpha, betaCommunity.community.id)).rejects.toBe(
449     "banned_from_community",
450   );
451
452   // Unban alpha
453   let unBanAlpha = await banPersonFromCommunity(
454     beta,
455     alphaPerson.person.id,
456     2,
457     false,
458     false,
459   );
460   expect(unBanAlpha.banned).toBe(false);
461   let postRes3 = await createPost(alpha, betaCommunity.community.id);
462   expect(postRes3.post_view.post).toBeDefined();
463   expect(postRes3.post_view.community.local).toBe(false);
464   expect(postRes3.post_view.creator.local).toBe(true);
465   expect(postRes3.post_view.counts.score).toBe(1);
466
467   // Make sure that post makes it to beta community
468   let searchBeta2 = await searchPostLocal(beta, postRes3.post_view.post);
469   expect(searchBeta2.posts[0]).toBeDefined();
470 });
471
472 test("A and G subscribe to B (center) A posts, it gets announced to G", async () => {
473   if (!betaCommunity) {
474     throw "Missing beta community";
475   }
476   let postRes = await createPost(alpha, betaCommunity.community.id);
477   expect(postRes.post_view.post).toBeDefined();
478
479   let betaPost = (await resolvePost(gamma, postRes.post_view.post)).post;
480   expect(betaPost?.post.name).toBeDefined();
481 });
482
483 test("Report a post", async () => {
484   // Note, this is a different one from the setup
485   let betaCommunity = (await resolveBetaCommunity(beta)).community;
486   if (!betaCommunity) {
487     throw "Missing beta community";
488   }
489   let postRes = await createPost(beta, betaCommunity.community.id);
490   expect(postRes.post_view.post).toBeDefined();
491
492   let alphaPost = (await resolvePost(alpha, postRes.post_view.post)).post;
493   if (!alphaPost) {
494     throw "Missing alpha post";
495   }
496   let alphaReport = (
497     await reportPost(alpha, alphaPost.post.id, randomString(10))
498   ).post_report_view.post_report;
499
500   let betaReport = (await listPostReports(beta)).post_reports[0].post_report;
501   expect(betaReport).toBeDefined();
502   expect(betaReport.resolved).toBe(false);
503   expect(betaReport.original_post_name).toBe(alphaReport.original_post_name);
504   expect(betaReport.original_post_url).toBe(alphaReport.original_post_url);
505   expect(betaReport.original_post_body).toBe(alphaReport.original_post_body);
506   expect(betaReport.reason).toBe(alphaReport.reason);
507 });
508
509 test("Sanitize HTML", async () => {
510   let betaCommunity = (await resolveBetaCommunity(beta)).community;
511   if (!betaCommunity) {
512     throw "Missing beta community";
513   }
514
515   let name = randomString(5);
516   let body = "<script>alert('xss');</script> hello";
517   let form: CreatePost = {
518     name,
519     body,
520     auth: beta.auth,
521     community_id: betaCommunity.community.id,
522   };
523   let post = await beta.client.createPost(form);
524   expect(post.post_view.post.body).toBe(" hello");
525 });