about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS.md311
-rw-r--r--Aptfile17
-rw-r--r--app/controllers/api/base_controller.rb4
-rw-r--r--app/controllers/application_controller.rb4
-rw-r--r--app/controllers/auth/sessions_controller.rb15
-rw-r--r--app/controllers/oauth/authorizations_controller.rb14
-rw-r--r--app/helpers/settings_helper.rb1
-rw-r--r--app/javascript/mastodon/locales/ru.json8
-rw-r--r--app/javascript/styles/mastodon/accessibility.scss2
-rw-r--r--app/javascript/styles/mastodon/components.scss4
-rw-r--r--app/javascript/styles/mastodon/reset.scss5
-rw-r--r--app/services/fetch_link_card_service.rb18
-rw-r--r--app/services/fetch_oembed_service.rb2
-rw-r--r--app/views/accounts/_header.html.haml5
-rw-r--r--app/views/layouts/modal.html.haml2
-rwxr-xr-xbin/tootctl1
-rw-r--r--config/application.rb1
-rw-r--r--config/initializers/devise.rb2
-rw-r--r--config/initializers/session_store.rb2
-rw-r--r--config/locales/ru.yml22
-rw-r--r--config/locales/simple_form.ru.yml2
-rw-r--r--lib/mastodon/accounts_cli.rb139
-rw-r--r--lib/mastodon/cli_helper.rb1
-rw-r--r--lib/tasks/repo.rake30
-rw-r--r--spec/controllers/auth/sessions_controller_spec.rb7
-rw-r--r--spec/controllers/oauth/authorizations_controller_spec.rb32
-rw-r--r--spec/rails_helper.rb1
27 files changed, 505 insertions, 147 deletions
diff --git a/AUTHORS.md b/AUTHORS.md
index c4bbb6014..abcc24384 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -3,76 +3,85 @@ and provided thanks to the work of the following contributors:
 
 * [Gargron](https://github.com/Gargron)
 * [ykzts](https://github.com/ykzts)
-* [mjankowski](https://github.com/mjankowski)
 * [akihikodaki](https://github.com/akihikodaki)
+* [mjankowski](https://github.com/mjankowski)
 * [unarist](https://github.com/unarist)
-* [yiskah](https://github.com/yiskah)
+* [ThibG](https://github.com/ThibG)
 * [m4sk1n](https://github.com/m4sk1n)
+* [yiskah](https://github.com/yiskah)
 * [nolanlawson](https://github.com/nolanlawson)
 * [sorin-davidoi](https://github.com/sorin-davidoi)
 * [abcang](https://github.com/abcang)
-* [ThibG](https://github.com/ThibG)
 * [lynlynlynx](https://github.com/lynlynlynx)
 * [alpaca-tc](https://github.com/alpaca-tc)
 * [nclm](https://github.com/nclm)
 * [ineffyble](https://github.com/ineffyble)
+* [renatolond](https://github.com/renatolond)
 * [jeroenpraat](https://github.com/jeroenpraat)
 * [blackle](https://github.com/blackle)
 * [Quent-in](https://github.com/Quent-in)
 * [JantsoP](https://github.com/JantsoP)
 * [nullkal](https://github.com/nullkal)
 * [yookoala](https://github.com/yookoala)
+* [mayaeh](https://github.com/mayaeh)
 * [ysksn](https://github.com/ysksn)
+* [shuheiktgw](https://github.com/shuheiktgw)
 * [ashfurrow](https://github.com/ashfurrow)
-* [eramdam](https://github.com/eramdam)
-* [mayaeh](https://github.com/mayaeh)
 * [zunda](https://github.com/zunda)
-* [ticky](https://github.com/ticky)
+* [eramdam](https://github.com/eramdam)
+* [Kjwon15](https://github.com/Kjwon15)
 * [masarakki](https://github.com/masarakki)
+* [ticky](https://github.com/ticky)
+* [Quenty31](https://github.com/Quenty31)
+* [danhunsaker](https://github.com/danhunsaker)
+* [ThisIsMissEm](https://github.com/ThisIsMissEm)
+* [hcmiya](https://github.com/hcmiya)
+* [stephenburgess8](https://github.com/stephenburgess8)
 * [Wonderfall](https://github.com/Wonderfall)
+* [takayamaki](https://github.com/takayamaki)
 * [matteoaquila](https://github.com/matteoaquila)
 * [rkarabut](https://github.com/rkarabut)
-* [stephenburgess8](https://github.com/stephenburgess8)
-* [Kjwon15](https://github.com/Kjwon15)
 * [Artoria2e5](https://github.com/Artoria2e5)
 * [yukimochi](https://github.com/yukimochi)
 * [marrus-sh](https://github.com/marrus-sh)
 * [krainboltgreene](https://github.com/krainboltgreene)
-* [renatolond](https://github.com/renatolond)
-* [BoFFire](https://github.com/BoFFire)
-* [clworld](https://github.com/clworld)
-* [danhunsaker](https://github.com/danhunsaker)
 * [patf](https://github.com/patf)
-* [Quenty31](https://github.com/Quenty31)
-* [MitarashiDango](https://github.com/MitarashiDango)
 * [Aldarone](https://github.com/Aldarone)
+* [BoFFire](https://github.com/BoFFire)
+* [clworld](https://github.com/clworld)
+* [dracos](https://github.com/dracos)
+* [SerCom_KC](mailto:sercom-kc@users.noreply.github.com)
+* [Sylvhem](https://github.com/Sylvhem)
+* [nightpool](https://github.com/nightpool)
+* [MasterGroosha](https://github.com/MasterGroosha)
 * [JeanGauthier](https://github.com/JeanGauthier)
 * [kschaper](https://github.com/kschaper)
-* [takayamaki](https://github.com/takayamaki)
+* [mabkenar](https://github.com/mabkenar)
+* [MitarashiDango](mailto:mitarashidango@users.noreply.github.com)
+* [beatrix-bitrot](https://github.com/beatrix-bitrot)
 * [adbelle](https://github.com/adbelle)
 * [evanminto](https://github.com/evanminto)
-* [mabkenar](https://github.com/mabkenar)
 * [MightyPork](https://github.com/MightyPork)
-* [beatrix-bitrot](https://github.com/beatrix-bitrot)
 * [yhirano55](https://github.com/yhirano55)
 * [camponez](https://github.com/camponez)
+* [MaciekBaron](https://github.com/MaciekBaron)
+* [SerCom-KC](https://github.com/SerCom-KC)
 * [aschmitz](https://github.com/aschmitz)
 * [fpiesche](https://github.com/fpiesche)
 * [gandaro](https://github.com/gandaro)
 * [johnsudaar](https://github.com/johnsudaar)
 * [trebmuh](https://github.com/trebmuh)
-* [Sylvhem](https://github.com/Sylvhem)
+* [Rakib Hasan](mailto:rmhasan@gmail.com)
 * [lindwurm](https://github.com/lindwurm)
+* [victorhck](mailto:victorhck@geeko.site)
 * [voidsatisfaction](https://github.com/voidsatisfaction)
-* [neetshin](https://github.com/neetshin)
 * [valentin2105](https://github.com/valentin2105)
+* [devkral](https://github.com/devkral)
 * [hikari-no-yume](https://github.com/hikari-no-yume)
-* [Angristan](https://github.com/Angristan)
+* [angristan](https://github.com/angristan)
 * [seefood](https://github.com/seefood)
 * [jackjennings](https://github.com/jackjennings)
-* [hcmiya](https://github.com/hcmiya)
-* [nightpool](https://github.com/nightpool)
-* [salvadorpla](https://github.com/salvadorpla)
+* [spla](mailto:spla@mastodont.cat)
 * [expenses](https://github.com/expenses)
 * [walf443](https://github.com/walf443)
 * [JoelQ](https://github.com/JoelQ)
@@ -85,65 +94,75 @@ and provided thanks to the work of the following contributors:
 * [victorhck](https://github.com/victorhck)
 * [puckipedia](https://github.com/puckipedia)
 * [contraexemplo](https://github.com/contraexemplo)
+* [hugogameiro](https://github.com/hugogameiro)
 * [kazu9su](https://github.com/kazu9su)
 * [Komic](https://github.com/Komic)
 * [diomed](https://github.com/diomed)
+* [ariasuni](https://github.com/ariasuni)
+* [Neetshin](mailto:neetshin@neetsh.in)
 * [rainyday](https://github.com/rainyday)
+* [ProgVal](https://github.com/ProgVal)
+* [yuntan](https://github.com/yuntan)
+* [goofy-bz](mailto:goofy@babelzilla.org)
 * [kadiix](https://github.com/kadiix)
 * [kodacs](https://github.com/kodacs)
-* [ProgVal](https://github.com/ProgVal)
+* [fvh-P](https://github.com/fvh-P)
+* [rtucker](https://github.com/rtucker)
+* [KScl](https://github.com/KScl)
 * [sterdev](https://github.com/sterdev)
 * [TheKinrar](https://github.com/TheKinrar)
 * [AA4ch1](https://github.com/AA4ch1)
 * [alexgleason](https://github.com/alexgleason)
 * [cpytel](https://github.com/cpytel)
 * [northerner](https://github.com/northerner)
+* [fhemberger](https://github.com/fhemberger)
 * [hnrysmth](https://github.com/hnrysmth)
-* [hugogameiro](https://github.com/hugogameiro)
+* [d6rkaiz](https://github.com/d6rkaiz)
+* [JMendyk](https://github.com/JMendyk)
 * [JohnD28](https://github.com/JohnD28)
 * [znz](https://github.com/znz)
 * [Naouak](https://github.com/Naouak)
-* [rtucker](https://github.com/rtucker)
 * [reneklacan](https://github.com/reneklacan)
-* [KScl](https://github.com/KScl)
-* [SerCom-KC](https://github.com/SerCom-KC)
+* [ekiru](https://github.com/ekiru)
 * [tcitworld](https://github.com/tcitworld)
 * [geta6](https://github.com/geta6)
-* [goofy-bz](https://github.com/goofy-bz)
 * [happycoloredbanana](https://github.com/happycoloredbanana)
 * [leopku](https://github.com/leopku)
 * [SansPseudoFix](https://github.com/SansPseudoFix)
 * [tomfhowe](https://github.com/tomfhowe)
 * [noraworld](https://github.com/noraworld)
-* [fvh-P](https://github.com/fvh-P)
 * [178inaba](https://github.com/178inaba)
-* [devkral](https://github.com/devkral)
 * [alyssais](https://github.com/alyssais)
 * [kodnaplakal](https://github.com/kodnaplakal)
 * [stalker314314](https://github.com/stalker314314)
 * [huertanix](https://github.com/huertanix)
 * [genesixx](https://github.com/genesixx)
-* [fhemberger](https://github.com/fhemberger)
 * [halkeye](https://github.com/halkeye)
+* [hinaloe](https://github.com/hinaloe)
 * [treby](https://github.com/treby)
-* [d6rkaiz](https://github.com/d6rkaiz)
 * [jpdevries](https://github.com/jpdevries)
-* [rndm-stranger](https://github.com/rndm-stranger)
+* [00x9d](https://github.com/00x9d)
+* [Kurtis Rainbolt-Greene](mailto:me@kurtisrainboltgreene.name)
 * [saper](https://github.com/saper)
 * [nevillepark](https://github.com/nevillepark)
 * [ornithocoder](https://github.com/ornithocoder)
 * [pierreozoux](https://github.com/pierreozoux)
-* [ramlmn](https://github.com/ramlmn)
+* [Ram Lmn](mailto:ramlmn@users.noreply.github.com)
 * [harukasan](https://github.com/harukasan)
 * [stamak](https://github.com/stamak)
+* [theboss](https://github.com/theboss)
+* [Technowix](mailto:technowix@users.noreply.github.com)
 * [Eychics](https://github.com/Eychics)
-* [thor-the-norseman](https://github.com/thor-the-norseman)
+* [Thor Harald Johansen](mailto:thj@thj.no)
 * [0x70b1a5](https://github.com/0x70b1a5)
 * [gled-rs](https://github.com/gled-rs)
 * [R0ckweb](https://github.com/R0ckweb)
+* [caasi](https://github.com/caasi)
 * [esetomo](https://github.com/esetomo)
 * [foxiehkins](https://github.com/foxiehkins)
-* [sdukhovni](https://github.com/sdukhovni)
+* [hoodie](mailto:hoodiekitten@outlook.com)
+* [luzi82](https://github.com/luzi82)
+* [duxovni](https://github.com/duxovni)
 * [unsmell](https://github.com/unsmell)
 * [chriswmartin](https://github.com/chriswmartin)
 * [vahnj](https://github.com/vahnj)
@@ -152,6 +171,7 @@ and provided thanks to the work of the following contributors:
 * [redtachyons](https://github.com/redtachyons)
 * [thurloat](https://github.com/thurloat)
 * [aaribaud](https://github.com/aaribaud)
+* [Andrew](mailto:andrewlchronister@gmail.com)
 * [estuans](https://github.com/estuans)
 * [dissolve](https://github.com/dissolve)
 * [PurpleBooth](https://github.com/PurpleBooth)
@@ -165,7 +185,6 @@ and provided thanks to the work of the following contributors:
 * [farlistener](https://github.com/farlistener)
 * [DavidLibeau](https://github.com/DavidLibeau)
 * [SirCmpwn](https://github.com/SirCmpwn)
-* [MasterGroosha](https://github.com/MasterGroosha)
 * [Fjoerfoks](https://github.com/Fjoerfoks)
 * [fmauNeko](https://github.com/fmauNeko)
 * [gloaec](https://github.com/gloaec)
@@ -175,26 +194,37 @@ and provided thanks to the work of the following contributors:
 * [h-izumi](https://github.com/h-izumi)
 * [ErikXXon](https://github.com/ErikXXon)
 * [ian-kelling](https://github.com/ian-kelling)
+* [immae](https://github.com/immae)
+* [Reverite](https://github.com/Reverite)
 * [foozmeat](https://github.com/foozmeat)
 * [jasonrhodes](https://github.com/jasonrhodes)
-* [asm](https://github.com/asm)
+* [Jason Snell](mailto:jason@newrelic.com)
 * [jviide](https://github.com/jviide)
 * [crakaC](https://github.com/crakaC)
 * [tkbky](https://github.com/tkbky)
+* [Kaylee](mailto:kaylee@codethat.sucks)
 * [Kazhnuz](https://github.com/Kazhnuz)
+* [connyduck](https://github.com/connyduck)
+* [Lindsey Bieda](mailto:lindseyb@users.noreply.github.com)
+* [Lorenz Diener](mailto:halcyon@icosahedron.website)
 * [alimony](https://github.com/alimony)
 * [mig5](https://github.com/mig5)
 * [ndarville](https://github.com/ndarville)
 * [Abzol](https://github.com/Abzol)
+* [pwoolcoc](https://github.com/pwoolcoc)
 * [xPaw](https://github.com/xPaw)
+* [petzah](https://github.com/petzah)
+* [ignisf](https://github.com/ignisf)
 * [raymestalez](https://github.com/raymestalez)
+* [u1-liquid](https://github.com/u1-liquid)
 * [sim6](https://github.com/sim6)
-* [ekiru](https://github.com/ekiru)
-* [Technowix](https://github.com/Technowix)
+* [stemid](https://github.com/stemid)
 * [ThomasLeister](https://github.com/ThomasLeister)
 * [mcat-ee](https://github.com/mcat-ee)
 * [tototoshi](https://github.com/tototoshi)
+* [TrashMacNugget](https://github.com/TrashMacNugget)
 * [VirtuBox](https://github.com/VirtuBox)
+* [Vladyslav](mailto:vaden@tuta.io)
 * [kaniini](https://github.com/kaniini)
 * [vayan](https://github.com/vayan)
 * [yannicka](https://github.com/yannicka)
@@ -202,12 +232,16 @@ and provided thanks to the work of the following contributors:
 * [zacanger](https://github.com/zacanger)
 * [amazedkoumei](https://github.com/amazedkoumei)
 * [anon5r](https://github.com/anon5r)
+* [bsky](mailto:me@imbsky.net)
+* [chr-1x](https://github.com/chr-1x)
 * [codl](https://github.com/codl)
+* [cpsdqs](https://github.com/cpsdqs)
 * [barzamin](https://github.com/barzamin)
 * [fhalna](https://github.com/fhalna)
 * [haoyayoi](https://github.com/haoyayoi)
 * [ik11235](https://github.com/ik11235)
 * [kawax](https://github.com/kawax)
+* [kedamaDQ](https://github.com/kedamaDQ)
 * [007lva](https://github.com/007lva)
 * [matsurai25](https://github.com/matsurai25)
 * [mecab](https://github.com/mecab)
@@ -215,32 +249,41 @@ and provided thanks to the work of the following contributors:
 * [oliverkeeble](https://github.com/oliverkeeble)
 * [pinfort](https://github.com/pinfort)
 * [rbaumert](https://github.com/rbaumert)
+* [trwnh](https://github.com/trwnh)
 * [usagi-f](https://github.com/usagi-f)
 * [vidarlee](https://github.com/vidarlee)
 * [vjackson725](https://github.com/vjackson725)
 * [wxcafe](https://github.com/wxcafe)
 * [rinsuki](https://github.com/rinsuki)
+* [新都心(Neet Shin)](mailto:nucx@dio-vox.com)
 * [cygnan](https://github.com/cygnan)
 * [Awea](https://github.com/Awea)
 * [halcy](https://github.com/halcy)
-* [bounshi](https://github.com/bounshi)
+* [naaaaaaaaaaaf](https://github.com/naaaaaaaaaaaf)
+* [NecroTechno](https://github.com/NecroTechno)
 * [8398a7](https://github.com/8398a7)
 * [857b](https://github.com/857b)
+* [insom](https://github.com/insom)
+* [Aditoo17](https://github.com/Aditoo17)
 * [unascribed](https://github.com/unascribed)
 * [Aguay-val](https://github.com/Aguay-val)
 * [knu](https://github.com/knu)
+* [h3poteto](https://github.com/h3poteto)
+* [unleashed](https://github.com/unleashed)
 * [alxrcs](https://github.com/alxrcs)
 * [console-cowboy](https://github.com/console-cowboy)
 * [pointlessone](https://github.com/pointlessone)
 * [a2](https://github.com/a2)
 * [0xa](https://github.com/0xa)
+* [palindromordnilap](https://github.com/palindromordnilap)
 * [virtualpain](https://github.com/virtualpain)
 * [sapphirus](https://github.com/sapphirus)
 * [amandavisconti](https://github.com/amandavisconti)
 * [ameliavoncat](https://github.com/ameliavoncat)
 * [ilpianista](https://github.com/ilpianista)
-* [andydrop](https://github.com/andydrop)
+* [Andreas Drop](mailto:andy@remline.de)
 * [schas002](https://github.com/schas002)
+* [abackstrom](https://github.com/abackstrom)
 * [jumbosushi](https://github.com/jumbosushi)
 * [ayumin](https://github.com/ayumin)
 * [BaptisteGelez](https://github.com/BaptisteGelez)
@@ -251,6 +294,7 @@ and provided thanks to the work of the following contributors:
 * [brycied00d](https://github.com/brycied00d)
 * [carlosjs23](https://github.com/carlosjs23)
 * [cgxxx](https://github.com/cgxxx)
+* [kibitan](https://github.com/kibitan)
 * [chrisheninger](https://github.com/chrisheninger)
 * [chris-martin](https://github.com/chris-martin)
 * [DoubleMalt](https://github.com/DoubleMalt)
@@ -259,21 +303,30 @@ and provided thanks to the work of the following contributors:
 * [chriswk](https://github.com/chriswk)
 * [csu](https://github.com/csu)
 * [kklleemm](https://github.com/kklleemm)
+* [dachinat](https://github.com/dachinat)
 * [monsterpit-daggertooth](https://github.com/monsterpit-daggertooth)
 * [watilde](https://github.com/watilde)
 * [daprice](https://github.com/daprice)
 * [dar5hak](https://github.com/dar5hak)
 * [kant](https://github.com/kant)
+* [maxolasersquad](https://github.com/maxolasersquad)
 * [singingwolfboy](https://github.com/singingwolfboy)
 * [davidcelis](https://github.com/davidcelis)
+* [davefp](https://github.com/davefp)
 * [yipdw](https://github.com/yipdw)
 * [debanshuk](https://github.com/debanshuk)
+* [Derek Lewis](mailto:derekcecillewis@gmail.com)
 * [dblandin](https://github.com/dblandin)
-* [aranaur](https://github.com/aranaur)
+* [Drew Gates](mailto:aranaur@users.noreply.github.com)
+* [dtschust](https://github.com/dtschust)
+* [Dryusdan](https://github.com/Dryusdan)
+* [eai04191](https://github.com/eai04191)
 * [d3vgru](https://github.com/d3vgru)
 * [Elizafox](https://github.com/Elizafox)
 * [ericblade](https://github.com/ericblade)
 * [mikoim](https://github.com/mikoim)
+* [espenronnevik](https://github.com/espenronnevik)
+* [Finariel](https://github.com/Finariel)
 * [siuying](https://github.com/siuying)
 * [hattori6789](https://github.com/hattori6789)
 * [algernon](https://github.com/algernon)
@@ -283,21 +336,23 @@ and provided thanks to the work of the following contributors:
 * [Fiaxhs](https://github.com/Fiaxhs)
 * [reedcourty](https://github.com/reedcourty)
 * [anneau](https://github.com/anneau)
+* [Harmon758](https://github.com/Harmon758)
 * [HellPie](https://github.com/HellPie)
 * [Habu-Kagumba](https://github.com/Habu-Kagumba)
-* [hinaloe](https://github.com/hinaloe)
 * [suzukaze](https://github.com/suzukaze)
 * [Hiromi-Kai](https://github.com/Hiromi-Kai)
+* [hishamhm](https://github.com/hishamhm)
 * [musashino205](https://github.com/musashino205)
 * [iwaim](https://github.com/iwaim)
 * [valrus](https://github.com/valrus)
 * [IMcD23](https://github.com/IMcD23)
 * [yi0713](https://github.com/yi0713)
-* [immae](https://github.com/immae)
 * [iblech](https://github.com/iblech)
+* [usbsnowcrash](https://github.com/usbsnowcrash)
 * [jack-michaud](https://github.com/jack-michaud)
 * [Floppy](https://github.com/Floppy)
 * [loomchild](https://github.com/loomchild)
+* [jenkr55](https://github.com/jenkr55)
 * [docjkl](https://github.com/docjkl)
 * [TrollDecker](https://github.com/TrollDecker)
 * [jmontane](https://github.com/jmontane)
@@ -311,24 +366,29 @@ and provided thanks to the work of the following contributors:
 * [j0k3r](https://github.com/j0k3r)
 * [KEINOS](https://github.com/KEINOS)
 * [futoase](https://github.com/futoase)
-* [abjectio](https://github.com/abjectio)
+* [Pneumaticat](https://github.com/Pneumaticat)
+* [Kit Redgrave](mailto:qwertyitis@gmail.com)
+* [Knut Erik](mailto:abjectio@users.noreply.github.com)
 * [mkody](https://github.com/mkody)
-* [connyduck](https://github.com/connyduck)
 * [k0ta0uchi](https://github.com/k0ta0uchi)
 * [KrzysiekJ](https://github.com/KrzysiekJ)
 * [leowzukw](https://github.com/leowzukw)
 * [lmorchard](https://github.com/lmorchard)
+* [Tak](https://github.com/Tak)
 * [cacheflow](https://github.com/cacheflow)
 * [ldidry](https://github.com/ldidry)
 * [jemus42](https://github.com/jemus42)
 * [lfuelling](https://github.com/lfuelling)
 * [Grabacr07](https://github.com/Grabacr07)
 * [mistermantas](https://github.com/mistermantas)
+* [mareklach](https://github.com/mareklach)
 * [wirehack7](https://github.com/wirehack7)
+* [martymcguire](https://github.com/martymcguire)
 * [marvinkopf](https://github.com/marvinkopf)
 * [otsune](https://github.com/otsune)
-* [m-blc](https://github.com/m-blc)
+* [Mathias B](mailto:10813340+mathias-b@users.noreply.github.com)
 * [matt-auckland](https://github.com/matt-auckland)
+* [matthiasbeyer](https://github.com/matthiasbeyer)
 * [mattjmattj](https://github.com/mattjmattj)
 * [mtparet](https://github.com/mtparet)
 * [maximeborges](https://github.com/maximeborges)
@@ -336,7 +396,7 @@ and provided thanks to the work of the following contributors:
 * [michaeljdeeb](https://github.com/michaeljdeeb)
 * [Themimitoof](https://github.com/Themimitoof)
 * [cyweo](https://github.com/cyweo)
-* [M1dgard](https://github.com/M1dgard)
+* [Midgard](mailto:m1dgard@users.noreply.github.com)
 * [mike-burns](https://github.com/mike-burns)
 * [verymilan](https://github.com/verymilan)
 * [milmazz](https://github.com/milmazz)
@@ -344,29 +404,38 @@ and provided thanks to the work of the following contributors:
 * [mitchhentges](https://github.com/mitchhentges)
 * [moritzheiber](https://github.com/moritzheiber)
 * [mouse-reeve](https://github.com/mouse-reeve)
+* [Mozinet-fr](https://github.com/Mozinet-fr)
 * [lae](https://github.com/lae)
 * [Nanamachi](https://github.com/Nanamachi)
+* [orinthe](https://github.com/orinthe)
+* [Dar13](https://github.com/Dar13)
 * [ngerakines](https://github.com/ngerakines)
 * [vonneudeck](https://github.com/vonneudeck)
 * [Ninetailed](https://github.com/Ninetailed)
 * [k24](https://github.com/k24)
-* [noiob](https://github.com/noiob)
+* [Noiob](mailto:noiob@users.noreply.github.com)
 * [kwaio](https://github.com/kwaio)
 * [norayr](https://github.com/norayr)
 * [joyeusenoelle](https://github.com/joyeusenoelle)
 * [OlivierNicole](https://github.com/OlivierNicole)
+* [noppa](https://github.com/noppa)
 * [Otakan951](https://github.com/Otakan951)
 * [fahy](https://github.com/fahy)
+* [PatrickRWells](https://github.com/PatrickRWells)
 * [Pangoraw](https://github.com/Pangoraw)
-* [pwoolcoc](https://github.com/pwoolcoc)
 * [peterkeen](https://github.com/peterkeen)
-* [petzah](https://github.com/petzah)
-* [ignisf](https://github.com/ignisf)
+* [pgate](https://github.com/pgate)
+* [qguv](https://github.com/qguv)
+* [remram44](https://github.com/remram44)
+* [retokromer](https://github.com/retokromer)
 * [rfwatson](https://github.com/rfwatson)
 * [rfreebern](https://github.com/rfreebern)
+* [Ryan Wade](mailto:ryan.wade@protonmail.com)
 * [sylph01](https://github.com/sylph01)
+* [S-H-GAMELINKS](https://github.com/S-H-GAMELINKS)
 * [staticsafe](https://github.com/staticsafe)
 * [snwh](https://github.com/snwh)
+* [sts10](https://github.com/sts10)
 * [skoji](https://github.com/skoji)
 * [ScienJus](https://github.com/ScienJus)
 * [larkinscott](https://github.com/larkinscott)
@@ -378,73 +447,97 @@ and provided thanks to the work of the following contributors:
 * [ernix](https://github.com/ernix)
 * [rosylilly](https://github.com/rosylilly)
 * [shouko](https://github.com/shouko)
+* [Sina Mashek](mailto:sina@mashek.xyz)
 * [sossii](https://github.com/sossii)
+* [SpankyWorks](https://github.com/SpankyWorks)
 * [StefOfficiel](https://github.com/StefOfficiel)
 * [svetlik](https://github.com/svetlik)
 * [dereckson](https://github.com/dereckson)
-* [theboss](https://github.com/theboss)
+* [phaedryx](https://github.com/phaedryx)
 * [takp](https://github.com/takp)
 * [tkusano](https://github.com/tkusano)
+* [TakesxiSximada](https://github.com/TakesxiSximada)
 * [TheInventrix](https://github.com/TheInventrix)
 * [shug0](https://github.com/shug0)
 * [Fortyseven](https://github.com/Fortyseven)
 * [tobypinder](https://github.com/tobypinder)
 * [tomosm](https://github.com/tomosm)
 * [TomoyaShibata](https://github.com/TomoyaShibata)
-* [TrashMacNugget](https://github.com/TrashMacNugget)
 * [treyssatvincent](https://github.com/treyssatvincent)
-* [optikfluffel](https://github.com/optikfluffel)
-* [vmincev](https://github.com/vmincev)
-* [waldyrious](https://github.com/waldyrious)
-* [tahnok](https://github.com/tahnok)
-* [YDrogen](https://github.com/YDrogen)
-* [YOSHIOKAEiichiro](https://github.com/YOSHIOKAEiichiro)
-* [S-YOU](https://github.com/S-YOU)
-* [YaQ00](https://github.com/YaQ00)
-* [yanakend](https://github.com/yanakend)
-* [orzFly](https://github.com/orzFly)
-* [chansuke](https://github.com/chansuke)
-* [yuntan](https://github.com/yuntan)
-* [LogicalDash](https://github.com/LogicalDash)
-* [ZiiX](https://github.com/ZiiX)
-* [benklop](https://github.com/benklop)
-* [caasi](https://github.com/caasi)
-* [caesarologia](https://github.com/caesarologia)
-* [chrolis](https://github.com/chrolis)
-* [cormojs](https://github.com/cormojs)
-* [cpsdqs](https://github.com/cpsdqs)
-* [d0p1s4m4](https://github.com/d0p1s4m4)
-* [evilny0](https://github.com/evilny0)
-* [febrezo](https://github.com/febrezo)
-* [fsubal](https://github.com/fsubal)
-* [dikky1218](https://github.com/dikky1218)
-* [gentarok](https://github.com/gentarok)
-* [hakoai](https://github.com/hakoai)
-* [chaosbunker](https://github.com/chaosbunker)
-* [isati](https://github.com/isati)
-* [jkap](https://github.com/jkap)
-* [jirayudech](https://github.com/jirayudech)
-* [jukper](https://github.com/jukper)
-* [karlyeurl](https://github.com/karlyeurl)
-* [kedamaDQ](https://github.com/kedamaDQ)
-* [kuro5hin](https://github.com/kuro5hin)
-* [maxypy](https://github.com/maxypy)
-* [marcus-herrmann](https://github.com/marcus-herrmann)
-* [mshrtkch](https://github.com/mshrtkch)
-* [muan](https://github.com/muan)
-* [rch850](https://github.com/rch850)
-* [roikale](https://github.com/roikale)
-* [rysiekpl](https://github.com/rysiekpl)
-* [saturday06](https://github.com/saturday06)
-* [scriptjunkie](https://github.com/scriptjunkie)
-* [seekr](https://github.com/seekr)
-* [syui](https://github.com/syui)
-* [tackeyy](https://github.com/tackeyy)
-* [tmyt](https://github.com/tmyt)
-* [utam0k](https://github.com/utam0k)
-* [vpzomtrrfrt](https://github.com/vpzomtrrfrt)
-* [walfie](https://github.com/walfie)
-* [y-temp4](https://github.com/y-temp4)
-* [ymmtmdk](https://github.com/ymmtmdk)
+* [Udo Kramer](mailto:optik@fluffel.io)
+* [Una](mailto:una@unascribed.com)
+* [Ushitora Anqou](mailto:ushitora_anqou@yahoo.co.jp)
+* [Valentin Lorentz](mailto:progval+git@progval.net)
+* [Vladimir Mincev](mailto:vladimir@canicinteractive.com)
+* [Waldir Pimenta](mailto:waldyrious@gmail.com)
+* [Wesley Ellis](mailto:tahnok@gmail.com)
+* [Wiktor](mailto:wiktor@metacode.biz)
+* [Wonderfall](mailto:wonderfall@schrodinger.io)
+* [YDrogen](mailto:ydrogen45@gmail.com)
+* [YMHuang](mailto:ymhuang@fmbase.tw)
+* [YOSHIOKA Eiichiro](mailto:yoshioka.eiichiro@gmail.com)
+* [YOU](mailto:stackexchange.you@gmail.com)
+* [YaQ](mailto:i_k_o_m_a_7@yahoo.co.jp)
+* [Yanaken](mailto:yanakend@gmail.com)
+* [Yann Klis](mailto:yann.klis@gmail.com)
+* [Yeechan Lu](mailto:wz.bluesnow@gmail.com)
+* [Yusuke Abe](mailto:moonset20@gmail.com)
+* [Zachary Spector](mailto:logicaldash@gmail.com)
+* [ZiiX](mailto:ziix@users.noreply.github.com)
+* [asria-jp](mailto:is@alicematic.com)
+* [ava](mailto:vladooku@users.noreply.github.com)
+* [benklop](mailto:benklop@gmail.com)
+* [bsky](mailto:git@imbsky.net)
+* [caesarologia](mailto:lopesgemelli.1@gmail.com)
+* [chrolis](mailto:chrolis@users.noreply.github.com)
+* [cormo](mailto:cormorant2+github@gmail.com)
+* [d0p1](mailto:dopi-sama@hush.com)
+* [evilny0](mailto:evilny0@moomoocamp.net)
+* [febrezo](mailto:felixbrezo@gmail.com)
+* [fsubal](mailto:fsubal@users.noreply.github.com)
+* [fusshi-](mailto:dikky1218@users.noreply.github.com)
+* [gentaro](mailto:gentaroooo@gmail.com)
+* [hakoai](mailto:hk--76@qa2.so-net.ne.jp)
+* [haosbvnker](mailto:github@chaosbunker.com)
+* [isati](mailto:phil@juchnowi.cz)
+* [jenn kaplan](mailto:me@jkap.io)
+* [jirayudech](mailto:jirayudech@gmail.com)
+* [jukper](mailto:jukkaperanto@gmail.com)
+* [jumoru](mailto:jumoru@mailbox.org)
+* [karlyeurl](mailto:karl.yeurl@gmail.com)
+* [kedama](mailto:32974885+kedamadq@users.noreply.github.com)
+* [kuro5hin](mailto:rusty@kuro5hin.org)
+* [maxypy](mailto:maxime@mpigou.fr)
+* [mhe](mailto:mail@marcus-herrmann.com)
+* [mimikun](mailto:dzdzble_effort_311@outlook.jp)
+* [mshrtkch](mailto:mshrtkch@users.noreply.github.com)
+* [muan](mailto:muan@github.com)
+* [neetshin](mailto:neetshin@neetsh.in)
+* [rch850](mailto:rich850@gmail.com)
+* [roikale](mailto:roikale@users.noreply.github.com)
+* [rysiekpl](mailto:rysiek@hackerspace.pl)
+* [saturday06](mailto:dyob@lunaport.net)
+* [scriptjunkie](mailto:scriptjunkie@scriptjunkie.us)
+* [seekr](mailto:mario.drs@gmail.com)
+* [sundevour](mailto:31990469+sundevour@users.noreply.github.com)
+* [syui](mailto:syui@users.noreply.github.com)
+* [tackeyy](mailto:mailto.takita.yusuke@gmail.com)
+* [tateisu](mailto:tateisu@gmail.com)
+* [tmyt](mailto:shigure@refy.net)
+* [utam0k](mailto:k0ma@utam0k.jp)
+* [vpzomtrrfrt](mailto:vpzomtrrfrt@gmail.com)
+* [walfie](mailto:walfington@gmail.com)
+* [y-temp4](mailto:y.temp4@gmail.com)
+* [ymmtmdk](mailto:ymmtmdk@gmail.com)
+* [yoshipc](mailto:yoooo@yoshipc.net)
+* [Özcan Zafer AYAN](mailto:ozcanzaferayan@gmail.com)
+* [ばん](mailto:detteiu0321@gmail.com)
+* [みたらしだんご](mailto:mitarashidango@users.noreply.github.com)
+* [りんすき](mailto:6533808+rinsuki@users.noreply.github.com)
+* [ヨイツの賢狼ホロ | 3rd style](mailto:horo@yoitsu.moe)
+* [猫吸血鬼ディフリス / 猫ロキP](mailto:deflis@gmail.com)
+* [艮 鮟鱇](mailto:ushitora_anqou@yahoo.co.jp)
+* [西小倉宏信](mailto:nishiko@mindia.jp)
+* [雨宮美羽](mailto:k737566@gmail.com)
 
 This document is provided for informational purposes only. Since it is only updated once per release, the version you are looking at may be currently out of date. To see the full list of contributors, consider looking at the [git history](https://github.com/tootsuite/mastodon/graphs/contributors) instead.
diff --git a/Aptfile b/Aptfile
index 60d24f8b3..0a01fa24b 100644
--- a/Aptfile
+++ b/Aptfile
@@ -10,3 +10,20 @@ libxdamage1
 libxfixes3
 protobuf-compiler
 zlib1g-dev
+libcairo2
+libcroco3
+libdatrie1
+libgdk-pixbuf2.0-0
+libgraphite2-3
+libharfbuzz0b
+libpango-1.0-0
+libpangocairo-1.0-0
+libpangoft2-1.0-0
+libpixman-1-0
+librsvg2-2
+libthai-data
+libthai0
+libvpx5
+libxcb-render0
+libxcb-shm0
+libxrender1
diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb
index 0b3735087..90f42251e 100644
--- a/app/controllers/api/base_controller.rb
+++ b/app/controllers/api/base_controller.rb
@@ -53,10 +53,6 @@ class Api::BaseController < ApplicationController
     [params[:limit].to_i.abs, default_limit * 2].min
   end
 
-  def truthy_param?(key)
-    ActiveModel::Type::Boolean.new.cast(params[key])
-  end
-
   def current_resource_owner
     @current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
   end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 8ffc31bb4..dca6c5a5a 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -128,6 +128,10 @@ class ApplicationController < ActionController::Base
 
   protected
 
+  def truthy_param?(key)
+    ActiveModel::Type::Boolean.new.cast(params[key])
+  end
+
   def forbidden
     respond_with_error(403)
   end
diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb
index 7cd46662f..19722364c 100644
--- a/app/controllers/auth/sessions_controller.rb
+++ b/app/controllers/auth/sessions_controller.rb
@@ -11,6 +11,7 @@ class Auth::SessionsController < Devise::SessionsController
   prepend_before_action :set_pack
   before_action :set_instance_presenter, only: [:new]
   before_action :set_body_classes
+  after_action :clear_site_data, only: [:destroy]
 
   def new
     Devise.omniauth_configs.each do |provider, config|
@@ -28,8 +29,10 @@ class Auth::SessionsController < Devise::SessionsController
   end
 
   def destroy
+    tmp_stored_location = stored_location_for(:user)
     super
     flash.delete(:notice)
+    store_location_for(:user, tmp_stored_location) if continue_after?
   end
 
   protected
@@ -126,4 +129,16 @@ class Auth::SessionsController < Devise::SessionsController
     end
     paths
   end
+
+  def clear_site_data
+    return if continue_after?
+
+    # Should be '"*"' but that doen't work in Chrome (neither does '"executionContexts"')
+    # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data
+    response.headers['Clear-Site-Data'] = '"cache", "cookies", "storage"'
+  end
+
+  def continue_after?
+    truthy_param?(:continue)
+  end
 end
diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb
index eb977510b..f6f5d1ecc 100644
--- a/app/controllers/oauth/authorizations_controller.rb
+++ b/app/controllers/oauth/authorizations_controller.rb
@@ -18,4 +18,18 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
   def set_pack
     use_pack 'auth'
   end
+
+  def render_success
+    if skip_authorization? || (matching_token? && !truthy_param?('force_login'))
+      redirect_or_render authorize_response
+    elsif Doorkeeper.configuration.api_only
+      render json: pre_auth
+    else
+      render :new
+    end
+  end
+
+  def truthy_param?(key)
+    ActiveModel::Type::Boolean.new.cast(params[key])
+  end
 end
diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb
index fc03fcf82..ed873ceed 100644
--- a/app/helpers/settings_helper.rb
+++ b/app/helpers/settings_helper.rb
@@ -8,6 +8,7 @@ module SettingsHelper
     bg: 'Български',
     ca: 'Català',
     co: 'Corsu',
+    cs: 'Čeština',
     cy: 'Cymraeg',
     da: 'Dansk',
     de: 'Deutsch',
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 83cbb5240..7499f03ea 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -63,7 +63,7 @@
   "column_header.show_settings": "Показать настройки",
   "column_header.unpin": "Открепить",
   "column_subheading.settings": "Настройки",
-  "community.column_settings.media_only": "Только медиа",
+  "community.column_settings.media_only": "Только с медиа",
   "compose_form.direct_message_warning": "Этот статус будет виден только упомянутым пользователям.",
   "compose_form.direct_message_warning_learn_more": "Узнать больше",
   "compose_form.hashtag_warning": "Этот пост не будет показывается в поиске по хэштегу, т.к. он непубличный. Только публичные посты можно найти в поиске по хэштегу.",
@@ -76,7 +76,7 @@
   "compose_form.sensitive.unmarked": "Медиафайлы не отмечены как чувствительные",
   "compose_form.spoiler.marked": "Текст скрыт за предупреждением",
   "compose_form.spoiler.unmarked": "Текст не скрыт",
-  "compose_form.spoiler_placeholder": "Напишите свое предупреждение здесь",
+  "compose_form.spoiler_placeholder": "Текст предупреждения",
   "confirmation_modal.cancel": "Отмена",
   "confirmations.block.confirm": "Заблокировать",
   "confirmations.block.message": "Вы уверены, что хотите заблокировать {name}?",
@@ -290,7 +290,7 @@
   "status.mention": "Упомянуть @{name}",
   "status.more": "Больше",
   "status.mute": "Заглушить @{name}",
-  "status.mute_conversation": "Заглушить тред",
+  "status.mute_conversation": "Заглушить всю цепочку",
   "status.open": "Развернуть статус",
   "status.pin": "Закрепить в профиле",
   "status.pinned": "Закреплённый статус",
@@ -300,7 +300,7 @@
   "status.reblogs.empty": "Никто ещё не продвинул этот статус. Как только кто-то это сделает, они появятся здесь.",
   "status.redraft": "Удалить и исправить",
   "status.reply": "Ответить",
-  "status.replyAll": "Ответить на тред",
+  "status.replyAll": "Ответить всем",
   "status.report": "Пожаловаться",
   "status.sensitive_toggle": "Нажмите для просмотра",
   "status.sensitive_warning": "Чувствительный контент",
diff --git a/app/javascript/styles/mastodon/accessibility.scss b/app/javascript/styles/mastodon/accessibility.scss
index 373bcd4ac..d33806c84 100644
--- a/app/javascript/styles/mastodon/accessibility.scss
+++ b/app/javascript/styles/mastodon/accessibility.scss
@@ -1,4 +1,4 @@
-$black-emojis: '8ball' 'ant' 'back' 'black_circle' 'black_large_square' 'black_medium_small_square' 'black_medium_square' 'black_nib' 'black_small_square' 'bomb' 'bust_in_silhouette' 'camera' 'camera_with_flash' 'clubs' 'copyright' 'curly_loop' 'currency_exchange' 'end' 'heavy_check_mark' 'heavy_division_sign' 'heavy_dollar_sign' 'heavy_minus_sign' 'heavy_multiplication_x' 'heavy_plus_sign' 'lower_left_fountain_pen' 'on' 'registered' 'soon' 'spades' 'spider' 'tm' 'top' 'waving_black_flag' 'wavy_dash' 'video_game';
+$black-emojis: '8ball' 'ant' 'back' 'black_circle' 'black_heart' 'black_large_square' 'black_medium_small_square' 'black_medium_square' 'black_nib' 'black_small_square' 'bomb' 'bowling' 'bust_in_silhouette' 'busts_in_silhouette' 'camera' 'camera_with_flash' 'clubs' 'copyright' 'curly_loop' 'currency_exchange' 'dark_sunglasses' 'eight_pointed_black_star' 'electric_plug' 'end' 'female-guard' 'film_projector' 'fried_egg' 'gorilla' 'guardsman' 'heavy_check_mark' 'heavy_division_sign' 'heavy_dollar_sign' 'heavy_minus_sign' 'heavy_multiplication_x' 'heavy_plus_sign' 'hocho' 'hole' 'joystick' 'kaaba' 'lower_left_ballpoint_pen' 'lower_left_fountain_pen' 'male-guard' 'microphone' 'mortar_board' 'movie_camera' 'musical_score' 'on' 'registered' 'soon' 'spades' 'speaking_head_in_silhouette' 'spider' 'telephone_receiver' 'tm' 'top' 'tophat' 'turkey' 'vhs' 'video_camera' 'video_game' 'water_buffalo' 'waving_black_flag' 'wavy_dash';
 
 %white-emoji-outline {
   filter: drop-shadow(1px 1px 0 $white) drop-shadow(-1px 1px 0 $white) drop-shadow(1px -1px 0 $white) drop-shadow(-1px -1px 0 $white);
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 359b2b6a7..c6b3ed0e2 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -1666,14 +1666,14 @@ a.account__display-name {
 
   &.top {
     bottom: -5px;
-    margin-left: -13px;
+    margin-left: -7px;
     border-width: 5px 7px 0;
     border-top-color: $ui-secondary-color;
   }
 
   &.bottom {
     top: -5px;
-    margin-left: -13px;
+    margin-left: -7px;
     border-width: 0 7px 5px;
     border-bottom-color: $ui-secondary-color;
   }
diff --git a/app/javascript/styles/mastodon/reset.scss b/app/javascript/styles/mastodon/reset.scss
index ff3b2c022..a140e8bc7 100644
--- a/app/javascript/styles/mastodon/reset.scss
+++ b/app/javascript/styles/mastodon/reset.scss
@@ -53,6 +53,11 @@ table {
   border-spacing: 0;
 }
 
+html {
+  scrollbar-face-color: lighten($ui-base-color, 4%);
+  scrollbar-track-color: rgba($base-overlay-background, 0.1);
+}
+
 ::-webkit-scrollbar {
   width: 12px;
   height: 12px;
diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb
index 560a81768..ea94e2491 100644
--- a/app/services/fetch_link_card_service.rb
+++ b/app/services/fetch_link_card_service.rb
@@ -87,34 +87,36 @@ class FetchLinkCardService < BaseService
   end
 
   def attempt_oembed
-    embed = FetchOEmbedService.new.call(@url, html: @html)
+    service = FetchOEmbedService.new
+    embed   = service.call(@url, html: @html)
+    url     = Addressable::URI.parse(service.endpoint_url)
 
     return false if embed.nil?
 
     @card.type          = embed[:type]
     @card.title         = embed[:title]         || ''
     @card.author_name   = embed[:author_name]   || ''
-    @card.author_url    = embed[:author_url]    || ''
+    @card.author_url    = embed[:author_url].present? ? (url + embed[:author_url]).to_s : ''
     @card.provider_name = embed[:provider_name] || ''
-    @card.provider_url  = embed[:provider_url]  || ''
+    @card.provider_url  = embed[:provider_url].present? ? (url + embed[:provider_url]).to_s : ''
     @card.width         = 0
     @card.height        = 0
 
     case @card.type
     when 'link'
-      @card.image_remote_url = embed[:thumbnail_url] if embed[:thumbnail_url].present?
+      @card.image_remote_url = (url + embed[:thumbnail_url]).to_s if embed[:thumbnail_url].present?
     when 'photo'
       return false if embed[:url].blank?
 
-      @card.embed_url        = embed[:url]
-      @card.image_remote_url = embed[:url]
+      @card.embed_url        = (url + embed[:url]).to_s
+      @card.image_remote_url = (url + embed[:url]).to_s
       @card.width            = embed[:width].presence  || 0
       @card.height           = embed[:height].presence || 0
     when 'video'
       @card.width            = embed[:width].presence  || 0
       @card.height           = embed[:height].presence || 0
       @card.html             = Formatter.instance.sanitize(embed[:html], Sanitize::Config::MASTODON_OEMBED)
-      @card.image_remote_url = embed[:thumbnail_url] if embed[:thumbnail_url].present?
+      @card.image_remote_url = (url + embed[:thumbnail_url]).to_s if embed[:thumbnail_url].present?
     when 'rich'
       # Most providers rely on <script> tags, which is a no-no
       return false
@@ -146,7 +148,7 @@ class FetchLinkCardService < BaseService
 
     @card.title            = meta_property(page, 'og:title').presence || page.at_xpath('//title')&.content || ''
     @card.description      = meta_property(page, 'og:description').presence || meta_property(page, 'description') || ''
-    @card.image_remote_url = meta_property(page, 'og:image') if meta_property(page, 'og:image')
+    @card.image_remote_url = (Addressable::URI.parse(@url) + meta_property(page, 'og:image')).to_s if meta_property(page, 'og:image')
 
     return if @card.title.blank? && @card.html.blank?
 
diff --git a/app/services/fetch_oembed_service.rb b/app/services/fetch_oembed_service.rb
index 998228517..9ddf9b13b 100644
--- a/app/services/fetch_oembed_service.rb
+++ b/app/services/fetch_oembed_service.rb
@@ -31,7 +31,7 @@ class FetchOEmbedService
 
     return if @endpoint_url.blank?
 
-    @endpoint_url = Addressable::URI.parse(@endpoint_url).to_s
+    @endpoint_url = (Addressable::URI.parse(@url) + @endpoint_url).to_s
   rescue Addressable::URI::InvalidURIError
     @endpoint_url = nil
   end
diff --git a/app/views/accounts/_header.html.haml b/app/views/accounts/_header.html.haml
index 95e55a1b0..bfad49b6c 100644
--- a/app/views/accounts/_header.html.haml
+++ b/app/views/accounts/_header.html.haml
@@ -3,7 +3,10 @@
     = image_tag account.header.url, class: 'parallax'
   .public-account-header__bar
     = link_to short_account_url(account), class: 'avatar' do
-      = image_tag account.avatar.url
+      - if current_account&.user&.setting_auto_play_gif
+        = image_tag account.avatar_original_url
+      - else
+        = image_tag account.avatar_static_url
     .public-account-header__tabs
       .public-account-header__tabs__name
         %h1
diff --git a/app/views/layouts/modal.html.haml b/app/views/layouts/modal.html.haml
index a86b4fd3f..b6e33ca91 100644
--- a/app/views/layouts/modal.html.haml
+++ b/app/views/layouts/modal.html.haml
@@ -5,7 +5,7 @@
       .name
         = t 'users.signed_in_as'
         %span.username @#{current_account.local_username_and_domain}
-      = link_to destroy_user_session_path, method: :delete, class: 'logout-link icon-button' do
+      = link_to destroy_user_session_path(continue: true), method: :delete, class: 'logout-link icon-button' do
         = fa_icon 'sign-out'
 
   .container-alt= yield
diff --git a/bin/tootctl b/bin/tootctl
index 2fe02523a..f26e1c7ed 100755
--- a/bin/tootctl
+++ b/bin/tootctl
@@ -1,4 +1,5 @@
 #!/usr/bin/env ruby
 APP_PATH = File.expand_path('../config/application', __dir__)
+require_relative '../config/boot'
 require_relative '../lib/cli'
 Mastodon::CLI.start(ARGV)
diff --git a/config/application.rb b/config/application.rb
index 151b1d0b4..06ff8ed36 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -43,6 +43,7 @@ module Mastodon
       :bg,
       :ca,
       :co,
+      :cs,
       :cy,
       :da,
       :de,
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index cd9bacf68..3e4c9a79d 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -10,6 +10,7 @@ Warden::Manager.after_set_user except: :fetch do |user, warden|
     expires: 1.year.from_now,
     httponly: true,
     secure: (Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true'),
+    same_site: :lax,
   }
 end
 
@@ -20,6 +21,7 @@ Warden::Manager.after_fetch do |user, warden|
       expires: 1.year.from_now,
       httponly: true,
       secure: (Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true'),
+      same_site: :lax,
     }
   else
     warden.logout
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
index 3dc0edd6f..c0757b6b5 100644
--- a/config/initializers/session_store.rb
+++ b/config/initializers/session_store.rb
@@ -1,3 +1,3 @@
 # Be sure to restart your server when you modify this file.
 
-Rails.application.config.session_store :cookie_store, key: '_mastodon_session', secure: (Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true')
+Rails.application.config.session_store :cookie_store, key: '_mastodon_session', secure: (Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true'), same_site: :lax
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index f1b26236a..19771aefa 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -6,7 +6,7 @@ ru:
     about_this: Об этом узле
     administered_by: 'Администратор узла:'
     api: API
-    apps: Мобильные приложения
+    apps: Приложения
     closed_registrations: В данный момент регистрация на этом узле закрыта. Но вы можете найти другой узел, создать на нём учётную запись и получить доступ к той же сети оттуда.
     contact: Связаться
     contact_missing: Не установлено
@@ -51,7 +51,7 @@ ru:
       many: подписчиков
       one: подписчик
       other: подписчиков
-    following: Подписан(а)
+    following: подписки
     joined: 'Дата регистрации: %{date}'
     media: Медиа
     moved_html: "%{name} переехал(а) на %{new_profile_link}:"
@@ -206,7 +206,7 @@ ru:
     custom_emojis:
       by_domain: Домен
       copied_msg: Локальная копия эмодзи успешно создана
-      copy: Скопироват
+      copy: Копировать
       copy_failed_msg: Не удалось создать локальную копию эмодзи
       created_msg: Эмодзи успешно создано!
       delete: Удалить
@@ -231,11 +231,11 @@ ru:
     dashboard:
       backlog: задачи
       config: Конфигурация
-      feature_deletions: Аккаунтов удалено
+      feature_deletions: Удаление аккаунтов
       feature_invites: Пригласительные ссылки
-      feature_registrations: Регистрации
-      feature_relay: Ретрансляторов сети
-      features: Нововведения
+      feature_registrations: Регистрация
+      feature_relay: Ретрансляторы
+      features: Возможности
       hidden_service: Федерация со скрытыми сервисами
       open_reports: открытых жалоб
       recent_users: Недавние пользователи
@@ -300,7 +300,7 @@ ru:
       search: Поиск
       title: Известные узлы
     invites:
-      deactivate_all: Удалить все
+      deactivate_all: Отключить все
       filter:
         all: Все
         available: Актуальные
@@ -314,7 +314,7 @@ ru:
       inbox_url: URL ретранслятора
       pending: Ожидание подтверждения ретранслятора
       save_and_enable: Сохранить и включить
-      setup: Настроте соединение с ретранслятором
+      setup: Настроить соединение с ретранслятором
       status: Состояние
       title: Ретрансляторы
     report_notes:
@@ -405,7 +405,7 @@ ru:
         title: Расширенное описание узла
       site_short_description:
         desc_html: Отображается в боковой панели и в тегах. Опишите, что такое Mastodon и что делает именно этот узел особенным. Если пусто, используется описание узла по умолчанию.
-        title: Короткое описание узла
+        title: Краткое описание узла
       site_terms:
         desc_html: Вы можете добавить сюда собственную политику конфиденциальности, пользовательское соглашение и другие документы. Можно использовать теги HTML.
         title: Условия использования
@@ -791,7 +791,7 @@ ru:
       ownership: Нельзя закрепить чужой статус
       private: Нельзя закрепить непубличный статус
       reblog: Нельзя закрепить продвинутый статус
-    show_more: Подробнее
+    show_more: Ещё
     sign_in_to_participate: Войдите, чтобы принять участие в дискуссии
     title: '%{name}: "%{quote}"'
     visibilities:
diff --git a/config/locales/simple_form.ru.yml b/config/locales/simple_form.ru.yml
index 3ca176a1f..d1066b054 100644
--- a/config/locales/simple_form.ru.yml
+++ b/config/locales/simple_form.ru.yml
@@ -35,6 +35,8 @@ ru:
         data: Файл CSV, экспортированный с другого узла Mastodon
       sessions:
         otp: 'Введите код двухфакторной аутентификации, сгенерированный в мобильном приложении, или используйте один из Ваших кодов восстановления:'
+      user:
+        chosen_languages: Если выбрано, то в публичных лентах будут показаны только посты на выбранных языках
     labels:
       account:
         fields:
diff --git a/lib/mastodon/accounts_cli.rb b/lib/mastodon/accounts_cli.rb
index 83b69549d..d44cdfae9 100644
--- a/lib/mastodon/accounts_cli.rb
+++ b/lib/mastodon/accounts_cli.rb
@@ -43,6 +43,145 @@ module Mastodon
       end
     end
 
+    option :email, required: true
+    option :confirmed, type: :boolean
+    option :role, default: 'user'
+    option :reattach, type: :boolean
+    option :force, type: :boolean
+    desc 'add USERNAME', 'Create a new user'
+    long_desc <<-LONG_DESC
+      Create a new user account with a given USERNAME and an
+      e-mail address provided with --email.
+
+      With the --confirmed option, the confirmation e-mail will
+      be skipped and the account will be active straight away.
+
+      With the --role option one of  "user", "admin" or "moderator"
+      can be supplied. Defaults to "user"
+
+      With the --reattach option, the new user will be reattached
+      to a given existing username of an old account. If the old
+      account is still in use by someone else, you can supply
+      the --force option to delete the old record and reattach the
+      username to the new account anyway.
+    LONG_DESC
+    def add(username)
+      account  = Account.new(username: username)
+      password = SecureRandom.hex
+      user     = User.new(email: options[:email], password: password, admin: options[:role] == 'admin', moderator: options[:role] == 'moderator', confirmed_at: Time.now.utc)
+
+      if options[:reattach]
+        account = Account.find_local(username) || Account.new(username: username)
+
+        if account.user.present? && !options[:force]
+          say('The chosen username is currently in use', :red)
+          say('Use --force to reattach it anyway and delete the other user')
+          return
+        elsif account.user.present?
+          account.user.destroy!
+        end
+      end
+
+      user.account = account
+
+      if user.save
+        if options[:confirmed]
+          user.confirmed_at = nil
+          user.confirm!
+        end
+
+        say('OK', :green)
+        say("New password: #{password}")
+      else
+        user.errors.to_h.each do |key, error|
+          say('Failure/Error: ', :red)
+          say(key)
+          say('    ' + error, :red)
+        end
+      end
+    end
+
+    desc 'del USERNAME', 'Delete a user'
+    long_desc <<-LONG_DESC
+      Remove a user account with a given USERNAME.
+    LONG_DESC
+    def del(username)
+      account = Account.find_local(username)
+
+      if account.nil?
+        say('No user with such username', :red)
+        return
+      end
+
+      say("Deleting user with #{account.statuses_count}, this might take a while...")
+      SuspendAccountService.new.call(account, remove_user: true)
+      say('OK', :green)
+    end
+
+    option :dry_run, type: :boolean
+    desc 'cull', 'Remove remote accounts that no longer exist'
+    long_desc <<-LONG_DESC
+      Query every single remote account in the database to determine
+      if it still exists on the origin server, and if it doesn't,
+      remove it from the database.
+
+      Accounts that have had confirmed activity within the last week
+      are excluded from the checks.
+
+      If 10 or more accounts from the same domain cannot be queried
+      due to a connection error (such as missing DNS records) then
+      the domain is considered dead, and all other accounts from it
+      are deleted without further querying.
+
+      With the --dry-run option, no deletes will actually be carried
+      out.
+    LONG_DESC
+    def cull
+      domain_thresholds = Hash.new { |hash, key| hash[key] = 0 }
+      skip_threshold    = 7.days.ago
+      culled            = 0
+      dead_servers      = []
+      dry_run           = options[:dry_run] ? ' (DRY RUN)' : ''
+
+      Account.remote.where(protocol: :activitypub).partitioned.find_each do |account|
+        next if account.updated_at >= skip_threshold || account.last_webfingered_at >= skip_threshold
+
+        unless dead_servers.include?(account.domain)
+          begin
+            code = Request.new(:head, account.uri).perform(&:code)
+          rescue HTTP::ConnectionError
+            domain_thresholds[account.domain] += 1
+
+            if domain_thresholds[account.domain] >= 10
+              dead_servers << account.domain
+            end
+          rescue StandardError
+            next
+          end
+        end
+
+        if [404, 410].include?(code) || dead_servers.include?(account.domain)
+          unless options[:dry_run]
+            SuspendAccountService.new.call(account)
+            account.destroy
+          end
+
+          culled += 1
+          say('.', :green, false)
+        else
+          say('.', nil, false)
+        end
+      end
+
+      say
+      say("Removed #{culled} accounts (#{dead_servers.size} dead servers)#{dry_run}", :green)
+
+      unless dead_servers.empty?
+        say('R.I.P.:', :yellow)
+        dead_servers.each { |domain| say('    ' + domain) }
+      end
+    end
+
     private
 
     def rotate_keys_for_account(account, delay = 0)
diff --git a/lib/mastodon/cli_helper.rb b/lib/mastodon/cli_helper.rb
index 8c4d9731c..2f807d08c 100644
--- a/lib/mastodon/cli_helper.rb
+++ b/lib/mastodon/cli_helper.rb
@@ -4,5 +4,6 @@ dev_null = Logger.new('/dev/null')
 
 Rails.logger                 = dev_null
 ActiveRecord::Base.logger    = dev_null
+ActiveJob::Base.logger       = dev_null
 HttpLog.configuration.logger = dev_null
 Paperclip.options[:log]      = false
diff --git a/lib/tasks/repo.rake b/lib/tasks/repo.rake
new file mode 100644
index 000000000..367859e94
--- /dev/null
+++ b/lib/tasks/repo.rake
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+namespace :repo do
+  desc 'Generate the authors.md file'
+  task :authors do
+    file = File.open('AUTHORS.md', 'w')
+    file << <<~HEADER
+      Mastodon is available on [GitHub](https://github.com/tootsuite/mastodon)
+      and provided thanks to the work of the following contributors:
+
+    HEADER
+
+    url = 'https://api.github.com/repos/tootsuite/mastodon/contributors?anon=1'
+    HttpLog.config.compact_log = true
+    while url.present?
+      response = HTTP.get(url)
+      contributors = Oj.load(response.body)
+      contributors.each do |c|
+        file << "* [#{c['login']}](#{c['html_url']})\n" if c['login']
+        file << "* [#{c['name']}](mailto:#{c['email']})\n" if c['name']
+      end
+      url = LinkHeader.parse(response.headers['Link']).find_link(%w(rel next))&.href
+    end
+
+    file << <<~FOOTER
+
+      This document is provided for informational purposes only. Since it is only updated once per release, the version you are looking at may be currently out of date. To see the full list of contributors, consider looking at the [git history](https://github.com/tootsuite/mastodon/graphs/contributors) instead.
+    FOOTER
+  end
+end
diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb
index 97719a606..b4f912717 100644
--- a/spec/controllers/auth/sessions_controller_spec.rb
+++ b/spec/controllers/auth/sessions_controller_spec.rb
@@ -30,6 +30,13 @@ RSpec.describe Auth::SessionsController, type: :controller do
 
         expect(response).to redirect_to(new_user_session_path)
       end
+
+      it 'does not delete redirect location with continue=true' do
+        sign_in(user, scope: :user)
+        controller.store_location_for(:user, '/authorize')
+        delete :destroy, params: { continue: 'true' }
+        expect(controller.stored_location_for(:user)).to eq '/authorize'
+      end
     end
 
     context 'with a suspended user' do
diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb
index 91c2d03ef..a84260a54 100644
--- a/spec/controllers/oauth/authorizations_controller_spec.rb
+++ b/spec/controllers/oauth/authorizations_controller_spec.rb
@@ -5,23 +5,25 @@ require 'rails_helper'
 RSpec.describe Oauth::AuthorizationsController, type: :controller do
   render_views
 
-  let(:app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/') }
+  let(:app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/', scopes: 'read') }
 
   describe 'GET #new' do
     subject do
-      get :new, params: { client_id: app.uid, response_type: 'code', redirect_uri: 'http://localhost/' }
+      get :new, params: { client_id: app.uid, response_type: 'code', redirect_uri: 'http://localhost/', scope: 'read' }
     end
 
     shared_examples 'stores location for user' do
       it 'stores location for user' do
         subject
-        expect(controller.stored_location_for(:user)).to eq "/oauth/authorize?client_id=#{app.uid}&redirect_uri=http%3A%2F%2Flocalhost%2F&response_type=code"
+        expect(controller.stored_location_for(:user)).to eq "/oauth/authorize?client_id=#{app.uid}&redirect_uri=http%3A%2F%2Flocalhost%2F&response_type=code&scope=read"
       end
     end
 
     context 'when signed in' do
+      let!(:user) { Fabricate(:user) }
+
       before do
-        sign_in Fabricate(:user), scope: :user
+        sign_in user, scope: :user
       end
 
       it 'returns http success' do
@@ -35,6 +37,28 @@ RSpec.describe Oauth::AuthorizationsController, type: :controller do
       end
 
       include_examples 'stores location for user'
+
+      context 'when app is already authorized' do
+        before do
+          Doorkeeper::AccessToken.find_or_create_for(
+            app,
+            user.id,
+            app.scopes,
+            Doorkeeper.configuration.access_token_expires_in,
+            Doorkeeper.configuration.refresh_token_enabled?
+          )
+        end
+
+        it 'redirects to callback' do
+          subject
+          expect(response).to redirect_to(/\A#{app.redirect_uri}/)
+        end
+
+        it 'does not redirect to callback with force_login=true' do
+          get :new, params: { client_id: app.uid, response_type: 'code', redirect_uri: 'http://localhost/', scope: 'read', force_login: 'true' }
+          expect(response.body).to match(/Authorize/)
+        end
+      end
     end
 
     context 'when not signed in' do
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index c575128e4..79e80220c 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -29,6 +29,7 @@ Devise::Test::ControllerHelpers.module_eval do
       value: resource.activate_session(warden.request),
       expires: 1.year.from_now,
       httponly: true,
+      same_site: :lax,
     }
   end
 end