Compare commits

..

268 Commits

Author SHA1 Message Date
Claire
a6dc5bc4ea Merge pull request #3455 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to 38e7bb9b86 into stable-4.5
2026-03-24 16:43:29 +01:00
Claire
2c35e71cfc Merge commit '38e7bb9b866b5d207a511de093de25536f13e9c4' into glitch-soc/merge-4.5 2026-03-24 16:17:23 +01:00
Claire
38e7bb9b86 Bump version to v4.5.8 (#38371) 2026-03-24 16:15:49 +01:00
Claire
089a141efc Merge commit from fork 2026-03-24 15:44:08 +01:00
Claire
c188e659b1 Merge commit from fork 2026-03-24 15:42:40 +01:00
Claire
d6d73bd144 Update dependency nokogiri 2026-03-24 15:36:06 +01:00
Claire
92d7ad46cf Update dependency devise 2026-03-24 15:36:06 +01:00
Matt Jankowski
23be60a641 Update devise to version 5.0 (#37419) 2026-03-24 15:36:06 +01:00
Claire
a5f1988fe1 Update dependency faraday 2026-03-24 15:36:06 +01:00
Claire
841ea7058e Update dependency rack 2026-03-24 15:36:06 +01:00
Claire
5bf82b1f9e Update dependency rails 2026-03-24 15:36:06 +01:00
github-actions[bot]
e0d097fac0 New Crowdin Translations for stable-4.5 (automated) (#38341)
Co-authored-by: GitHub Actions <noreply@github.com>
2026-03-24 10:43:13 +01:00
Claire
c2f9c7c553 Fixes some model definitions in tootctl maintenance fix-duplicates (#38214) 2026-03-23 16:54:33 +01:00
Claire
1fa9451603 Change media description length limit for remote media attachments from 1500 to 10000 characters (#37921) 2026-03-23 16:54:33 +01:00
Claire
d0348531cd Merge pull request #3442 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to f37dc6c59e into stable-4.5
2026-03-16 18:33:02 +01:00
diondiondion
a97811b056 [Glitch] Prevent hover card from showing unintentionally
Port 316290ba9d to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-03-14 11:55:04 +01:00
Claire
f4baed2a69 Merge commit 'f37dc6c59e88aa3a119ecbe76ee9fba480d13daa' into glitch-soc/merge-4.5 2026-03-14 11:54:20 +01:00
Matt Jankowski
f37dc6c59e Normalize current_username on account migration (#38183) 2026-03-13 18:17:18 +01:00
Hugo Gameiro
9171fa49b6 Fix OpenStack Swift Keystone token rate limiting (#38145) 2026-03-13 18:17:18 +01:00
Claire
ac91d30a5a Change HTTP signatures to skip the Accept header (#38132) 2026-03-13 18:17:18 +01:00
diondiondion
dff7d55a6d Prevent hover card from showing unintentionally (#38112) 2026-03-13 18:17:18 +01:00
Claire
c2244cbb67 Merge pull request #3433 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to d7059dcf1c into stable-4.5
2026-03-09 18:43:07 +01:00
Claire
436bf0590c [Glitch] Fix “Unblock” and “Unmute” actions being disabled when blocked
Port a3f0a0373d to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-03-09 12:58:36 +01:00
Claire
c8a5c2c121 [Glitch] Fix username availability check being wrongly applied on race conditions
Port ea34d35b32 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-03-09 12:57:37 +01:00
diondiondion
1033029a6c [Glitch] Prevent hover card from showing on touch devices
Port de4ee8565c to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-03-09 12:57:16 +01:00
Claire
c14a62c3af Merge commit 'd7059dcf1c5fb4dcebd80e8033a455917d0a21d1' into glitch-soc/merge-4.5 2026-03-09 12:56:25 +01:00
Claire
d7059dcf1c Fix poll expiration notification being re-triggered on implicit updates (#38078) 2026-03-09 11:39:36 +01:00
Claire
a7bfcf7131 Redirect to short account URLs when requesting HTML for one of the AP endpoints (#38056) 2026-03-09 11:39:36 +01:00
Claire
6fcdc05e43 Add for searching already-known private GtS posts (#38057) 2026-03-09 11:39:36 +01:00
Matt Jankowski
a475f2ba39 Fix incorrect I18n string in webauthn mailers (#38062) 2026-03-09 11:39:36 +01:00
Claire
a3f0a0373d Fix “Unblock” and “Unmute” actions being disabled when blocked (#38075) 2026-03-09 11:39:36 +01:00
Claire
ed521e91e1 Fix username availability check being wrongly applied on race conditions (#37975) 2026-03-09 11:39:36 +01:00
diondiondion
ba22c3f133 Prevent hover card from showing on touch devices (#38039) 2026-03-09 11:39:36 +01:00
Claire
f198ec7c1c Fix existing posts not being removed from lists when a list member is unfollowed (#38048) 2026-03-09 11:39:36 +01:00
Claire
58fed93bae [Glitch] Fix quote-inline fallback being removed even for legacy quotes (#3402)
Port 2a9c7d2b9e to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-03-02 12:20:49 +01:00
Claire
fd493378dc Merge pull request #3418 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to ab872f28b9 into stable-4.5
2026-02-24 15:47:50 +01:00
Claire
d609819aa7 Merge commit 'ab872f28b9ff8f09026461ed4874070f4e62be84' into glitch-soc/merge-4.5 2026-02-24 14:59:35 +01:00
Claire
4f6a53c22c Merge pull request #3415 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to 96a96a79ca into stable-4.5
2026-02-24 14:57:51 +01:00
Claire
ab872f28b9 Bump version to v4.5.7 (#37963) 2026-02-24 14:55:18 +01:00
Matt Jankowski
1103ebdc55 Capture output in cli/emoji spec (#37861) 2026-02-24 10:35:40 +01:00
ChaosExAnima
93eb2ac28a [Glitch] duplicate fix from #37858
Port 96a96a79ca to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-02-23 18:57:41 +01:00
Claire
04e0b85f5b [Glitch] Fix delete & redraft of pending posts
Port ab9aa25cd3 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-02-23 18:56:26 +01:00
Claire
4046affea9 Merge commit '96a96a79caeaddf4ce07c3d0468332902b00eab2' into glitch-soc/merge-4.5 2026-02-23 18:55:36 +01:00
ChaosExAnima
96a96a79ca duplicate fix from #37858 2026-02-23 18:41:43 +01:00
Claire
aec9ccba3d Fix delete & redraft of pending posts (#37839) 2026-02-23 18:41:43 +01:00
Claire
9c927683db Add --suspended-only option to tootctl emoji purge (#37828) 2026-02-23 18:41:43 +01:00
Claire
fbbf8b9a8c Process actor public keys when they are in a separate document without the ActivityStreams context (#37826) 2026-02-23 18:41:43 +01:00
Claire
b7e34ade1d Purge custom emojis on domain suspension (#37808) 2026-02-23 18:41:43 +01:00
Claire
e68754d2a2 Fix streaming of disabled timelines with special permissions (#37791) 2026-02-23 18:41:43 +01:00
Claire
31316aa082 Fix processing of object updates with duplicate hashtags (#37756) 2026-02-23 18:41:43 +01:00
David Roetzel
27c1e13aa8 Reject unconfirmed FASPs (#37926) 2026-02-20 16:29:35 +01:00
David Roetzel
17c04fe04b Re-use custom socket class for FASP requests (#37925) 2026-02-20 16:29:35 +01:00
Claire
ffddcc7c1d Merge pull request #3364 from ClearlyClaire/glitch-soc/features/local-only-drop-emoji
Deprecate eye emoji in favor of a bespoke API parameter
2026-02-11 20:24:07 +01:00
Claire
a602cc9126 Merge pull request #3378 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to e8045de79b into stable-4.5
2026-02-03 16:29:14 +01:00
Claire
4d4611beba Merge commit 'e8045de79bf0b445f43a7b7b7e5b38919edd93f6' into glitch-soc/merge-4.5 2026-02-03 15:33:46 +01:00
Claire
e8045de79b Bump version to v4.5.6 (#37715) 2026-02-03 15:26:52 +01:00
Claire
5f30206c5e Merge commit from fork 2026-02-03 14:59:53 +01:00
Claire
6fd034cb77 Merge pull request #3373 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to 68a26ce7c6 into stable-4.5
2026-01-30 19:22:40 +01:00
PGray
527bed86b5 [Glitch] Fix quote cancel button not appearing after edit then delete-and-redraft
Port f1c00feb5c to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-01-30 18:19:59 +01:00
Claire
a1e0fbfb67 Merge commit '68a26ce7c650ac2140c295b52f78b3d08191d6bd' into glitch-soc/merge-4.5 2026-01-30 18:19:44 +01:00
Claire
68a26ce7c6 Fix connection recycling pushing symbols to connection pool (#37674) 2026-01-30 12:18:36 +01:00
Claire
ff20ce9acf Clear affected relationship cache on Move activities (#37664) 2026-01-30 12:18:36 +01:00
PGray
1ba2b1cdc1 Fix quote cancel button not appearing after edit then delete-and-redraft (#37066) 2026-01-29 14:55:25 +01:00
Claire
4c1fbe4e2e Fix followers with profile subscription (bell icon) being notified of post edits (#37646) 2026-01-29 14:55:25 +01:00
Claire
569ff6c8ad Fix error when encountering invalid tag in updated object (#37635) 2026-01-29 14:55:25 +01:00
Claire
81716f7e27 Fix quote cache invalidation (#37592) 2026-01-29 14:55:25 +01:00
Claire
8935137526 Shorten caching of quote posts pending approval (#37570) 2026-01-29 14:55:25 +01:00
Claire
dcc5c2b6f6 Fix cross-server conversation tracking (#37559) 2026-01-29 14:55:25 +01:00
Shlee
f1c32f6a11 Unclosed connection leak when replacing pooled connection in SharedTimedStack.try_create (#37335) 2026-01-29 14:55:25 +01:00
Claire
23f04c2623 Merge pull request #3357 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to db943c43c8 into stable-4.5
2026-01-20 16:25:19 +01:00
Claire
ada1d32394 Merge commit 'db943c43c8fe834a0db6e87c020783ecf42476a9' into glitch-soc/merge-4.5 2026-01-20 15:56:06 +01:00
Claire
db943c43c8 Bump version to v4.5.5 (#37546) 2026-01-20 15:53:37 +01:00
Claire
1a74b74a40 Merge commit from fork
* Add limit on inbox payload size

The 1MB limit is consistent with the limit we use when fetching remote resources

* Add limit to number of options from federated polls

* Add a limit to the number of federated profile fields

* Add limit on federated username length

* Add hard limits for federated display name and account bio

* Add hard limits for `alsoKnownAs` and `attributionDomains`

* Add hard limit on federated custom emoji shortcode

* Highlight most destructive limits and expand on their reasoning
2026-01-20 15:14:45 +01:00
Claire
9a25b12f0c Merge commit from fork 2026-01-20 15:13:42 +01:00
Claire
6f9b32b137 Merge commit from fork 2026-01-20 15:13:10 +01:00
Claire
1b3ef035b9 Merge commit from fork 2026-01-20 15:10:38 +01:00
Claire
6698901d57 Fix potential duplicate handling of quote accept/reject/delete (#37537) 2026-01-20 08:57:46 +01:00
Claire
ba0609bbaf Skip tombstone creation on deleting from 404 (#37533) 2026-01-20 08:57:46 +01:00
Claire
d545e55b86 Merge pull request #3353 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to ded7f50f2c into stable-4.5
2026-01-19 19:30:21 +01:00
Echo
25d572e9b9 [Glitch] Remove trailing variation selector code for legacy emojis
Port f354bbe8aa to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-01-19 18:33:09 +01:00
diondiondion
3479b453e5 [Glitch] Fix mobile admin sidebar displaying under batch table toolbar
Port 53437c4653 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-01-19 18:32:48 +01:00
Claire
c96eebde37 Merge commit 'ded7f50f2c2672879292ff571b2e531ea87f77e4' into glitch-soc/merge-4.5
Conflicts:
- `app/controllers/api/v1/statuses_controller.rb`:
  Upstream refactored a bit where we had an extra argument for markdown/HTML.
  Adapted upstream change.
2026-01-19 18:29:02 +01:00
Claire
723b2601b8 Fix custom emojis not being rendered in status prepend (#3342) 2026-01-19 18:27:03 +01:00
Essem
66c06a0655 Merge pull request #3340 from TheEssem/fix/quote-cw-fallback-md
Fix quotes with only CWs not having fallback link when posting with other content types
2026-01-19 18:27:03 +01:00
Claire
ded7f50f2c Fix FeedManager#filter_from_home error when handling a reblog of a deleted status (#37486) 2026-01-19 11:37:34 +01:00
Claire
85eda5b46f Simplify status batch removal SQL query (#37469) 2026-01-19 11:37:34 +01:00
Matt Jankowski
f1c9c89c39 Add spec for quote policy update change (#37474) 2026-01-19 11:37:34 +01:00
Shlee
57e0c6562f Fix quote_approval_policy being reset to user defaults when omitted in status update (#37436) 2026-01-19 11:37:34 +01:00
Joshua Rogers
f7b6e57151 Fix Vary parsing in cache control enforcement (#37426) 2026-01-19 11:37:34 +01:00
Joshua Rogers
57f658dc5c Fix arg order for non_matching_uri_hosts? call in QuoteRequest (#37425) 2026-01-19 11:37:34 +01:00
Joshua Rogers
0cda068918 Fix thread-unsafe ActivityPub activity dispatch (#37423) 2026-01-19 11:37:34 +01:00
David Roetzel
deeaf50472 Fix URI generation for reblogs by accounts with numerical AP ids (#37415) 2026-01-19 11:37:34 +01:00
Shlee
adea0b7b31 Fix SignatureParser accepting duplicate parameters in HTTP Signature header (#37375)
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2026-01-19 11:37:34 +01:00
Shlee
1eb8d1b967 SharedConnectionPool - NoMethodError: undefined method 'site' for Integer (#37374) 2026-01-19 11:37:34 +01:00
Echo
f354bbe8aa Remove trailing variation selector code for legacy emojis (#37320) 2026-01-19 11:37:34 +01:00
diondiondion
53437c4653 Fix mobile admin sidebar displaying under batch table toolbar (#37307) 2026-01-19 11:37:34 +01:00
Claire
617926742c Update SECURITY.md (#37505) 2026-01-15 14:17:38 +01:00
Claire
5799d5d306 Merge pull request #3336 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to 55a7b1ea58 into stable-4.5
2026-01-07 14:40:15 +01:00
Claire
b5d868018d Merge commit '55a7b1ea5820b2fa8d754108b6a948d4bd60d98b' into glitch-soc/merge-4.5 2026-01-07 14:25:37 +01:00
Claire
55a7b1ea58 Bump version to v4.5.4 (#37409) 2026-01-07 14:23:34 +01:00
Claire
c1fb6893c5 Merge commit from fork 2026-01-07 14:15:14 +01:00
Claire
71ae4cf2cf Merge commit from fork 2026-01-07 14:14:42 +01:00
Claire
2ffe03457d Merge pull request #3334 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to a846ed17ff into stable-4.5
2026-01-06 20:38:29 +01:00
Claire
c1f5a9db23 [Glitch] Fix custom emojis not being rendered in profile fields
Port b622f4c698 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-01-06 18:14:35 +01:00
Claire
7c0701d906 [Glitch] Fix outdated link target for “locked” warning
Port e8a49bd6ae to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2026-01-06 18:14:35 +01:00
Claire
b134c6a8ef Merge commit 'a846ed17ffb85087de658678b482495981f02770' into glitch-soc/merge-4.5 2026-01-06 18:12:51 +01:00
Claire
a846ed17ff Fix custom emojis not being rendered in profile fields (#37365) 2026-01-06 14:11:56 +01:00
Claire
3013039720 Fix serialization of context pages (#37376) 2026-01-06 14:11:56 +01:00
Claire
ad4ba5aa00 Fix quotes with CWs but no text not having fallback link (#37361) 2026-01-06 14:11:56 +01:00
Claire
1c5461fffe Fix outdated link target for “locked” warning (#37366) 2026-01-06 14:11:56 +01:00
Claire
725c1a159d Merge pull request #3324 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to 3de59a9344 into stable-4.5
2025-12-28 19:47:25 +01:00
ChaosExAnima
b52efea5cb [Glitch] Remove rendering of custom emoji using the database
Port 3de59a9344 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-28 10:56:09 +01:00
Claire
a0bdfc46c7 [Glitch] Fix custom emojis not displaying in CWs and fav/boost notifications
Port 962ae88caf to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-28 10:55:34 +01:00
diondiondion
afcdc19730 [Glitch] Fix notifications page error in Tor browser
Port 7d9d3de972 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-28 10:55:10 +01:00
Echo
80aa3bc8ad [Glitch] Emojis: Show in embedded statuses
Port 546a95349e to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-28 10:54:47 +01:00
Claire
92955f7e6e [Glitch] Fix hashtag autocomplete replacing suggestion's first characters with input
Port 8d1ea4c531 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-28 10:53:53 +01:00
Claire
b868e598bc Merge commit '3de59a93441367fbca0fd22818c8411adc73a967' into glitch-soc/merge-4.5 2025-12-28 10:51:43 +01:00
ChaosExAnima
3de59a9344 Remove rendering of custom emoji using the database (#37284) 2025-12-19 11:02:32 +01:00
Echo
32c3376d84 Fixes CDN domain loading (#37310) 2025-12-19 11:02:32 +01:00
Claire
962ae88caf Fix custom emojis not displaying in CWs and fav/boost notifications (#37306) 2025-12-19 11:02:32 +01:00
diondiondion
7d9d3de972 Fix notifications page error in Tor browser (#37285) 2025-12-19 11:02:32 +01:00
Echo
546a95349e Emojis: Show in embedded statuses (#37272) 2025-12-19 11:02:32 +01:00
Claire
df1ab0ab90 Fix default Admin role not including view_feeds permission (#37301) 2025-12-19 11:02:32 +01:00
Claire
8d1ea4c531 Fix hashtag autocomplete replacing suggestion's first characters with input (#37281) 2025-12-19 11:02:32 +01:00
Claire
8233295e3b Fix mentions of domain-blocked users being processed (#37257) 2025-12-19 11:02:32 +01:00
Claire
4eb0a506d3 Change HTTP Signature verification status from 401 to 503 on temporary failure to get remote actor (#37221) 2025-12-19 11:02:32 +01:00
Claire
75739a5a9b Change build-releases workflow to tag images latest based on latest stable-x.y branch (#37179)
Co-authored-by: emilweth <7402764+emilweth@users.noreply.github.com>
2025-12-19 11:02:32 +01:00
Claire
54e08a54e9 Merge pull request #3308 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to 86cff1abca into stable-4.5
2025-12-08 17:20:59 +01:00
Claire
12ec21a95f [Glitch] Fix “Delete and Redraft” on a non-quote being treated as a quote post in some cases
Port 1ae3b4672b to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-08 16:40:40 +01:00
Echo
fe9a71975c [Glitch] Fixes YouTube embeds
Port 9bc9ebc59e to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-08 16:40:11 +01:00
Echo
e1f145973b [Glitch] Remove noreferrer from external links
Port 234990cc37 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-08 16:39:17 +01:00
Claire
66f25c6709 [Glitch] Fix error handling when re-fetching already-known statuses
Port edfbcfb3f5 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-08 16:39:03 +01:00
diondiondion
e4e4ffb08d [Glitch] Fix post navigation in single-column mode when Advanced UI is enabled
Port f12f198f61 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-08 16:38:49 +01:00
Claire
e016e2a31e [Glitch] Fix compose autosuggest always lowercasing token
Port a26636ff1f to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-08 16:38:31 +01:00
Claire
6c1e892dd7 Merge commit '86cff1abca6af7ffb1a6ca004ae308c0df6d45ba' into glitch-soc/merge-4.5 2025-12-08 16:37:11 +01:00
Claire
86cff1abca Bump version to v4.5.3 (#37142) 2025-12-08 16:20:15 +01:00
Claire
e6d2fc869b Merge commit from fork 2025-12-08 15:44:08 +01:00
github-actions[bot]
a9f8268a75 New Crowdin Translations for stable-4.5 (automated) (#37158)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-12-08 12:56:49 +01:00
Claire
dfe269439a Fix “Delete and Redraft” on a non-quote being treated as a quote post in some cases (#37140) 2025-12-05 16:50:07 +01:00
Echo
9bc9ebc59e Fixes YouTube embeds (#37126) 2025-12-05 11:15:16 +01:00
Claire
a6d31c0ccf Fix streamed quoted polls not being hydrated correctly (#37118) 2025-12-05 11:15:16 +01:00
David Roetzel
1e2cf6c964 Fix creation of duplicate conversations (#37108) 2025-12-05 11:15:16 +01:00
Echo
c42c71c90a Remove noreferrer from external links (#37107) 2025-12-05 11:15:16 +01:00
Claire
782e410719 Make settings-related database migrations more robust (#37079) 2025-12-05 11:15:16 +01:00
Claire
b0c141e658 Fix error handling when re-fetching already-known statuses (#37077) 2025-12-05 11:15:16 +01:00
diondiondion
1ef4bbd88d Fix post navigation in single-column mode when Advanced UI is enabled (#37044) 2025-12-05 11:15:16 +01:00
Claire
240d38b7c0 Fix tootctl status remove removing quoted posts and remote quotes of local posts (#37009) 2025-12-05 11:15:16 +01:00
Claire
770d1212bb Increase HTTP read timeout for expensive S3 batch delete operation (#37004) 2025-12-05 11:15:16 +01:00
Claire
86e463c0e8 Fix compose autosuggest always lowercasing token (#36995) 2025-12-05 11:15:16 +01:00
Matt Jankowski
a04a210e14 Suggest ES image version 7.17.29 in docker compose (#36972) 2025-12-05 11:15:16 +01:00
Claire
300d62f1c4 Merge pull request #3291 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to 19588756ef into stable-4.5
2025-11-20 15:07:17 +01:00
Claire
27d33d1233 [Glitch] Fix statuses without text disappearing on reload
Port 05c624cfa7 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-20 14:49:45 +01:00
Claire
b35c691ab2 Merge commit '19588756ef62847a01486fa360d4e4ee00307948' into glitch-soc/merge-4.5 2025-11-20 14:49:19 +01:00
Claire
19588756ef Bump version to v4.5.2 (#36944) 2025-11-20 14:41:09 +01:00
github-actions[bot]
e398ff40b2 New Crowdin Translations for stable-4.5 (automated) (#36945)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-20 13:40:31 +01:00
Claire
96eb687524 Fix missing fallback link in CW-only quote posts (#36963) 2025-11-20 12:56:41 +01:00
Claire
05c624cfa7 Fix statuses without text disappearing on reload (#36962) 2025-11-20 12:56:41 +01:00
Claire
dba811952a Merge pull request #3289 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to 5fe316b2e9 into stable-4.5
2025-11-19 22:59:47 +01:00
diondiondion
8836c4fc84 [Glitch] Fix g + h keyboard shortcut not working when a post is focused
Port 1dbf10198d to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:25:09 +01:00
Claire
1da82862f1 [Glitch] Fix quoting overwriting current content warning
Port c6ccacdf7b to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:24:40 +01:00
Claire
8c725777ed [Glitch] Fix scroll-to-status in threaded view being unreliable
Port 6ccd9c2f1f to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:24:15 +01:00
Claire
126823986a [Glitch] Change private quote education modal to not show up on self-quotes
Port 261d9b33fe to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:23:42 +01:00
Claire
f04b06a44f [Glitch] Fix double encoding in links
Port 4ee21c2e29 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:23:13 +01:00
Echo
c7481cb2ca [Glitch] Emoji: Fix path resolution for emoji worker
Port c08cd6d62a to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:22:37 +01:00
Echo
7141917943 [Glitch] Fix error with remote tags including percent signs
Port 6486c092f6 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:19:45 +01:00
Claire
6c7a9b8311 [Glitch] Fix bogus quote approval policy not always being replaced correctly
Port a7b45682a6 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:19:16 +01:00
Claire
8ae06fdbcd [Glitch] Fix hashtag completion not being inserted correctly
Port 5a57c0844a to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:18:46 +01:00
diondiondion
553bb4673e [Glitch] Fix Cmd/Ctrl + Enter in the composer triggering confirmation dialog action
Port 1d081250f4 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:18:16 +01:00
Claire
fe6d3690fd Merge commit '5fe316b2e94bccb91732a1d6675854abb60e9a4b' into glitch-soc/merge-4.5 2025-11-19 22:15:12 +01:00
Claire
9746c5eb6b Merge pull request #3287 from ClearlyClaire/glitch-soc/backports/4.5
Backport changes to stable-4.5
2025-11-19 22:14:32 +01:00
Claire
b5ae2f07a1 Change quotes to inherit local-only status of quoted post in composer (#3286) 2025-11-19 21:29:00 +01:00
Claire
9b91852f93 Fix d bookmark keyboard shortcut (#3285) 2025-11-19 21:28:26 +01:00
Claire
0bb7711225 Fix threaded mode not resetting quote (#3284) 2025-11-19 21:26:10 +01:00
Claire
86445f45fc Clean up CSS differences with upstream (#3283) 2025-11-19 21:26:10 +01:00
Claire
5fe316b2e9 Update dependency glob (#36941) 2025-11-19 16:29:35 +01:00
diondiondion
1dbf10198d Fix g + h keyboard shortcut not working when a post is focused (#36935) 2025-11-19 15:20:01 +01:00
Claire
c6ccacdf7b Fix quoting overwriting current content warning (#36934) 2025-11-19 15:20:01 +01:00
Claire
6ccd9c2f1f Fix scroll-to-status in threaded view being unreliable (#36927) 2025-11-19 15:20:01 +01:00
Claire
261d9b33fe Change private quote education modal to not show up on self-quotes (#36926) 2025-11-19 15:20:01 +01:00
Claire
4ee21c2e29 Fix double encoding in links (#36925) 2025-11-19 15:20:01 +01:00
Echo
c08cd6d62a Emoji: Fix path resolution for emoji worker (#36897) 2025-11-19 15:20:01 +01:00
Shugo Maeda
44d45e5705 Fix ArgumentError of tootctl upgrade storage-schema (#36914) 2025-11-19 15:20:01 +01:00
Claire
27c67f1750 Fix cross-origin handling of CSS modules (#36890) 2025-11-19 15:20:01 +01:00
renovate[bot]
bb28552859 chore(deps): update dependency js-yaml to v4.1.1 [security] (#36891)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-19 15:20:01 +01:00
Echo
6486c092f6 Fix error with remote tags including percent signs (#36886) 2025-11-19 15:20:01 +01:00
Claire
a7b45682a6 Fix bogus quote approval policy not always being replaced correctly (#36885) 2025-11-19 15:20:01 +01:00
Claire
5a57c0844a Fix hashtag completion not being inserted correctly (#36884) 2025-11-19 15:20:01 +01:00
diondiondion
1d081250f4 Fix Cmd/Ctrl + Enter in the composer triggering confirmation dialog action (#36870) 2025-11-19 15:20:01 +01:00
Claire
e6c8958d07 Fix missing alt-text confirmation modal not opening (#3281) 2025-11-15 16:48:12 +01:00
Claire
b2506cc110 Merge pull request #3276 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to bb6093c315 into stable-4.5
2025-11-13 17:58:54 +01:00
Claire
d18491b7a7 [Glitch] Fix error when sending new posts
Port 058f704c21 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 17:36:50 +01:00
Claire
13330030cd [Glitch] Fix posts coming from public/hashtag streaming being marked as unquotable
Port 55b9d21537 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 17:36:21 +01:00
diondiondion
f9012a774c [Glitch] Fix Cmd/Ctrl + Enter not submitting Alt text modal on some browsers
Port 6baa8f2466 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 17:31:18 +01:00
Echo
375af385e7 [Glitch] Fix deprecation warning in Vite
Port 28b9e9087a to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 17:30:32 +01:00
diondiondion
7e5224a3c0 [Glitch] Fixes blank screen in browsers that don't support Intl.DisplayNames
Port fa2cc409ce to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 17:29:41 +01:00
Claire
140d782cba [Glitch] Fix filters not being applied to quotes in detailed view
Port 8a100d84c5 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 17:28:58 +01:00
Echo
c7a7ce8ce7 [Glitch] Emoji: Load emoji with hash in URL
Port 9ae0464e8f to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 17:28:15 +01:00
diondiondion
afbe0a4860 [Glitch] Fix scroll shift caused by fetch-all-replies alerts
Port 9eea4479e1 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 17:27:30 +01:00
diondiondion
febde69d0b [Glitch] Fix dropdown menu not focusing first item when opened via keyboard
Port 30103fd2c8 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 17:26:57 +01:00
Claire
85b9a5944d [Glitch] Fix prepared quote not being discarded with contents when replying
Port fbe05d42fb to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 17:26:34 +01:00
Claire
585827c14f Merge commit 'bb6093c3153f092736e2f25959e3dcdceeb7bce1' into glitch-soc/merge-4.5 2025-11-13 17:22:33 +01:00
Claire
bb6093c315 Bump version to v4.5.1 2025-11-13 17:12:07 +01:00
Claire
058f704c21 Fix error when sending new posts (#36869) 2025-11-13 17:12:07 +01:00
diondiondion
6baa8f2466 Fix Cmd/Ctrl + Enter not submitting Alt text modal on some browsers (#36866) 2025-11-13 17:12:07 +01:00
github-actions[bot]
e742eff044 New Crowdin Translations for stable-4.5 (automated) (#36864)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-13 15:46:34 +01:00
Claire
55b9d21537 Fix posts coming from public/hashtag streaming being marked as unquotable (#36860) 2025-11-13 15:24:58 +01:00
Claire
59f0134578 Fix Update importing old previously-unknown activities and treating them as recent ones (#36848) 2025-11-13 15:24:58 +01:00
Echo
28b9e9087a Fix deprecation warning in Vite (#36849) 2025-11-13 15:24:58 +01:00
diondiondion
fa2cc409ce Fixes blank screen in browsers that don't support Intl.DisplayNames (#36847) 2025-11-13 15:24:58 +01:00
Claire
8a100d84c5 Fix filters not being applied to quotes in detailed view (#36843) 2025-11-13 15:24:58 +01:00
Echo
9ae0464e8f Emoji: Load emoji with hash in URL (#36808) 2025-11-13 15:24:58 +01:00
diondiondion
9eea4479e1 Fix scroll shift caused by fetch-all-replies alerts (#36807) 2025-11-13 15:24:58 +01:00
diondiondion
30103fd2c8 Fix dropdown menu not focusing first item when opened via keyboard (#36804) 2025-11-13 15:24:58 +01:00
Claire
a9a7ad62f1 Update dependency rollup from 4.46.2 to 4.46.4 (#36781) 2025-11-13 15:24:58 +01:00
Claire
ea663cf7c7 Fix /api/v1/statuses/:id/context sometimes returing Mastodon-Async-Refresh without result_count (#36779) 2025-11-13 15:24:58 +01:00
Claire
fbe05d42fb Fix prepared quote not being discarded with contents when replying (#36778) 2025-11-13 15:24:58 +01:00
Claire
29ae9c9c4b Add 4.5.x to the list of supported branches (#36761) 2025-11-06 17:12:41 +01:00
Claire
4684d5e69b Merge pull request #3269 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to 26c78392f8
2025-11-06 13:09:16 +01:00
Claire
3ca92c4ae2 Merge commit '26c78392f88afccebb8a88b68bc9994a9ce12648' into glitch-soc/merge-4.5 2025-11-06 12:49:01 +01:00
Claire
81b1a34d96 Merge pull request #3267 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to 048430f4e8
2025-11-06 12:45:08 +01:00
Claire
26c78392f8 Bump version to v4.5.0 (#36732) 2025-11-06 12:39:07 +01:00
Echo
caecc88247 [Glitch] Fix: correctly dismisses announcement when viewed
Port d45b4db1d7 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-06 12:20:19 +01:00
Echo
bed4ca26e2 [Glitch] Add default visualizer for audio upload without poster
Port ef3a95affc to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-06 12:19:58 +01:00
diondiondion
5d108e95d7 [Glitch] Fix spoiler toggle button being able to submit compose form
Port 3e6a9371b0 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-06 12:18:21 +01:00
Claire
8a2d38a47b Merge commit '048430f4e8010672eb667f1ccf2372571cfb97dd' into glitch-soc/merge-4.5 2025-11-06 12:16:55 +01:00
github-actions[bot]
048430f4e8 New Crowdin Translations for stable-4.5 (automated) (#36745)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-06 11:37:54 +01:00
Echo
d45b4db1d7 Fix: correctly dismisses announcement when viewed (#36750) 2025-11-06 11:23:46 +01:00
Echo
ef3a95affc Add default visualizer for audio upload without poster (#36734) 2025-11-06 10:34:12 +01:00
diondiondion
3e6a9371b0 Fix spoiler toggle button being able to submit compose form (#36736) 2025-11-06 10:34:12 +01:00
Claire
7ab0cfd637 Merge pull request #3266 from ClearlyClaire/glitch-soc/merge-4.5
Port missing changes to stable-4.5
2025-11-05 11:27:29 +01:00
Claire
b33bcc8be6 Merge pull request #3265 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to e91c764590
2025-11-05 10:52:40 +01:00
Claire
cdad6ee0c9 [Glitch] Change paste-link-to-quote loading state from generic loading bar to compose placeholder
Port cfdd9396c0 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-05 10:09:28 +01:00
Claire
2d958cb909 [Glitch] Change quote action to error instead of insert link in Private Mentions
Port ba498ae779 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-05 10:09:12 +01:00
Echo
949f15e200 [Glitch] Quote Posts: Add notifications for DMs and private posts
Port 5bae08d1ff to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-05 10:09:02 +01:00
Claire
105a2d64a7 [Glitch] Fix Skeleton placeholders being animated when setting to reduce animations is enabled
Port 0b50789c5b to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-05 10:08:49 +01:00
Claire
1c17990413 [Glitch] Fix quote dropdown menu item in detailed status view
Port a978e37f4c to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-05 10:08:37 +01:00
Claire
0a8f96d3be [Glitch] Remove option to disable access to local topic feeds for logged-in users
Port dd708298a8 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-05 10:08:24 +01:00
Claire
1ec8e42dbb [Glitch] Disable paste-link-to-quote flow when composing Private Mentions
Port 6d53ca63d6 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-05 10:08:08 +01:00
Claire
7ea3c6a039 Merge commit 'e91c7645905972d9663a0d944b133ff24670bce2' into glitch-soc/merge-4.5 2025-11-05 10:02:33 +01:00
Claire
e91c764590 Bump version to v4.5.0-rc.3 2025-11-05 09:59:00 +01:00
Claire
cfdd9396c0 Change paste-link-to-quote loading state from generic loading bar to compose placeholder (#36695) 2025-11-05 09:59:00 +01:00
Claire
ba498ae779 Change quote action to error instead of insert link in Private Mentions (#36721) 2025-11-05 09:59:00 +01:00
Echo
5bae08d1ff Quote Posts: Add notifications for DMs and private posts (#36696) 2025-11-05 09:59:00 +01:00
Echo
5253527ec4 Add CSS Module support (#36637) 2025-11-05 09:59:00 +01:00
Claire
0b50789c5b Fix Skeleton placeholders being animated when setting to reduce animations is enabled (#36716) 2025-11-05 09:59:00 +01:00
Claire
a978e37f4c Fix quote dropdown menu item in detailed status view (#36704) 2025-11-05 09:59:00 +01:00
Claire
dd708298a8 Remove option to disable access to local topic feeds for logged-in users (#36703) 2025-11-05 09:59:00 +01:00
renovate[bot]
449eb03f11 chore(deps): update dependency sidekiq to v8.0.9 (#36699)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 09:59:00 +01:00
renovate[bot]
1baede0a7c chore(deps): update dependency brakeman to v7.1.1 (#35434)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 09:59:00 +01:00
renovate[bot]
a7ecfc1ca5 fix(deps): update dependency @rails/ujs to v7.1.600 (#36634)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 09:59:00 +01:00
Claire
e62baacfc1 Increase number of quote approval job retries (#36698) 2025-11-05 09:59:00 +01:00
Rachael Wright-Munn
b5a6feb3bf Move "Privacy and reach" from "Public profile" to top-level navigation (#27294) 2025-11-05 09:59:00 +01:00
Claire
05964f571b Prevent creation of Private Mentions quoting someone who is not mentioned (#36689) 2025-11-05 09:59:00 +01:00
Claire
16a54f7158 Fix issuance of quote approval for remote private statuses (#36693) 2025-11-05 09:59:00 +01:00
Claire
6d53ca63d6 Disable paste-link-to-quote flow when composing Private Mentions (#36690) 2025-11-05 09:59:00 +01:00
renovate[bot]
93acfdd7d3 chore(deps): update dependency irb to v1.15.3 (#36682)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 09:59:00 +01:00
renovate[bot]
a209b8e544 chore(deps): update dependency rubyzip to v3.2.2 (#36687)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 09:59:00 +01:00
Claire
ca0c5e7a79 Merge pull request #3258 from ClearlyClaire/glitch-soc/merge-4.5
Merge upstream changes up to af4c372ab2 into stable-4.5
2025-10-31 16:35:41 +01:00
diondiondion
10a81a2f43 [Glitch] Fix initially selected language in Rules panel, hide selector when no alternative translations exist
Port aa579ce286 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-10-31 16:12:38 +01:00
diondiondion
9f8fce3c47 [Glitch] Show error when submitting empty post rather than failing silently
Port 214d59bd37 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-10-31 16:12:03 +01:00
Claire
5f5e6ca031 Merge commit 'af4c372ab22b636742833592235d18418604fcc1' into glitch-soc/merge-4.5 2025-10-31 16:04:05 +01:00
Claire
af4c372ab2 Bump version to v4.5.0-rc.2 2025-10-31 16:01:06 +01:00
diondiondion
aa579ce286 Fix initially selected language in Rules panel, hide selector when no alternative translations exist (#36672) 2025-10-31 16:01:06 +01:00
github-actions[bot]
adfabf8c80 New Crowdin Translations for stable-4.5 (automated) (#36670)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-10-31 14:51:18 +01:00
renovate[bot]
ea710df180 chore(deps): update dependency axios to v1.13.1 (#36633)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-31 14:09:36 +01:00
renovate[bot]
e1b6e28829 chore(deps): update dependency libvips to v8.17.3 (#36654)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-31 14:09:36 +01:00
diondiondion
214d59bd37 Show error when submitting empty post rather than failing silently (#36650) 2025-10-31 14:09:36 +01:00
Claire
e4291e9b05 Fix SMTP configuration with mail 2.9.0 (#36646) 2025-10-31 14:09:36 +01:00
2616 changed files with 38722 additions and 94900 deletions

View File

@@ -1,5 +1,5 @@
# For details, see https://github.com/devcontainers/images/tree/main/src/ruby
FROM mcr.microsoft.com/devcontainers/ruby:3.4-trixie
FROM mcr.microsoft.com/devcontainers/ruby:1-3.3-bookworm
# Install node version from .nvmrc
WORKDIR /app
@@ -9,7 +9,7 @@ RUN /bin/bash --login -i -c "nvm install"
# Install additional OS packages
RUN apt-get update && \
export DEBIAN_FRONTEND=noninteractive && \
apt-get -y install --no-install-recommends libicu-dev libidn11-dev ffmpeg libvips42 libpam-dev
apt-get -y install --no-install-recommends libicu-dev libidn11-dev ffmpeg imagemagick libvips42 libpam-dev
# Disable download prompt for Corepack
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0

View File

@@ -56,7 +56,7 @@ services:
- internal_network
es:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.29
image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2
restart: unless-stopped
environment:
ES_JAVA_OPTS: -Xms512m -Xmx512m
@@ -73,7 +73,7 @@ services:
hard: -1
libretranslate:
image: libretranslate/libretranslate:v1.7.3
image: libretranslate/libretranslate:v1.6.2
restart: unless-stopped
volumes:
- lt-data:/home/libretranslate/.local

View File

@@ -59,7 +59,7 @@ body:
Any additional technical details you may have, like logs or error traces
value: |
If this is happening on your own Mastodon server, please fill out those:
- Ruby version: (from `ruby --version`, eg. v3.4.9)
- Ruby version: (from `ruby --version`, eg. v3.4.4)
- Node.js version: (from `node --version`, eg. v22.16.0)
validations:
required: false

View File

@@ -60,7 +60,7 @@ body:
value: |
Please at least include those informations:
- Operating system: (eg. Ubuntu 24.04.2)
- Ruby version: (from `ruby --version`, eg. v3.4.9)
- Ruby version: (from `ruby --version`, eg. v3.4.4)
- Node.js version: (from `node --version`, eg. v22.16.0)
validations:
required: false

View File

@@ -9,7 +9,7 @@ runs:
using: 'composite'
steps:
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
@@ -23,7 +23,7 @@ runs:
shell: bash
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
- uses: actions/cache@v4
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}

View File

@@ -14,10 +14,10 @@ runs:
shell: bash
run: |
sudo apt-get update
sudo apt-get install --no-install-recommends -y libicu-dev libidn11-dev libvips42 ${{ inputs.additional-system-dependencies }}
sudo apt-get install -y libicu-dev libidn11-dev libvips42 ${{ inputs.additional-system-dependencies }}
- name: Set up Ruby
uses: ruby/setup-ruby@4eb9f110bac952a8b68ecf92e3b5c7a987594ba6 # v1
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ inputs.ruby-version }}
bundler-cache: true

View File

@@ -5,6 +5,7 @@
'customManagers:dockerfileVersions',
':labels(dependencies)',
':prConcurrentLimitNone', // Remove limit for open PRs at any time.
':prHourlyLimit2', // Rate limit PR creation to a maximum of two per hour.
':enableVulnerabilityAlertsWithLabel(security)',
],
rebaseWhen: 'conflicted',
@@ -22,6 +23,8 @@
// Require Dependency Dashboard Approval for major version bumps of these node packages
matchManagers: ['npm'],
matchPackageNames: [
'tesseract.js', // Requires code changes
// react-router: Requires manual upgrade
'history',
'react-router-dom',
@@ -113,7 +116,6 @@
],
matchUpdateTypes: ['major'],
groupName: 'artifact actions (major)',
extends: ['helpers:pinGitHubActionDigests'],
},
{
// Update @types/* packages every week, with one grouped PR
@@ -154,15 +156,9 @@
groupName: 'opentelemetry-ruby (non-major)',
},
{
// The ruby portion of the Playwright group
matchManagers: ['bundler'],
matchPackageNames: ['playwright-ruby-client'],
groupName: 'Playwright',
},
{
// The node portion of the Playwright group
matchManagers: ['npm'],
matchPackageNames: ['playwright'],
// Group Playwright Ruby & JS deps in the same PR, as they need to be in sync
matchManagers: ['bundler', 'npm'],
matchPackageNames: ['playwright-ruby-client', 'playwright'],
groupName: 'Playwright',
},
// Add labels depending on package manager

View File

@@ -35,7 +35,7 @@ jobs:
- linux/arm64
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/checkout@v4
- name: Prepare
env:
@@ -47,19 +47,19 @@ jobs:
image_names=${PUSH_TO_IMAGES//$'\n'/,}
echo "IMAGE_NAMES=${image_names%,}" >> $GITHUB_ENV
- uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- uses: docker/setup-buildx-action@v3
id: buildx
- name: Log in to Docker Hub
if: contains(inputs.push_to_images, 'tootsuite')
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to the GitHub Container registry
if: contains(inputs.push_to_images, 'ghcr.io')
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -67,7 +67,7 @@ jobs:
- name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
uses: docker/metadata-action@v5
if: ${{ inputs.push_to_images != '' }}
with:
images: ${{ inputs.push_to_images }}
@@ -76,7 +76,7 @@ jobs:
- name: Build and push by digest
id: build
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
uses: docker/build-push-action@v6
with:
context: .
file: ${{ inputs.file_to_build }}
@@ -100,7 +100,7 @@ jobs:
- name: Upload digest
if: ${{ inputs.push_to_images != '' }}
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@v4
with:
# `hashFiles` is used to disambiguate between streaming and non-streaming images
name: digests-${{ hashFiles(inputs.file_to_build) }}-${{ env.PLATFORM_PAIR }}
@@ -119,10 +119,10 @@ jobs:
PUSH_TO_IMAGES: ${{ inputs.push_to_images }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/checkout@v4
- name: Download digests
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
# `hashFiles` is used to disambiguate between streaming and non-streaming images
@@ -131,25 +131,25 @@ jobs:
- name: Log in to Docker Hub
if: contains(inputs.push_to_images, 'tootsuite')
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to the GitHub Container registry
if: contains(inputs.push_to_images, 'ghcr.io')
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
uses: docker/metadata-action@v5
if: ${{ inputs.push_to_images != '' }}
with:
images: ${{ inputs.push_to_images }}

View File

@@ -18,7 +18,7 @@ jobs:
steps:
# Repository needs to be cloned so `git rev-parse` below works
- name: Clone repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
- id: version_vars
run: |
echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT

View File

@@ -16,7 +16,7 @@ jobs:
steps:
# Repository needs to be cloned to list branches
- name: Clone repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v6
with:
fetch-depth: 0

View File

@@ -28,10 +28,10 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@4eb9f110bac952a8b68ecf92e3b5c7a987594ba6 # v1
uses: ruby/setup-ruby@v1
with:
bundler-cache: true

View File

@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/checkout@v4
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
@@ -42,7 +42,8 @@ jobs:
- name: Check for missing strings in English YML
run: |
bin/i18n-tasks missing -t used -l en
bin/i18n-tasks add-missing -l en
git diff --exit-code
- name: Check for wrong string interpolations
run: bin/i18n-tasks check-consistent-interpolations

View File

@@ -1,51 +1,31 @@
name: 'Chromatic'
permissions:
contents: read
on:
push:
branches-ignore:
- renovate/*
- stable-*
paths:
- 'package.json'
- 'yarn.lock'
- '**/*.js'
- '**/*.jsx'
- '**/*.ts'
- '**/*.tsx'
- '**/*.css'
- '**/*.scss'
- '.github/workflows/chromatic.yml'
jobs:
pathcheck:
name: Check for relevant changes
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.filter.outputs.src }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
id: filter
with:
filters: |
src:
- 'package.json'
- 'yarn.lock'
- '**/*.js'
- '**/*.jsx'
- '**/*.ts'
- '**/*.tsx'
- '**/*.css'
- '**/*.scss'
- '.github/workflows/chromatic.yml'
chromatic:
name: Run Chromatic
runs-on: ubuntu-latest
needs: pathcheck
if: github.repository == 'mastodon/mastodon' && needs.pathcheck.outputs.changed == 'true'
if: github.repository == 'mastodon/mastodon'
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
@@ -53,10 +33,9 @@ jobs:
run: yarn build-storybook
- name: Run Chromatic
uses: chromaui/action@07791f8243f4cb2698bf4d00426baf4b2d1cb7e0 # v13
uses: chromaui/action@v12
with:
# ⚠️ Make sure to configure a `CHROMATIC_PROJECT_TOKEN` repository secret
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
zip: true
storybookBuildDir: 'storybook-static'
exitOnceUploaded: true # Exit immediately after upload
autoAcceptChanges: 'main' # Auto-accept changes on main branch only

View File

@@ -31,11 +31,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -48,7 +48,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4
uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -61,6 +61,6 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4
uses: github/codeql-action/analyze@v3
with:
category: '/language:${{matrix.language}}'

View File

@@ -13,7 +13,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
- name: Increase Git http.postBuffer
# This is needed due to a bug in Ubuntu's cURL version?
@@ -24,7 +24,7 @@ jobs:
# Download the translation files from Crowdin
- name: crowdin action
uses: crowdin/github-action@b4b468cffefb50bdd99dd83e5d2eaeb63c880380 # v2
uses: crowdin/github-action@v2
with:
config: crowdin-glitch.yml
upload_sources: false
@@ -51,7 +51,7 @@ jobs:
# Create or update the pull request
- name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
uses: peter-evans/create-pull-request@v7.0.8
with:
commit-message: 'New Crowdin translations'
title: 'New Crowdin Translations for ${{ github.base_ref || github.ref_name }} (automated)'

View File

@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
- name: Increase Git http.postBuffer
# This is needed due to a bug in Ubuntu's cURL version?
@@ -26,7 +26,7 @@ jobs:
# Download the translation files from Crowdin
- name: crowdin action
uses: crowdin/github-action@b4b468cffefb50bdd99dd83e5d2eaeb63c880380 # v2
uses: crowdin/github-action@v2
with:
config: crowdin-glitch.yml
upload_sources: false
@@ -53,7 +53,7 @@ jobs:
# Create or update the pull request
- name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8
uses: peter-evans/create-pull-request@v7
with:
commit-message: 'New Crowdin translations'
title: 'New Crowdin Translations (automated)'

View File

@@ -23,10 +23,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
- name: crowdin action
uses: crowdin/github-action@b4b468cffefb50bdd99dd83e5d2eaeb63c880380 # v2
uses: crowdin/github-action@v2
with:
config: crowdin-glitch.yml
upload_sources: true

View File

@@ -13,10 +13,10 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Check formatting
- name: Check formatting with Prettier
run: yarn format:check

View File

@@ -0,0 +1,17 @@
{
"problemMatcher": [
{
"owner": "haml-lint",
"severity": "warning",
"pattern": [
{
"regexp": "^(.*):(\\d+)\\s\\[W]\\s(.*):\\s(.*)$",
"file": 1,
"line": 2,
"code": 3,
"message": 4
}
]
}
]
}

View File

@@ -9,6 +9,7 @@ on:
- 'package.json'
- 'yarn.lock'
- '.nvmrc'
- '.prettier*'
- 'stylelint.config.js'
- '**/*.css'
- '**/*.scss'
@@ -20,6 +21,7 @@ on:
- 'package.json'
- 'yarn.lock'
- '.nvmrc'
- '.prettier*'
- 'stylelint.config.js'
- '**/*.css'
- '**/*.scss'
@@ -32,7 +34,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript

View File

@@ -33,13 +33,14 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@4eb9f110bac952a8b68ecf92e3b5c7a987594ba6 # v1
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Run haml-lint
run: |
echo "::add-matcher::.github/workflows/haml-lint-problem-matcher.json"
bin/haml-lint --reporter github

View File

@@ -10,6 +10,7 @@ on:
- 'yarn.lock'
- 'tsconfig.json'
- '.nvmrc'
- '.prettier*'
- 'eslint.config.mjs'
- '**/*.js'
- '**/*.jsx'
@@ -23,6 +24,7 @@ on:
- 'yarn.lock'
- 'tsconfig.json'
- '.nvmrc'
- '.prettier*'
- 'eslint.config.mjs'
- '**/*.js'
- '**/*.jsx'
@@ -36,7 +38,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript

View File

@@ -35,15 +35,15 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@4eb9f110bac952a8b68ecf92e3b5c7a987594ba6 # v1
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Set-up RuboCop Problem Matcher
uses: r7kamura/rubocop-problem-matchers-action@59f1a0759f50cc2649849fd850b8487594bb5a81 # v1.2.2
uses: r7kamura/rubocop-problem-matchers-action@v1
- name: Run rubocop
run: bin/rubocop

View File

@@ -18,7 +18,7 @@ jobs:
steps:
- name: Check for merge conflicts
uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 # v3
uses: eps1lon/actions-label-merge-conflict@v3
with:
dirtyLabel: 'rebase needed :construction:'
repoToken: '${{ secrets.GITHUB_TOKEN }}'

View File

@@ -34,7 +34,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript

View File

@@ -72,7 +72,7 @@ jobs:
BUNDLE_RETRY: 3
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/checkout@v4
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby

View File

@@ -32,7 +32,7 @@ jobs:
SECRET_KEY_BASE_DUMMY: 1
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/checkout@v4
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
@@ -43,7 +43,7 @@ jobs:
onlyProduction: 'true'
- name: Cache assets from compilation
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
uses: actions/cache@v4
with:
path: |
public/assets
@@ -65,7 +65,7 @@ jobs:
run: |
tar --exclude={"*.br","*.gz"} -zcf artifacts.tar.gz public/assets public/packs* tmp/cache/vite/last-build*.json
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- uses: actions/upload-artifact@v4
if: matrix.mode == 'test'
with:
path: |-
@@ -124,12 +124,13 @@ jobs:
fail-fast: false
matrix:
ruby-version:
- '3.2'
- '3.3'
- '.ruby-version'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/checkout@v4
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
- uses: actions/download-artifact@v4
with:
path: './'
name: ${{ github.sha }}
@@ -150,7 +151,7 @@ jobs:
bin/flatware fan bin/rails db:test:prepare
- name: Cache RSpec persistence file
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
uses: actions/cache@v4
with:
path: |
tmp/rspec/examples.txt
@@ -166,12 +167,99 @@ jobs:
- name: Upload coverage reports to Codecov
if: matrix.ruby-version == '.ruby-version'
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
uses: codecov/codecov-action@v5
with:
files: coverage/lcov/*.lcov
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
test-imagemagick:
name: ImageMagick tests
runs-on: ubuntu-latest
needs:
- build
services:
postgres:
image: postgres:14-alpine
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
options: >-
--health-cmd pg_isready
--health-interval 10ms
--health-timeout 3s
--health-retries 50
ports:
- 5432:5432
redis:
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10ms
--health-timeout 3s
--health-retries 50
ports:
- 6379:6379
env:
DB_HOST: localhost
DB_USER: postgres
DB_PASS: postgres
COVERAGE: ${{ matrix.ruby-version == '.ruby-version' }}
RAILS_ENV: test
ALLOW_NOPAM: true
PAM_ENABLED: true
PAM_DEFAULT_SERVICE: pam_test
PAM_CONTROLLED_SERVICE: pam_test_controlled
OIDC_ENABLED: true
OIDC_SCOPE: read
SAML_ENABLED: true
CAS_ENABLED: true
BUNDLE_WITH: 'pam_authentication test'
GITHUB_RSPEC: ${{ matrix.ruby-version == '.ruby-version' && github.event.pull_request && 'true' }}
MASTODON_USE_LIBVIPS: false
strategy:
fail-fast: false
matrix:
ruby-version:
- '3.2'
- '3.3'
- '.ruby-version'
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
path: './'
name: ${{ github.sha }}
- name: Expand archived asset artifacts
run: |
tar xvzf artifacts.tar.gz
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
with:
ruby-version: ${{ matrix.ruby-version}}
additional-system-dependencies: ffmpeg imagemagick libpam-dev
- name: Load database schema
run: './bin/rails db:create db:schema:load db:seed'
- run: bin/rspec --tag attachment_processing
- name: Upload coverage reports to Codecov
if: matrix.ruby-version == '.ruby-version'
uses: codecov/codecov-action@v5
with:
files: coverage/lcov/mastodon.lcov
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
test-e2e:
name: End to End testing
runs-on: ubuntu-latest
@@ -216,13 +304,14 @@ jobs:
fail-fast: false
matrix:
ruby-version:
- '3.2'
- '3.3'
- '.ruby-version'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/checkout@v4
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
- uses: actions/download-artifact@v4
with:
path: './'
name: ${{ github.sha }}
@@ -245,7 +334,7 @@ jobs:
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
@@ -261,14 +350,14 @@ jobs:
- run: bin/rspec spec/system --tag streaming --tag js
- name: Archive logs
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@v4
if: failure()
with:
name: e2e-logs-${{ matrix.ruby-version }}
path: log/
- name: Archive test screenshots
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@v4
if: failure()
with:
name: e2e-screenshots-${{ matrix.ruby-version }}
@@ -346,20 +435,21 @@ jobs:
fail-fast: false
matrix:
ruby-version:
- '3.2'
- '3.3'
- '.ruby-version'
search-image:
- docker.elastic.co/elasticsearch/elasticsearch:7.17.29
- docker.elastic.co/elasticsearch/elasticsearch:7.17.13
include:
- ruby-version: '.ruby-version'
search-image: docker.elastic.co/elasticsearch/elasticsearch:8.19.2
search-image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2
- ruby-version: '.ruby-version'
search-image: opensearchproject/opensearch:2
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/checkout@v4
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
- uses: actions/download-artifact@v4
with:
path: './'
name: ${{ github.sha }}
@@ -379,8 +469,15 @@ jobs:
- run: bin/rspec --tag search
- name: Archive logs
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@v4
if: failure()
with:
name: test-search-logs-${{ matrix.ruby-version }}
path: log/
- name: Archive test screenshots
uses: actions/upload-artifact@v4
if: failure()
with:
name: test-search-screenshots
path: tmp/capybara/

View File

@@ -10,6 +10,6 @@ linters:
MiddleDot:
enabled: true
LineLength:
max: 240 # Override default value of 80 inherited from rubocop
max: 300
ViewLength:
max: 200 # Override default value of 100 inherited from rubocop

2
.nvmrc
View File

@@ -1 +1 @@
24.14
24.10

View File

@@ -1,99 +0,0 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"singleQuote": true,
"jsxSingleQuote": true,
"printWidth": 80,
"ignorePatterns": [
"/tmp",
"/coverage",
"/public/assets",
"/public/emoji",
"/public/packs",
"/public/packs-test",
"/public/system",
"/public/vite*",
"*.html",
"docker-compose.override.yml",
// Ignore config YAML files that include ERB/ruby code
"config/email.yml",
// Vendored CSS
"app/javascript/styles/mastodon/reset.scss",
"app/javascript/flavours/glitch/styles/reset.scss",
// Automatically generated
"/app/javascript/mastodon/features/emoji/emoji_map.json",
"/app/javascript/mastodon/features/emoji/emoji_data.json",
"AUTHORS.md",
"/app/javascript/mastodon/locales/*.json",
"/config/locales",
".storybook/static/mockServiceWorker.js",
// Automatically generated (glitch-soc)
"/app/javascript/flavours/glitch/features/emoji/emoji_map.json",
"/app/javascript/flavours/glitch/features/emoji/emoji_data.json",
"/app/javascript/flavours/glitch/locales/*.json",
"/config/locales-glitch",
// do not reformat JS files as this will change too many files and cause merge conflicts with open PRs and forks
"app/javascript/**/*.js",
"app/javascript/**/*.jsx",
"streaming/**/*.js"
],
"experimentalSortPackageJson": false,
"experimentalSortImports": {
"groups": [
["builtin"],
["react"],
["react-intl"],
["react-utils"],
["redux"],
["external", "type-external"],
["internal", "type-internal"],
["mastodon-internals"],
["parent", "type-parent"],
["sibling", "type-sibling", "index", "type-index"],
["side_effect"]
],
"customGroups": [
{
"groupName": "react",
"elementNamePattern": [
"react",
"react-dom",
"react-dom/client",
"prop-types"
]
},
{
"groupName": "react-intl",
"elementNamePattern": ["react-intl", "intl-messageformat"]
},
{
"groupName": "react-utils",
"elementNamePattern": [
"classnames",
"react-helmet",
"react-router",
"react-router-dom"
]
},
{
"groupName": "redux",
"elementNamePattern": [
"immutable",
"@reduxjs/toolkit",
"react-redux",
"react-immutable-proptypes",
"react-immutable-pure-component"
]
},
{
"groupName": "mastodon-internals",
"elementNamePattern": ["mastodon/**", "flavours/glitch/**", "@/**"]
}
]
}
}

100
.prettierignore Normal file
View File

@@ -0,0 +1,100 @@
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'
# Ignore bundler config and downloaded libraries.
/.bundle
/vendor/bundle
# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
# Ignore all logfiles and tempfiles.
.eslintcache
/log/*
!/log/.keep
/tmp
/coverage
.env
.env.production
.env.development
/node_modules/
/build/
# Ignore Vagrant files
.vagrant/
# Ignore IDE files
.vscode/
.idea/
# Ignore postgres + redis + elasticsearch volume optionally created by docker-compose
/postgres
/postgres14
/redis
/elasticsearch
# Ignore Apple files
.DS_Store
# Ignore vim files
*~
*.swp
# Ignore log files
*.log
# Ignore Docker option files
docker-compose.override.yml
# Ignore public
/public/assets
/public/emoji
/public/packs
/public/packs-test
/public/system
/public/vite*
# Ignore emoji map file
/app/javascript/mastodon/features/emoji/emoji_map.json
/app/javascript/mastodon/features/emoji/emoji_data.json
# Ignore locale files
/app/javascript/mastodon/locales/*.json
/config/locales
# Ignore vendored CSS reset
app/javascript/styles/mastodon/reset.scss
# Ignore Javascript pending https://github.com/mastodon/mastodon/pull/23631
*.js
*.jsx
# Ignore HTML till cleaned and included in CI
*.html
# Ignore the generated AUTHORS.md
AUTHORS.md
# Process a few selected JS files
!lint-staged.config.js
# Ignore config YAML files that include ERB/ruby code prettier does not understand
/config/email.yml
# Ignore glitch-soc emoji map file
/app/javascript/flavours/glitch/features/emoji/emoji_map.json
/app/javascript/flavours/glitch/features/emoji/emoji_data.json
# Ignore glitch-soc locale files
/app/javascript/flavours/glitch/locales
/config/locales-glitch
# Ignore glitch-soc vendored CSS reset
app/javascript/flavours/glitch/styles/reset.scss
# Ignore win95 theme
app/javascript/styles/win95.scss

4
.prettierrc.js Normal file
View File

@@ -0,0 +1,4 @@
module.exports = {
singleQuote: true,
jsxSingleQuote: true
};

View File

@@ -8,7 +8,7 @@ AllCops:
- lib/mastodon/migration_helpers.rb
ExtraDetails: true
NewCops: enable
TargetRubyVersion: 3.3 # Oldest supported ruby version
TargetRubyVersion: 3.2 # Oldest supported ruby version
inherit_from:
- .rubocop/layout.yml

View File

@@ -4,6 +4,3 @@ Layout/FirstHashElementIndentation:
Layout/LineLength:
Max: 300 # Default of 120 causes a duplicate entry in generated todo file
Layout/MultilineMethodCallIndentation:
EnforcedStyle: indented

View File

@@ -1 +1 @@
3.4.9
3.4.7

View File

@@ -3,18 +3,7 @@ import { resolve } from 'node:path';
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: [
{
directory: '../app/javascript/mastodon',
files: '**/*.stories.@(js|jsx|mjs|ts|tsx)',
titlePrefix: 'Vanilla',
},
{
directory: '../app/javascript/flavours/glitch',
files: '**/*.stories.@(js|jsx|mjs|ts|tsx)',
titlePrefix: 'Glitch',
},
],
stories: ['../app/javascript/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-docs',
'@storybook/addon-a11y',
@@ -38,12 +27,11 @@ const config: StorybookConfig = {
'oops.gif',
'oops.png',
].map((path) => ({ from: `../public/${path}`, to: `/${path}` })),
{ from: '../app/javascript/images/logo.svg', to: '/custom-emoji/logo.svg' },
],
viteFinal(config) {
// For an unknown reason, Storybook does not use the root
// from the Vite config so we need to set it manually.
config.root = resolve(import.meta.dirname, '../app/javascript');
config.root = resolve(__dirname, '../app/javascript');
return config;
},
};

View File

@@ -1,8 +0,0 @@
export const modes = {
darkTheme: {
theme: 'dark',
},
lightTheme: {
theme: 'light',
},
} as const;

View File

@@ -1,2 +1,2 @@
<html class="no-reduce-motion" data-color-scheme="light">
<html class="no-reduce-motion">
</html>

View File

@@ -11,25 +11,19 @@ import type { Preview } from '@storybook/react-vite';
import { initialize, mswLoader } from 'msw-storybook-addon';
import { action } from 'storybook/actions';
import {
importCustomEmojiData,
importLegacyShortcodes,
importEmojiData,
} from '@/mastodon/features/emoji/loader';
import type { LocaleData } from '@/mastodon/locales';
import { reducerWithInitialState } from '@/mastodon/reducers';
import { defaultMiddleware } from '@/mastodon/store/store';
import { mockHandlers, unhandledRequestHandler } from '@/testing/api';
import { modes } from './modes';
import '../app/javascript/styles/application.scss';
// If you want to run the dark theme during development,
// you can change the below to `/application.scss`
import '../app/javascript/styles/mastodon-light.scss';
import './styles.css';
// Disabling locales in Storybook as it's breaking with Vite 8.
// const localeFiles = import.meta.glob('@/mastodon/locales/*.json', {
// query: { as: 'json' },
// });
const localeFiles = import.meta.glob('@/mastodon/locales/*.json', {
query: { as: 'json' },
});
// Initialize MSW
initialize({
@@ -40,57 +34,28 @@ const preview: Preview = {
// Auto-generate docs: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
globalTypes: {
// locale: {
// description: 'Locale for the story',
// toolbar: {
// title: 'Locale',
// icon: 'globe',
// items: Object.keys(localeFiles).map((path) =>
// path.replace('/mastodon/locales/', '').replace('.json', ''),
// ),
// dynamicTitle: true,
// },
// },
theme: {
description: 'Theme for the story',
locale: {
description: 'Locale for the story',
toolbar: {
title: 'Theme',
icon: 'circlehollow',
items: [{ value: 'light' }, { value: 'dark' }],
title: 'Locale',
icon: 'globe',
items: Object.keys(localeFiles).map((path) =>
path.replace('/mastodon/locales/', '').replace('.json', ''),
),
dynamicTitle: true,
},
},
},
initialGlobals: {
locale: 'en',
theme: 'light',
},
decorators: [
(Story, { parameters, globals, args, argTypes }) => {
(Story, { parameters, globals, args }) => {
// Get the locale from the global toolbar
// and merge it with any parameters or args state.
const { locale } = globals as { locale: string };
const { state = {} } = parameters;
const argsState: Record<string, unknown> = {};
for (const [key, value] of Object.entries(args)) {
const argType = argTypes[key];
if (argType?.reduxPath) {
const reduxPath = Array.isArray(argType.reduxPath)
? argType.reduxPath.map((p) => p.toString())
: argType.reduxPath.split('.');
reduxPath.reduce((acc, key, i) => {
if (acc[key] === undefined) {
acc[key] = {};
}
if (i === reduxPath.length - 1) {
acc[key] = value;
}
return acc[key] as Record<string, unknown>;
}, argsState);
}
}
const { state: argsState = {} } = args;
const reducer = reducerWithInitialState(
{
@@ -99,7 +64,7 @@ const preview: Preview = {
},
},
state as Record<string, unknown>,
argsState,
argsState as Record<string, unknown>,
);
const store = configureStore({
@@ -137,18 +102,15 @@ const preview: Preview = {
}, [currentLocale, currentLocaleData]);
return (
<IntlProvider locale={currentLocale} messages={currentLocaleData}>
<IntlProvider
locale={currentLocale}
messages={currentLocaleData}
textComponent='span'
>
<Story />
</IntlProvider>
);
},
(Story, { globals }) => {
const theme = (globals.theme as string) || 'light';
useEffect(() => {
document.body.setAttribute('data-color-scheme', theme);
}, [theme]);
return <Story />;
},
(Story) => (
<MemoryRouter>
<Story />
@@ -165,12 +127,7 @@ const preview: Preview = {
</MemoryRouter>
),
],
loaders: [
mswLoader,
importCustomEmojiData,
importLegacyShortcodes,
({ globals: { locale } }) => importEmojiData(locale as string),
],
loaders: [mswLoader],
parameters: {
layout: 'centered',
@@ -195,13 +152,6 @@ const preview: Preview = {
msw: {
handlers: mockHandlers,
},
chromatic: {
modes: {
dark: modes.darkTheme,
light: modes.lightTheme,
},
},
},
};

View File

@@ -7,7 +7,7 @@
* - Please do NOT modify this file.
*/
const PACKAGE_VERSION = '2.12.14'
const PACKAGE_VERSION = '2.11.3'
const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
const activeClientIds = new Set()
@@ -205,7 +205,6 @@ async function resolveMainClient(event) {
* @param {FetchEvent} event
* @param {Client | undefined} client
* @param {string} requestId
* @param {number} requestInterceptedAt
* @returns {Promise<Response>}
*/
async function getResponse(event, client, requestId, requestInterceptedAt) {

View File

@@ -1,20 +1,7 @@
// The addon package.json incorrectly exports types, so we need to override them here.
import type { RootState } from '@/mastodon/store';
// See: https://github.com/storybookjs/storybook/blob/v9.0.4/code/addons/vitest/package.json#L70-L76
declare module '@storybook/addon-vitest/vitest-plugin' {
export * from '@storybook/addon-vitest/dist/vitest-plugin/index';
}
type RootPathKeys = keyof RootState;
declare module 'storybook/internal/csf' {
export interface InputType {
reduxPath?:
| `${RootPathKeys}.${string}`
| [RootPathKeys, ...(string | number)[]];
}
}
export {};

View File

@@ -0,0 +1,8 @@
import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';
import { setProjectAnnotations } from '@storybook/react-vite';
import * as projectAnnotations from './preview';
// This is an important step to apply the right configuration when testing your stories.
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);

View File

@@ -0,0 +1,13 @@
diff --git a/lib/index.js b/lib/index.js
index 16ed6be8be8f555cc99096c2ff60954b42dc313d..d009c069770d066ad0db7ad02de1ea473a29334e 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -99,7 +99,7 @@ function lodash(_ref) {
var node = _ref3;
- if ((0, _types.isModuleDeclaration)(node)) {
+ if ((0, _types.isImportDeclaration)(node) || (0, _types.isExportDeclaration)(node)) {
isModule = true;
break;
}

View File

@@ -538,7 +538,7 @@ and provided thanks to the work of the following contributors:
* [Drew Schuster](mailto:dtschust@gmail.com)
* [Dryusdan](mailto:dryusdan@dryusdan.fr)
* [Eai](mailto:eai@mizle.net)
* [Eashwar Ranganathan](mailto:eashwar@eashwar.com)
* [Eashwar Ranganathan](mailto:eranganathan@lyft.com)
* [Ed Knutson](mailto:knutsoned@gmail.com)
* [Elizabeth Martín Campos](mailto:me@elizabeth.sh)
* [Elizabeth Myers](mailto:elizabeth@interlinked.me)

File diff suppressed because it is too large Load Diff

View File

@@ -50,8 +50,6 @@ You can contribute in the following ways:
Please review the org-level [contribution guidelines] for high-level acceptance
criteria guidance and the [DEVELOPMENT] guide for environment-specific details.
You should also read the project's [AI Contribution Policy] to understand how we approach
AI-assisted contributions.
## API Changes and Additions
@@ -82,7 +80,7 @@ reviewed and merged into the codebase.
Our time is limited and PRs making large, unsolicited changes are unlikely to
get a response. Changes which link to an existing confirmed issue, or which come
from a "help wanted" issue or other request, are more likely to be reviewed.
from a "help wanted" issue or other request are more likely to be reviewed.
The smaller and more narrowly focused the changes in a PR are, the easier they
are to review and potentially merge. If the change only makes sense in some
@@ -132,4 +130,3 @@ and API docs. Improvements are made via PRs to the [documentation repository].
[keepachangelog]: https://keepachangelog.com/en/1.0.0/
[Mastodon documentation]: https://docs.joinmastodon.org
[SECURITY]: SECURITY.md
[AI Contribution Policy]: https://github.com/mastodon/.github/blob/main/AI_POLICY.md

View File

@@ -13,7 +13,7 @@ ARG BASE_REGISTRY="docker.io"
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.4.x"]
# renovate: datasource=docker depName=docker.io/ruby
ARG RUBY_VERSION="3.4.9"
ARG RUBY_VERSION="3.4.7"
# # Node.js version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="22"]
# renovate: datasource=node-version depName=node
ARG NODE_MAJOR_VERSION="24"
@@ -70,6 +70,8 @@ ENV \
PATH="${PATH}:/opt/ruby/bin:/opt/mastodon/bin" \
# Optimize jemalloc 5.x performance
MALLOC_CONF="narenas:2,background_thread:true,thp:never,dirty_decay_ms:1000,muzzy_decay_ms:0" \
# Enable libvips, should not be changed
MASTODON_USE_LIBVIPS=true \
# Sidekiq will touch tmp/sidekiq_process_has_started_and_will_begin_processing_jobs to indicate it is ready. This can be used for a readiness check in Kubernetes
MASTODON_SIDEKIQ_READY_FILENAME=sidekiq_process_has_started_and_will_begin_processing_jobs
@@ -181,7 +183,7 @@ FROM build AS libvips
# libvips version to compile, change with [--build-arg VIPS_VERSION="8.15.2"]
# renovate: datasource=github-releases depName=libvips packageName=libvips/libvips
ARG VIPS_VERSION=8.18.1
ARG VIPS_VERSION=8.17.3
# libvips download URL, change with [--build-arg VIPS_URL="https://github.com/libvips/libvips/releases/download"]
ARG VIPS_URL=https://github.com/libvips/libvips/releases/download

View File

@@ -13,8 +13,7 @@
- [FEP-f1d5: NodeInfo in Fediverse Software](https://codeberg.org/fediverse/fep/src/branch/main/fep/f1d5/fep-f1d5.md)
- [FEP-8fcf: Followers collection synchronization across servers](https://codeberg.org/fediverse/fep/src/branch/main/fep/8fcf/fep-8fcf.md)
- [FEP-5feb: Search indexing consent for actors](https://codeberg.org/fediverse/fep/src/branch/main/fep/5feb/fep-5feb.md)
- [FEP-044f: Consent-respecting quote posts](https://codeberg.org/fediverse/fep/src/branch/main/fep/044f/fep-044f.md)
- [FEP-3b86: Activity Intents](https://codeberg.org/fediverse/fep/src/branch/main/fep/3b86/fep-3b86.md): offer handlers for `Object` and `Create` (with support for the `content` parameter only), has support for the `Follow`, `Announce`, `Like` and `Object` intents
- [FEP-044f: Consent-respecting quote posts](https://codeberg.org/fediverse/fep/src/branch/main/fep/044f/fep-044f.md): partial support for incoming quote-posts
## ActivityPub in Mastodon
@@ -53,8 +52,8 @@ Mastodon requires all `POST` requests to be signed, and MAY require `GET` reques
## Size limits
Mastodon imposes a few hard limits on federated content.
These limits are intended to be very generous and way above what the Mastodon user experience is optimized for, so as to accommodate future changes and unusual or unforeseen usage patterns, while still providing some limits for performance reasons.
The following table summarizes those limits.
These limits are intended to be very generous and way above what the Mastodon user experience is optimized for, so as to accomodate future changes and unusual or unforeseen usage patterns, while still providing some limits for performance reasons.
The following table attempts to summary those limits.
| Limited property | Size limit | Consequence of exceeding the limit |
| ------------------------------------------------------------- | ---------- | ---------------------------------- |
@@ -68,6 +67,4 @@ The following table summarizes those limits.
| Account `attributionDomains` | 256 | List will be truncated |
| Account aliases (actor `alsoKnownAs`) | 256 | List will be truncated |
| Custom emoji shortcode (`Emoji` `name`) | 2048 | Emoji will be rejected |
| Media and avatar/header descriptions (`name`/`summary`) | 10000 | Description will be truncated |
| Collection name (`FeaturedCollection` `name`) | 256 | Name will be truncated |
| Collection description (`FeaturedCollection` `summary`) | 2048 | Description will be truncated |
| Media descriptions (`name`/`summary`) | 10000 | Description will be truncated |

47
Gemfile
View File

@@ -1,11 +1,11 @@
# frozen_string_literal: true
source 'https://rubygems.org'
ruby '>= 3.3.0', '< 3.5.0'
ruby '>= 3.2.0', '< 3.5.0'
gem 'propshaft'
gem 'puma', '~> 7.0'
gem 'rails', '~> 8.1.0'
gem 'rails', '~> 8.0'
gem 'thor', '~> 1.2'
gem 'dotenv'
@@ -13,7 +13,7 @@ gem 'haml-rails', '~>3.0'
gem 'pg', '~> 1.5'
gem 'pghero'
gem 'aws-sdk-core', require: false
gem 'aws-sdk-core', '< 3.216.0', require: false # TODO: https://github.com/mastodon/mastodon/pull/34173#issuecomment-2733378873
gem 'aws-sdk-s3', '~> 1.123', require: false
gem 'blurhash', '~> 0.1'
gem 'fog-core', '<= 2.6.0'
@@ -24,10 +24,10 @@ gem 'ruby-vips', '~> 2.2', require: false
gem 'active_model_serializers', '~> 0.10'
gem 'addressable', '~> 2.8'
gem 'bootsnap', require: false
gem 'bootsnap', '~> 1.18.0', require: false
gem 'browser'
gem 'charlock_holmes', '~> 0.7.7'
gem 'chewy'
gem 'chewy', '~> 7.3'
gem 'devise'
gem 'devise-two-factor'
@@ -40,7 +40,7 @@ gem 'net-ldap', '~> 0.18'
gem 'omniauth', '~> 2.0'
gem 'omniauth-cas', '~> 3.0.0.beta.1'
gem 'omniauth_openid_connect', '~> 0.8.0'
gem 'omniauth-rails_csrf_protection', '~> 2.0'
gem 'omniauth-rails_csrf_protection', '~> 1.0'
gem 'omniauth-saml', '~> 2.0'
gem 'color_diff', '~> 0.1'
@@ -55,7 +55,7 @@ gem 'hiredis-client'
gem 'htmlentities', '~> 4.3'
gem 'http', '~> 5.3.0'
gem 'http_accept_language', '~> 2.1'
gem 'httplog', '~> 1.8.0', require: false
gem 'httplog', '~> 1.7.0', require: false
gem 'i18n'
gem 'idn-ruby', require: 'idn'
gem 'inline_svg'
@@ -67,10 +67,11 @@ gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'mime-types', '~> 3.7.0', require: 'mime/types/columnar'
gem 'mutex_m'
gem 'nokogiri', '~> 1.15'
gem 'oj', '~> 3.14'
gem 'ox', '~> 2.14'
gem 'parslet'
gem 'premailer-rails'
gem 'public_suffix', '~> 7.0'
gem 'public_suffix', '~> 6.0'
gem 'pundit', '~> 2.3'
gem 'rack-attack', '~> 6.6'
gem 'rack-cors', require: 'rack/cors'
@@ -95,28 +96,27 @@ gem 'tzinfo-data', '~> 1.2023'
gem 'webauthn', '~> 3.0'
gem 'webpush', github: 'mastodon/webpush', ref: '9631ac63045cfabddacc69fc06e919b4c13eb913'
gem 'json'
gem 'json-ld'
gem 'json-ld-preloaded', '~> 3.2'
gem 'rdf-normalize', '~> 0.5'
gem 'prometheus_exporter', '~> 2.2', require: false
gem 'opentelemetry-api', '~> 1.8.0'
gem 'opentelemetry-api', '~> 1.7.0'
group :opentelemetry do
gem 'opentelemetry-exporter-otlp', '~> 0.32.0', require: false
gem 'opentelemetry-exporter-otlp', '~> 0.31.0', require: false
gem 'opentelemetry-instrumentation-active_job', '~> 0.10.0', require: false
gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.24.0', require: false
gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.24.0', require: false
gem 'opentelemetry-instrumentation-excon', '~> 0.28.0', require: false
gem 'opentelemetry-instrumentation-faraday', '~> 0.32.0', require: false
gem 'opentelemetry-instrumentation-http', '~> 0.29.0', require: false
gem 'opentelemetry-instrumentation-http_client', '~> 0.28.0', require: false
gem 'opentelemetry-instrumentation-net_http', '~> 0.28.0', require: false
gem 'opentelemetry-instrumentation-pg', '~> 0.35.0', require: false
gem 'opentelemetry-instrumentation-rack', '~> 0.30.0', require: false
gem 'opentelemetry-instrumentation-rails', '~> 0.40.0', require: false
gem 'opentelemetry-instrumentation-excon', '~> 0.26.0', require: false
gem 'opentelemetry-instrumentation-faraday', '~> 0.30.0', require: false
gem 'opentelemetry-instrumentation-http', '~> 0.27.0', require: false
gem 'opentelemetry-instrumentation-http_client', '~> 0.26.0', require: false
gem 'opentelemetry-instrumentation-net_http', '~> 0.26.0', require: false
gem 'opentelemetry-instrumentation-pg', '~> 0.32.0', require: false
gem 'opentelemetry-instrumentation-rack', '~> 0.29.0', require: false
gem 'opentelemetry-instrumentation-rails', '~> 0.39.0', require: false
gem 'opentelemetry-instrumentation-redis', '~> 0.28.0', require: false
gem 'opentelemetry-instrumentation-sidekiq', '~> 0.28.0', require: false
gem 'opentelemetry-sdk', '~> 1.4', require: false
@@ -129,13 +129,16 @@ group :test do
# Adds RSpec Error/Warning annotations to GitHub PRs on the Files tab
gem 'rspec-github', '~> 3.0', require: false
# RSpec helpers for email specs
gem 'email_spec'
# Extra RSpec extension methods and helpers for sidekiq
gem 'rspec-sidekiq', '~> 5.0'
# Browser integration testing
gem 'capybara', '~> 3.39'
gem 'capybara-playwright-driver'
gem 'playwright-ruby-client', '1.57.1', require: false # Pinning the exact version as it needs to be kept in sync with the installed npm package
gem 'playwright-ruby-client', '1.55.0', require: false # Pinning the exact version as it needs to be kept in sync with the installed npm package
# Used to reset the database between system tests
gem 'database_cleaner-active_record'
@@ -177,14 +180,14 @@ group :development do
# Enhanced error message pages for development
gem 'better_errors', '~> 2.9'
gem 'binding_of_caller'
gem 'binding_of_caller', '~> 1.0'
# Preview mail in the browser
gem 'letter_opener', '~> 1.8'
gem 'letter_opener_web', '~> 3.0'
# Security analysis CLI tools
gem 'brakeman', '~> 8.0', require: false
gem 'brakeman', '~> 7.0', require: false
gem 'bundler-audit', '~> 0.9', require: false
# Linter CLI for HAML files

File diff suppressed because it is too large Load Diff

View File

@@ -72,11 +72,10 @@ Mastodon is a **free, open-source social network server** based on [ActivityPub]
### Requirements
- **Ruby** 3.3+
- **Ruby** 3.2+
- **PostgreSQL** 14+
- **Redis** 7.0+
- **Node.js** 20+
- **FFmpeg** 5.1+
This repository includes deployment configurations for **Docker and docker-compose**, as well as for other environments like Heroku and Scalingo. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). A [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the main documentation.

1
Vagrantfile vendored
View File

@@ -29,6 +29,7 @@ sudo apt-get install \
libpq-dev \
libxml2-dev \
libxslt1-dev \
imagemagick \
nodejs \
redis-server \
redis-tools \

View File

@@ -53,9 +53,9 @@ class PublicStatusesIndex < Chewy::Index
}
index_scope ::Status.unscoped
.kept
.indexable
.includes(:media_attachments, :preloadable_poll, :tags, preview_cards_status: :preview_card)
.kept
.indexable
.includes(:media_attachments, :preloadable_poll, :tags, preview_cards_status: :preview_card)
root date_detection: false do
field(:id, type: 'long')

View File

@@ -1,8 +1,6 @@
# frozen_string_literal: true
class ActivityPub::CollectionsController < ActivityPub::BaseController
SUPPORTED_COLLECTIONS = %w(featured tags).freeze
vary_by -> { 'Signature' if authorized_fetch_mode? }
before_action :require_account_signature!, if: :authorized_fetch_mode?

View File

@@ -1,29 +0,0 @@
# frozen_string_literal: true
class ActivityPub::FeatureAuthorizationsController < ActivityPub::BaseController
include Authorization
vary_by -> { 'Signature' if authorized_fetch_mode? }
before_action :require_account_signature!, if: :authorized_fetch_mode?
before_action :set_collection_item
def show
expires_in 30.seconds, public: true if public_fetch_mode?
render json: @collection_item, serializer: ActivityPub::FeatureAuthorizationSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
private
def pundit_user
signed_request_account
end
def set_collection_item
@collection_item = @account.collection_items.accepted.find(params[:id])
authorize @collection_item.collection, :show?
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end

View File

@@ -1,79 +0,0 @@
# frozen_string_literal: true
class ActivityPub::FeaturedCollectionsController < ApplicationController
include SignatureAuthentication
include Authorization
include AccountOwnedConcern
PER_PAGE = 5
vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' }
before_action :check_feature_enabled
before_action :require_account_signature!, if: -> { authorized_fetch_mode? }
before_action :set_collections
skip_around_action :set_locale
skip_before_action :require_functional!, unless: :limited_federation_mode?
def index
respond_to do |format|
format.json do
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
render json: collection_presenter,
serializer: ActivityPub::CollectionSerializer,
adapter: ActivityPub::Adapter,
content_type: 'application/activity+json'
end
end
end
private
def set_collections
authorize @account, :index_collections?
@collections = @account.collections
.includes(:accepted_collection_items)
.page(params[:page]).per(PER_PAGE)
rescue Mastodon::NotPermittedError
not_found
end
def page_requested?
params[:page].present?
end
def next_page_url
ap_account_featured_collections_url(@account, page: @collections.next_page) if @collections.respond_to?(:next_page)
end
def prev_page_url
ap_account_featured_collections_url(@account, page: @collections.prev_page) if @collections.respond_to?(:prev_page)
end
def collection_presenter
if page_requested?
ActivityPub::CollectionPresenter.new(
id: ap_account_featured_collections_url(@account, page: params.fetch(:page, 1)),
type: :unordered,
size: @account.collections.count,
items: @collections,
part_of: ap_account_featured_collections_url(@account),
next: next_page_url,
prev: prev_page_url
)
else
ActivityPub::CollectionPresenter.new(
id: ap_account_featured_collections_url(@account),
type: :unordered,
size: @account.collections.count,
first: ap_account_featured_collections_url(@account, page: 1)
)
end
end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
end

View File

@@ -26,9 +26,9 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
end
def unknown_affected_account?
json = JSON.parse(body)
json = Oj.load(body, mode: :strict)
json.is_a?(Hash) && %w(Delete Update).include?(json['type']) && json['actor'].present? && json['actor'] == value_or_id(json['object']) && !Account.exists?(uri: json['actor'])
rescue JSON::ParserError
rescue Oj::ParseError
false
end
@@ -44,7 +44,7 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
return @body if defined?(@body)
@body = request.body.read
@body.presence&.force_encoding('UTF-8')
@body.force_encoding('UTF-8') if @body.present?
request.body.rewind if request.body.respond_to?(:rewind)

View File

@@ -1,22 +0,0 @@
# frozen_string_literal: true
module Admin
class CollectionsController < BaseController
before_action :set_account
before_action :set_collection, only: :show
def show
authorize @collection, :show?
end
private
def set_account
@account = Account.find(params[:account_id])
end
def set_collection
@collection = @account.collections.includes(accepted_collection_items: :account).find(params[:id])
end
end
end

View File

@@ -5,15 +5,6 @@ module Admin
def index
authorize :custom_emoji, :index?
# If filtering by local emojis, remove by_domain filter.
params.delete(:by_domain) if params[:local].present?
# If filtering by domain, ensure remote filter is set.
if params[:by_domain].present?
params.delete(:local)
params[:remote] = '1'
end
@custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page])
@form = Form::CustomEmojiBatch.new
end

View File

@@ -54,7 +54,7 @@ module Admin
end
# Allow transparently upgrading a domain block
if existing_domain_block.present? && existing_domain_block.domain == TagManager.instance.normalize_domain(@domain_block.domain)
if existing_domain_block.present? && existing_domain_block.domain == TagManager.instance.normalize_domain(@domain_block.domain.strip)
@domain_block = existing_domain_block
@domain_block.assign_attributes(resource_params)
end

View File

@@ -5,8 +5,8 @@ class Admin::Fasp::Debug::CallbacksController < Admin::BaseController
authorize [:admin, :fasp, :provider], :update?
@callbacks = Fasp::DebugCallback
.includes(:fasp_provider)
.order(created_at: :desc)
.includes(:fasp_provider)
.order(created_at: :desc)
end
def destroy

View File

@@ -34,11 +34,8 @@ class Admin::Instances::ModerationNotesController < Admin::BaseController
end
def set_instance
@instance = Instance.find_or_initialize_by(domain: normalized_domain)
end
def normalized_domain
TagManager.instance.normalize_domain(params[:instance_id])
domain = params[:instance_id]&.strip
@instance = Instance.find_or_initialize_by(domain: TagManager.instance.normalize_domain(domain))
end
def set_instance_note

View File

@@ -55,11 +55,8 @@ module Admin
private
def set_instance
@instance = Instance.find_or_initialize_by(domain: normalized_domain)
end
def normalized_domain
TagManager.instance.normalize_domain(params[:id])
domain = params[:id]&.strip
@instance = Instance.find_or_initialize_by(domain: TagManager.instance.normalize_domain(domain))
end
def set_instances

View File

@@ -13,7 +13,7 @@ class Admin::Reports::ActionsController < Admin::BaseController
case action_from_button
when 'delete', 'mark_as_sensitive'
Admin::ModerationAction.new(moderation_action_params).save!
Admin::StatusBatchAction.new(status_batch_action_params).save!
when 'silence', 'suspend'
Admin::AccountAction.new(account_action_params).save!
else
@@ -25,8 +25,9 @@ class Admin::Reports::ActionsController < Admin::BaseController
private
def moderation_action_params
def status_batch_action_params
shared_params
.merge(status_ids: @report.status_ids)
end
def account_action_params

View File

@@ -50,7 +50,7 @@ module Admin
private
def filtered_reports
ReportFilter.new(filter_params).results.order(id: :desc).includes(:account, :target_account, :collections)
ReportFilter.new(filter_params).results.order(id: :desc).includes(:account, :target_account)
end
def filter_params
@@ -58,7 +58,7 @@ module Admin
end
def set_report
@report = Report.includes(collections: :accepted_collection_items).find(params[:id])
@report = Report.find(params[:id])
end
end
end

View File

@@ -62,7 +62,7 @@ module Admin
def resource_params
params
.expect(user_role: [:name, :color, :highlighted, :position, :require_2fa, permissions_as_keys: []])
.expect(user_role: [:name, :color, :highlighted, :position, permissions_as_keys: []])
end
end
end

View File

@@ -9,7 +9,7 @@ module Admin
@site_upload.destroy!
redirect_back_or_to admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
redirect_back fallback_location: admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
end
private

View File

@@ -62,11 +62,7 @@ module Admin
end
def set_statuses
@statuses = Admin::StatusFilter.new(@account, filter_params).results.preload(*preload_columns, reblog: [:account, *preload_columns]).page(params[:page]).per(PER_PAGE)
end
def preload_columns
[:application, :preloadable_poll, :media_attachments, active_mentions: :account]
@statuses = Admin::StatusFilter.new(@account, filter_params).results.preload(:application, :preloadable_poll, :media_attachments, active_mentions: :account, reblog: [:account, :application, :preloadable_poll, :media_attachments, active_mentions: :account]).page(params[:page]).per(PER_PAGE)
end
def filter_params
@@ -82,6 +78,8 @@ module Admin
'report'
elsif params[:remove_from_report]
'remove_from_report'
elsif params[:delete]
'delete'
end
end
end

View File

@@ -1,26 +0,0 @@
# frozen_string_literal: true
class Api::V1::Accounts::EmailSubscriptionsController < Api::BaseController
before_action :set_account
before_action :require_feature_enabled!
before_action :require_account_permissions!
def create
@account.email_subscriptions.create!(email: params[:email], locale: I18n.locale)
render_empty
end
private
def set_account
@account = Account.local.find(params[:account_id])
end
def require_feature_enabled!
head 404 unless Mastodon::Feature.email_subscriptions_enabled?
end
def require_account_permissions!
head 404 if @account.unavailable? || !@account.user_can?(:manage_email_subscriptions) || !@account.user_email_subscriptions_enabled?
end
end

View File

@@ -9,9 +9,9 @@ class Api::V1::Accounts::NotesController < Api::BaseController
def create
if params[:comment].blank?
current_account.account_notes.find_by(target_account: @account)&.destroy
AccountNote.find_by(account: current_account, target_account: @account)&.destroy
else
@note = current_account.account_notes.find_or_initialize_by(target_account: @account)
@note = AccountNote.find_or_initialize_by(account: current_account, target_account: @account)
@note.comment = params[:comment]
@note.save! if @note.changed?
end

View File

@@ -38,7 +38,7 @@ class Api::V1::AccountsController < Api::BaseController
headers.merge!(response.headers)
self.response_body = response.body.to_json
self.response_body = Oj.dump(response.body)
self.status = response.status
rescue ActiveRecord::RecordInvalid => e
render json: ValidationErrorFormatter.new(e, 'account.username': :username, 'invite_request.text': :reason).as_json, status: 422

View File

@@ -1,12 +1,10 @@
# frozen_string_literal: true
class Api::V1::AnnualReportsController < Api::BaseController
include AsyncRefreshesConcern
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, except: [:read, :generate]
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:read, :generate]
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, only: :index
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, except: :index
before_action :require_user!
before_action :set_annual_report, only: [:show, :read]
before_action :set_annual_report, except: :index
def index
with_read_replica do
@@ -30,28 +28,6 @@ class Api::V1::AnnualReportsController < Api::BaseController
relationships: @relationships
end
def state
render json: { state: report_state }
end
def generate
return render_empty unless year == AnnualReport.current_campaign
return render_empty if GeneratedAnnualReport.exists?(account_id: current_account.id, year: year)
async_refresh = AsyncRefresh.new(refresh_key)
if async_refresh.running?
add_async_refresh_header(async_refresh, retry_seconds: 2)
return head 202
end
add_async_refresh_header(AsyncRefresh.create(refresh_key), retry_seconds: 2)
GenerateAnnualReportWorker.perform_async(current_account.id, year)
head 202
end
def read
@annual_report.view!
render_empty
@@ -59,21 +35,7 @@ class Api::V1::AnnualReportsController < Api::BaseController
private
def report_state
AnnualReport.new(current_account, year).state do |async_refresh|
add_async_refresh_header(async_refresh, retry_seconds: 2)
end
end
def refresh_key
"wrapstodon:#{current_account.id}:#{year}"
end
def year
params[:id]&.to_i
end
def set_annual_report
@annual_report = GeneratedAnnualReport.find_by!(account_id: current_account.id, year: year)
@annual_report = GeneratedAnnualReport.find_by!(account_id: current_account.id, year: params[:id])
end
end

View File

@@ -18,14 +18,14 @@ class Api::V1::BlocksController < Api::BaseController
def paginated_blocks
@paginated_blocks ||= Block.eager_load(target_account: [:account_stat, :user])
.joins(:target_account)
.merge(Account.without_suspended)
.where(account: current_account)
.paginate_by_max_id(
limit_param(DEFAULT_ACCOUNTS_LIMIT),
params[:max_id],
params[:since_id]
)
.joins(:target_account)
.merge(Account.without_suspended)
.where(account: current_account)
.paginate_by_max_id(
limit_param(DEFAULT_ACCOUNTS_LIMIT),
params[:max_id],
params[:since_id]
)
end
def next_path

View File

@@ -37,20 +37,20 @@ class Api::V1::ConversationsController < Api::BaseController
def paginated_conversations
AccountConversation.where(account: current_account)
.includes(
account: [:account_stat, user: :role],
last_status: [
:media_attachments,
:status_stat,
:tags,
{
preview_cards_status: { preview_card: { author_account: [:account_stat, user: :role] } },
active_mentions: :account,
account: [:account_stat, user: :role],
},
]
)
.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
.includes(
account: [:account_stat, user: :role],
last_status: [
:media_attachments,
:status_stat,
:tags,
{
preview_cards_status: { preview_card: { author_account: [:account_stat, user: :role] } },
active_mentions: :account,
account: [:account_stat, user: :role],
},
]
)
.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
end
def next_path

View File

@@ -1,86 +0,0 @@
# frozen_string_literal: true
class Api::V1::DonationCampaignsController < Api::BaseController
before_action :require_user!
STOPLIGHT_COOL_OFF_TIME = 60
STOPLIGHT_FAILURE_THRESHOLD = 10
def index
return head 204 if api_url.blank?
json = from_cache
return render json: json if json.present?
campaign = fetch_campaign
return head 204 if campaign.nil?
save_to_cache!(campaign)
render json: campaign
end
private
def api_url
Rails.configuration.x.donation_campaigns.api_url
end
def seed
@seed ||= Random.new(current_account.id).rand(100)
end
def from_cache
key = Rails.cache.read(request_key, raw: true)
return if key.blank?
campaign = Rails.cache.read("donation_campaign:#{key}", raw: true)
JSON.parse(campaign) if campaign.present?
end
def save_to_cache!(campaign)
return if campaign.blank?
Rails.cache.write_multi(
{
request_key => campaign_key(campaign),
"donation_campaign:#{campaign_key(campaign)}" => campaign.to_json,
},
expires_in: 1.hour,
raw: true
)
end
def fetch_campaign
stoplight_wrapper.run do
url = Addressable::URI.parse(api_url)
url.query_values = { platform: 'web', seed: seed, locale: locale, environment: Rails.configuration.x.donation_campaigns.environment }.compact
Request.new(:get, url.to_s).perform do |res|
return JSON.parse(res.body_with_limit) if res.code == 200
end
end
rescue *Mastodon::HTTP_CONNECTION_ERRORS, JSON::ParserError
nil
end
def stoplight_wrapper
Stoplight(
'donation_campaigns',
cool_off_time: STOPLIGHT_COOL_OFF_TIME,
threshold: STOPLIGHT_FAILURE_THRESHOLD
)
end
def request_key
"donation_campaign_request:#{seed}:#{locale}"
end
def campaign_key(campaign)
"#{campaign['id']}:#{campaign['locale']}"
end
def locale
I18n.locale.to_s
end
end

View File

@@ -1,15 +0,0 @@
# frozen_string_literal: true
class Api::V1::Instances::TermsOfServiceController < Api::V1::Instances::BaseController
before_action :cache_even_if_authenticated!
def index
@terms_of_service = TermsOfService.current || raise(ActiveRecord::RecordNotFound)
render json: @terms_of_service, serializer: REST::TermsOfServiceSerializer
end
def show
@terms_of_service = TermsOfService.published.find_by!(effective_date: params[:date])
render json: @terms_of_service, serializer: REST::TermsOfServiceSerializer
end
end

View File

@@ -0,0 +1,23 @@
# frozen_string_literal: true
class Api::V1::Instances::TermsOfServicesController < Api::V1::Instances::BaseController
before_action :set_terms_of_service
def show
cache_even_if_authenticated!
render json: @terms_of_service, serializer: REST::TermsOfServiceSerializer
end
private
def set_terms_of_service
@terms_of_service = begin
if params[:date].present?
TermsOfService.published.find_by!(effective_date: params[:date])
else
TermsOfService.current
end
end
not_found if @terms_of_service.nil?
end
end

View File

@@ -32,7 +32,13 @@ class Api::V1::MarkersController < Api::BaseController
private
def serialize_map(map)
map.transform_values { |value| ActiveModelSerializers::SerializableResource.new(value, serializer: REST::MarkerSerializer) }
serialized = {}
map.each_pair do |key, value|
serialized[key] = ActiveModelSerializers::SerializableResource.new(value, serializer: REST::MarkerSerializer).as_json
end
Oj.dump(serialized)
end
def resource_params

View File

@@ -18,14 +18,14 @@ class Api::V1::MutesController < Api::BaseController
def paginated_mutes
@paginated_mutes ||= Mute.eager_load(target_account: [:account_stat, :user])
.joins(:target_account)
.merge(Account.without_suspended)
.where(account: current_account)
.paginate_by_max_id(
limit_param(DEFAULT_ACCOUNTS_LIMIT),
params[:max_id],
params[:since_id]
)
.joins(:target_account)
.merge(Account.without_suspended)
.where(account: current_account)
.paginate_by_max_id(
limit_param(DEFAULT_ACCOUNTS_LIMIT),
params[:max_id],
params[:since_id]
)
end
def next_path

View File

@@ -47,6 +47,10 @@ class Api::V1::Peers::SearchController < Api::BaseController
end
def normalized_domain
TagManager.instance.normalize_domain(params[:q])
TagManager.instance.normalize_domain(query_value)
end
def query_value
params[:q].strip
end
end

View File

@@ -1,43 +0,0 @@
# frozen_string_literal: true
class Api::V1::ProfilesController < Api::BaseController
before_action -> { doorkeeper_authorize! :profile, :read, :'read:accounts' }, except: [:update]
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:update]
before_action :require_user!
def show
@account = current_account
render json: @account, serializer: REST::ProfileSerializer
end
def update
@account = current_account
UpdateAccountService.new.call(@account, account_params, raise_error: true)
ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
render json: @account, serializer: REST::ProfileSerializer
rescue ActiveRecord::RecordInvalid => e
render json: ValidationErrorFormatter.new(e).as_json, status: 422
end
def account_params
params.permit(
:display_name,
:note,
:avatar,
:avatar_description,
:header,
:header_description,
:locked,
:bot,
:discoverable,
:hide_collections,
:indexable,
:show_media,
:show_media_replies,
:show_featured,
attribution_domains: [],
fields_attributes: [:name, :value]
)
end
end

View File

@@ -23,10 +23,6 @@ class Api::V1::ReportsController < Api::BaseController
end
def report_params
if Mastodon::Feature.collections_enabled?
params.permit(:account_id, :comment, :category, :forward, forward_to_domains: [], status_ids: [], collection_ids: [], rule_ids: [])
else
params.permit(:account_id, :comment, :category, :forward, forward_to_domains: [], status_ids: [], rule_ids: [])
end
params.permit(:account_id, :comment, :category, :forward, forward_to_domains: [], status_ids: [], rule_ids: [])
end
end

View File

@@ -26,20 +26,20 @@ class Api::V1::Statuses::PinsController < Api::V1::Statuses::BaseController
def distribute_add_activity!
json = ActiveModelSerializers::SerializableResource.new(
@status,
serializer: ActivityPub::AddNoteSerializer,
serializer: ActivityPub::AddSerializer,
adapter: ActivityPub::Adapter
).as_json
ActivityPub::RawDistributionWorker.perform_async(json.to_json, current_account.id)
ActivityPub::RawDistributionWorker.perform_async(Oj.dump(json), current_account.id)
end
def distribute_remove_activity!
json = ActiveModelSerializers::SerializableResource.new(
@status,
serializer: ActivityPub::RemoveNoteSerializer,
serializer: ActivityPub::RemoveSerializer,
adapter: ActivityPub::Adapter
).as_json
ActivityPub::RawDistributionWorker.perform_async(json.to_json, current_account.id)
ActivityPub::RawDistributionWorker.perform_async(Oj.dump(json), current_account.id)
end
end

View File

@@ -41,8 +41,8 @@ class Api::V1::Statuses::QuotesController < Api::V1::Statuses::BaseController
if current_account&.id != @status.account_id
domains = @statuses.filter_map(&:account_domain).uniq
account_ids = @statuses.map(&:account_id).uniq
current_account&.preload_relations!(account_ids, domains)
@statuses.reject! { |status| StatusFilter.new(status, current_account).filtered? }
relations = current_account&.relations_map(account_ids, domains) || {}
@statuses.reject! { |status| StatusFilter.new(status, current_account, relations).filtered? }
end
end

View File

@@ -130,13 +130,10 @@ class Api::V1::StatusesController < Api::BaseController
@status = Status.where(account: current_account).find(params[:id])
authorize @status, :destroy?
# JSON is generated before `discard_with_reblogs` in order to have the proper URL
# for media attachments, as it would otherwise redirect to the media proxy
json = render_to_body json: @status, serializer: REST::StatusSerializer, source_requested: true
@status.discard_with_reblogs
StatusPin.find_by(status: @status)&.destroy
@status.account.statuses_count = @status.account.statuses_count - 1
json = render_to_body json: @status, serializer: REST::StatusSerializer, source_requested: true
RemovalWorker.perform_async(@status.id, { 'redraft' => !truthy_param?(:delete_media) })

View File

@@ -39,6 +39,6 @@ class Api::V1::TagsController < Api::BaseController
def set_or_create_tag
return not_found unless Tag::HASHTAG_NAME_RE.match?(params[:id])
@tag = Tag.find_normalized(params[:id]) || Tag.new(name: params[:id], display_name: params[:id])
@tag = Tag.find_normalized(params[:id]) || Tag.new(name: Tag.normalize(params[:id]), display_name: params[:id])
end
end

View File

@@ -1,62 +0,0 @@
# frozen_string_literal: true
class Api::V1Alpha::CollectionItemsController < Api::BaseController
include Authorization
before_action :check_feature_enabled
before_action -> { doorkeeper_authorize! :write, :'write:collections' }
before_action :require_user!
before_action :set_collection
before_action :set_account, only: [:create]
before_action :set_collection_item, only: [:destroy, :revoke]
after_action :verify_authorized
def create
authorize @collection, :update?
authorize @account, :feature?
@item = AddAccountToCollectionService.new.call(@collection, @account)
render json: @item, serializer: REST::CollectionItemSerializer, adapter: :json
end
def destroy
authorize @collection, :update?
DeleteCollectionItemService.new.call(@collection_item)
head 200
end
def revoke
authorize @collection_item, :revoke?
RevokeCollectionItemService.new.call(@collection_item)
head 200
end
private
def set_collection
@collection = Collection.find(params[:collection_id])
end
def set_account
return render(json: { error: '`account_id` parameter is missing' }, status: 422) if params[:account_id].blank?
@account = Account.find(params[:account_id])
end
def set_collection_item
@collection_item = @collection.collection_items.find(params[:id])
end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
end

View File

@@ -1,117 +0,0 @@
# frozen_string_literal: true
class Api::V1Alpha::CollectionsController < Api::BaseController
include Authorization
DEFAULT_COLLECTIONS_LIMIT = 40
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
render json: { error: ValidationErrorFormatter.new(e).as_json }, status: 422
end
before_action :check_feature_enabled
before_action -> { authorize_if_got_token! :read, :'read:collections' }, only: [:index, :show]
before_action -> { doorkeeper_authorize! :write, :'write:collections' }, only: [:create, :update, :destroy]
before_action :require_user!, only: [:create, :update, :destroy]
before_action :set_account, only: [:index]
before_action :set_collections, only: [:index]
before_action :set_collection, only: [:show, :update, :destroy]
after_action :insert_pagination_headers, only: [:index]
after_action :verify_authorized
def index
cache_if_unauthenticated!
authorize @account, :index_collections?
render json: @collections, each_serializer: REST::CollectionSerializer, adapter: :json
rescue Mastodon::NotPermittedError
render json: { collections: [] }
end
def show
cache_if_unauthenticated!
authorize @collection, :show?
render json: @collection, serializer: REST::CollectionWithAccountsSerializer
end
def create
authorize Collection, :create?
@collection = CreateCollectionService.new.call(collection_creation_params, current_user.account)
render json: @collection, serializer: REST::CollectionSerializer, adapter: :json
end
def update
authorize @collection, :update?
UpdateCollectionService.new.call(@collection, collection_update_params)
render json: @collection, serializer: REST::CollectionSerializer, adapter: :json
end
def destroy
authorize @collection, :destroy?
DeleteCollectionService.new.call(@collection)
head 200
end
private
def set_account
@account = Account.find(params[:account_id])
end
def set_collections
@collections = @account.collections
.with_tag
.order(created_at: :desc)
.offset(offset_param)
.limit(limit_param(DEFAULT_COLLECTIONS_LIMIT))
@collections = @collections.discoverable unless @account == current_account
end
def set_collection
@collection = Collection.find(params[:id])
end
def collection_creation_params
params.permit(:name, :description, :language, :sensitive, :discoverable, :tag_name, account_ids: [])
end
def collection_update_params
params.permit(:name, :description, :language, :sensitive, :discoverable, :tag_name)
end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
def next_path
return unless records_continue?
api_v1_alpha_account_collections_url(@account, pagination_params(offset: offset_param + limit_param(DEFAULT_COLLECTIONS_LIMIT)))
end
def prev_path
return if offset_param.zero?
api_v1_alpha_account_collections_url(@account, pagination_params(offset: offset_param - limit_param(DEFAULT_COLLECTIONS_LIMIT)))
end
def records_continue?
((offset_param * limit_param(DEFAULT_COLLECTIONS_LIMIT)) + @collections.size) < @account.collections.size
end
def offset_param
params[:offset].to_i
end
end

View File

@@ -9,21 +9,39 @@ class ApplicationController < ActionController::Base
include UserTrackingConcern
include SessionTrackingConcern
include CacheConcern
include ErrorResponses
include PreloadingConcern
include DomainControlHelper
include ThemingConcern
include DatabaseHelper
include AuthorizedFetchHelper
include SelfDestructHelper
helper_method :current_account
helper_method :current_session
helper_method :current_flavour
helper_method :current_skin
helper_method :current_theme
helper_method :single_user_mode?
helper_method :use_seamless_external_login?
helper_method :sso_account_settings
helper_method :limited_federation_mode?
helper_method :skip_csrf_meta_tags?
rescue_from ActionController::ParameterMissing, Paperclip::AdapterRegistry::NoHandlerError, with: :bad_request
rescue_from Mastodon::NotPermittedError, with: :forbidden
rescue_from ActionController::RoutingError, ActiveRecord::RecordNotFound, with: :not_found
rescue_from ActionController::UnknownFormat, with: :not_acceptable
rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_content
rescue_from Mastodon::RateLimitExceededError, with: :too_many_requests
rescue_from(*Mastodon::HTTP_CONNECTION_ERRORS, with: :internal_server_error)
rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight, ActiveRecord::SerializationFailure, with: :service_unavailable
rescue_from Seahorse::Client::NetworkingError do |e|
Rails.logger.warn "Storage server error: #{e}"
service_unavailable
end
before_action :check_self_destruct!
before_action :store_referrer, except: :raise_not_found, if: :devise_controller?
@@ -47,25 +65,19 @@ class ApplicationController < ActionController::Base
return if request.referer.blank?
redirect_uri = URI(request.referer)
return if redirect_uri.path.start_with?('/auth', '/settings/two_factor_authentication', '/settings/otp_authentication')
return if redirect_uri.path.start_with?('/auth')
stored_url = redirect_uri.to_s if redirect_uri.host == request.host && redirect_uri.port == request.port
store_location_for(:user, stored_url)
end
def mfa_setup_path(path_params = {})
settings_two_factor_authentication_methods_path(path_params)
end
def require_functional!
return if current_user.functional?
respond_to do |format|
format.any do
if current_user.missing_2fa?
redirect_to mfa_setup_path
elsif current_user.confirmed?
if current_user.confirmed?
redirect_to edit_user_registration_path
else
redirect_to auth_setup_path
@@ -77,8 +89,6 @@ class ApplicationController < ActionController::Base
render json: { error: 'Your login is missing a confirmed e-mail address' }, status: 403
elsif !current_user.approved?
render json: { error: 'Your login is currently pending approval' }, status: 403
elsif current_user.missing_2fa?
render json: { error: 'Your account requires two-factor authentication' }, status: 403
elsif !current_user.functional?
render json: { error: 'Your login is currently disabled' }, status: 403
end
@@ -104,6 +114,42 @@ class ApplicationController < ActionController::Base
ActiveModel::Type::Boolean.new.cast(params[key])
end
def forbidden
respond_with_error(403)
end
def not_found
respond_with_error(404)
end
def gone
respond_with_error(410)
end
def unprocessable_content
respond_with_error(422)
end
def not_acceptable
respond_with_error(406)
end
def bad_request
respond_with_error(400)
end
def internal_server_error
respond_with_error(500)
end
def service_unavailable
respond_with_error(503)
end
def too_many_requests
respond_with_error(429)
end
def single_user_mode?
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.without_internal.exists?
end
@@ -128,6 +174,13 @@ class ApplicationController < ActionController::Base
@current_session = SessionActivation.find_by(session_id: cookies.signed['_session_id']) if cookies.signed['_session_id'].present?
end
def respond_with_error(code)
respond_to do |format|
format.any { render "errors/#{code}", layout: 'error', status: code, formats: [:html] }
format.json { render json: { error: Rack::Utils::HTTP_STATUS_CODES[code] }, status: code }
end
end
def check_self_destruct!
return unless self_destruct?

View File

@@ -130,17 +130,12 @@ class Auth::RegistrationsController < Devise::RegistrationsController
end
def require_rules_acceptance!
return if @rules.empty? || validated_accept_token?
return if @rules.empty? || (session[:accept_token].present? && params[:accept] == session[:accept_token])
@accept_token = session[:accept_token] = SecureRandom.hex
@invite_code = invite_code
@rule_translations = @rules.map { |rule| rule.translation_for(I18n.locale) }
@invite_code = invite_code
render :rules
end
def validated_accept_token?
session[:accept_token].present? && params[:accept] == session[:accept_token]
set_locale { render :rules }
end
def is_flashing_format? # rubocop:disable Naming/PredicatePrefix

View File

@@ -1,24 +0,0 @@
# frozen_string_literal: true
class Auth::Sessions::SecurityKeyOptionsController < ApplicationController
skip_before_action :check_self_destruct!
skip_before_action :require_functional!
skip_before_action :update_user_sign_in
def show
user = User.find_by(id: session[:attempt_user_id])
if user&.webauthn_enabled?
options_for_get = WebAuthn::Credential.options_for_get(
allow: user.webauthn_credentials.pluck(:external_id),
user_verification: 'discouraged'
)
session[:webauthn_challenge] = options_for_get.challenge
render json: options_for_get, status: 200
else
render json: { error: t('webauthn_credentials.not_enabled') }, status: 401
end
end
end

View File

@@ -38,6 +38,23 @@ class Auth::SessionsController < Devise::SessionsController
flash.delete(:notice)
end
def webauthn_options
user = User.find_by(id: session[:attempt_user_id])
if user&.webauthn_enabled?
options_for_get = WebAuthn::Credential.options_for_get(
allow: user.webauthn_credentials.pluck(:external_id),
user_verification: 'discouraged'
)
session[:webauthn_challenge] = options_for_get.challenge
render json: options_for_get, status: 200
else
render json: { error: t('webauthn_credentials.not_enabled') }, status: 401
end
end
protected
def find_user

View File

@@ -1,42 +0,0 @@
# frozen_string_literal: true
class CollectionItemsController < ApplicationController
include SignatureAuthentication
include Authorization
include AccountOwnedConcern
vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' }
before_action :check_feature_enabled
before_action :require_account_signature!, if: -> { authorized_fetch_mode? }
before_action :set_collection_item
skip_around_action :set_locale
skip_before_action :require_functional!, unless: :limited_federation_mode?
def show
respond_to do |format|
format.json do
expires_in(3.minutes, public: public_fetch_mode?)
render json: @collection_item,
serializer: ActivityPub::FeaturedItemSerializer,
adapter: ActivityPub::Adapter,
content_type: 'application/activity+json'
end
end
end
private
def set_collection_item
@collection_item = @account.curated_collection_items.find(params[:id])
authorize @collection_item.collection, :show?
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
end

View File

@@ -1,46 +0,0 @@
# frozen_string_literal: true
class CollectionsController < ApplicationController
include WebAppControllerConcern
include SignatureAuthentication
include Authorization
include AccountOwnedConcern
vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' }
before_action :check_feature_enabled
before_action :require_account_signature!, only: :show, if: -> { request.format == :json && authorized_fetch_mode? }
before_action :set_collection
skip_around_action :set_locale, if: -> { request.format == :json }
skip_before_action :require_functional!, only: :show, unless: :limited_federation_mode?
def show
respond_to do |format|
# TODO: format.html
format.json do
expires_in expiration_duration, public: true if public_fetch_mode?
render_with_cache json: @collection, content_type: 'application/activity+json', serializer: ActivityPub::FeaturedCollectionSerializer, adapter: ActivityPub::Adapter
end
end
end
private
def set_collection
@collection = @account.collections.find(params[:id])
authorize @collection, :show?
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
def expiration_duration
recently_updated = @collection.updated_at > 15.minutes.ago
recently_updated ? 30.seconds : 5.minutes
end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
end

View File

@@ -4,8 +4,10 @@ module AccountableConcern
extend ActiveSupport::Concern
def log_action(action, target)
current_account
.action_logs
.create(action:, target:)
Admin::ActionLog.create(
account: current_account,
action: action,
target: target
)
end
end

View File

@@ -6,9 +6,9 @@ module Api::InteractionPoliciesConcern
def quote_approval_policy
case status_params[:quote_approval_policy].presence || current_user.setting_default_quote_policy
when 'public'
InteractionPolicy::POLICY_FLAGS[:public] << 16
Status::QUOTE_APPROVAL_POLICY_FLAGS[:public] << 16
when 'followers'
InteractionPolicy::POLICY_FLAGS[:followers] << 16
Status::QUOTE_APPROVAL_POLICY_FLAGS[:followers] << 16
when 'nobody'
0
else

View File

@@ -42,7 +42,7 @@ module ChallengableConcern
end
def render_challenge
render 'auth/challenges/new', layout: params[:oauth] ? 'modal' : 'auth'
render 'auth/challenges/new', layout: 'auth'
end
def challenge_passed?

View File

@@ -1,68 +0,0 @@
# frozen_string_literal: true
module ErrorResponses
extend ActiveSupport::Concern
included do
rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_content
rescue_from ActionController::ParameterMissing, Paperclip::AdapterRegistry::NoHandlerError, with: :bad_request
rescue_from ActionController::RoutingError, ActiveRecord::RecordNotFound, with: :not_found
rescue_from ActionController::UnknownFormat, with: :not_acceptable
rescue_from Mastodon::NotPermittedError, with: :forbidden
rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight, ActiveRecord::SerializationFailure, with: :service_unavailable
rescue_from Mastodon::RateLimitExceededError, with: :too_many_requests
rescue_from(*Mastodon::HTTP_CONNECTION_ERRORS, with: :internal_server_error)
rescue_from Seahorse::Client::NetworkingError do |e|
Rails.logger.warn "Storage server error: #{e}"
service_unavailable
end
end
protected
def bad_request
respond_with_error(400)
end
def forbidden
respond_with_error(403)
end
def gone
respond_with_error(410)
end
def internal_server_error
respond_with_error(500)
end
def not_acceptable
respond_with_error(406)
end
def not_found
respond_with_error(404)
end
def service_unavailable
respond_with_error(503)
end
def too_many_requests
respond_with_error(429)
end
def unprocessable_content
respond_with_error(422)
end
private
def respond_with_error(code)
respond_to do |format|
format.any { render "errors/#{code}", layout: 'error', formats: [:html], status: code }
format.json { render json: { error: Rack::Utils::HTTP_STATUS_CODES[code] }, status: code }
end
end
end

View File

@@ -53,21 +53,19 @@ module SignatureVerification
raise Mastodon::SignatureVerificationError, 'Request not signed' unless signed_request?
keypair = keypair_from_key_id
actor = actor_from_key_id
raise Mastodon::SignatureVerificationError, "Public key not found for key #{signature_key_id}" if keypair.nil?
raise Mastodon::SignatureVerificationError, "Public key not found for key #{signature_key_id}" if actor.nil?
check_keypair_validity!(keypair)
return (@signed_request_actor = keypair.actor) if signed_request.verified?(keypair)
return (@signed_request_actor = actor) if signed_request.verified?(actor)
keypair = stoplight_wrapper.run { keypair_refresh_key!(keypair) }
actor = stoplight_wrapper.run { actor_refresh_key!(actor) }
raise Mastodon::SignatureVerificationError, "Could not refresh public key #{signature_key_id}" if keypair.nil?
raise Mastodon::SignatureVerificationError, "Could not refresh public key #{signature_key_id}" if actor.nil?
check_keypair_validity!(keypair)
return (@signed_request_actor = keypair.actor) if signed_request.verified?(keypair)
return (@signed_request_actor = actor) if signed_request.verified?(actor)
fail_with! "Verification failed for #{keypair.actor.to_log_human_identifier} #{keypair.actor.uri} #{keypair.uri}"
fail_with! "Verification failed for #{actor.to_log_human_identifier} #{actor.uri}"
rescue Mastodon::MalformedHeaderError => e
@signature_verification_failure_code = 400
fail_with! e.message
@@ -91,7 +89,7 @@ module SignatureVerification
@signed_request_actor = nil
end
def keypair_from_key_id
def actor_from_key_id
key_id = signed_request.key_id
domain = key_id.start_with?('acct:') ? key_id.split('@').last : key_id
@@ -103,10 +101,9 @@ module SignatureVerification
if key_id.start_with?('acct:')
stoplight_wrapper.run { ResolveAccountService.new.call(key_id.delete_prefix('acct:'), suppress_errors: false) }
elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
keypair = Keypair.from_keyid(key_id)
return keypair if keypair.present?
stoplight_wrapper.run { ActivityPub::FetchRemoteKeyService.new.call(key_id, suppress_errors: false) }
account = ActivityPub::TagManager.instance.uri_to_actor(key_id)
account ||= stoplight_wrapper.run { ActivityPub::FetchRemoteKeyService.new.call(key_id, suppress_errors: false) }
account
end
rescue Mastodon::PrivateNetworkAddressError => e
raise Mastodon::SignatureVerificationError, "Requests to private network addresses are disallowed (tried to query #{e.host})"
@@ -123,20 +120,14 @@ module SignatureVerification
)
end
def keypair_refresh_key!(keypair)
# TODO: this currently only is concerned with refreshing the actor and returning the legacy key, this needs to be reworked
return if keypair.actor.local? || !keypair.actor.activitypub?
return keypair.actor.refresh! if keypair.actor.respond_to?(:refresh!) && keypair.actor.possibly_stale?
def actor_refresh_key!(actor)
return if actor.local? || !actor.activitypub?
return actor.refresh! if actor.respond_to?(:refresh!) && actor.possibly_stale?
Keypair.from_legacy_account(ActivityPub::FetchRemoteActorService.new.call(keypair.actor.uri, only_key: true, suppress_errors: false))
ActivityPub::FetchRemoteActorService.new.call(actor.uri, only_key: true, suppress_errors: false)
rescue Mastodon::PrivateNetworkAddressError => e
raise Mastodon::SignatureVerificationError, "Requests to private network addresses are disallowed (tried to query #{e.host})"
rescue Mastodon::HostValidationError, ActivityPub::FetchRemoteActorService::Error, Webfinger::Error => e
raise Mastodon::SignatureVerificationError, e.message
end
def check_keypair_validity!(keypair)
raise Mastodon::SignatureVerification, "Key #{signature_key_id} is revoked" if keypair.revoked?
raise Mastodon::SignatureVerification, "Key #{signature_key_id} has expired" if keypair.expired?
end
end

View File

@@ -0,0 +1,24 @@
# frozen_string_literal: true
module ThemingConcern
extend ActiveSupport::Concern
private
def current_flavour
@current_flavour ||= [current_user&.setting_flavour, Setting.flavour, 'glitch', 'vanilla'].find { |flavour| Themes.instance.flavours.include?(flavour) }
end
def current_skin
@current_skin ||= begin
skins = Themes.instance.skins_for(current_flavour)
[current_user&.setting_skin, Setting.skin, 'system', 'default'].find { |skin| skins.include?(skin) }
end
end
def current_theme
# NOTE: this is slightly different from upstream, as it's a derived value used
# for the sole purpose of pointing to the appropriate stylesheet pack
[current_flavour, current_skin]
end
end

Some files were not shown because too many files have changed in this diff Show More