about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.env.production.sample4
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock4
-rw-r--r--app/javascript/mastodon/locales/ar.json10
-rw-r--r--app/javascript/mastodon/locales/fi.json20
-rw-r--r--app/javascript/mastodon/locales/sk.json38
-rw-r--r--app/javascript/mastodon/locales/sv.json12
-rw-r--r--app/lib/ostatus/atom_serializer.rb2
-rw-r--r--app/models/user.rb32
-rw-r--r--app/serializers/activitypub/note_serializer.rb2
-rw-r--r--app/serializers/rest/status_serializer.rb6
-rw-r--r--app/views/notification_mailer/_status.html.haml5
-rw-r--r--app/views/notification_mailer/_status.text.erb5
-rw-r--r--app/views/user_mailer/email_changed.html.haml2
-rw-r--r--app/views/user_mailer/email_changed.text.erb2
-rw-r--r--config/application.rb2
-rw-r--r--config/initializers/devise.rb2
-rw-r--r--config/locales/ar.yml3
-rw-r--r--config/locales/es.yml1
-rw-r--r--config/locales/simple_form.fi.yml39
-rw-r--r--config/locales/sk.yml14
-rw-r--r--lib/mastodon/version.rb2
22 files changed, 134 insertions, 77 deletions
diff --git a/.env.production.sample b/.env.production.sample
index 2af3ebb4c..059b314b7 100644
--- a/.env.production.sample
+++ b/.env.production.sample
@@ -158,8 +158,8 @@ STREAMING_CLUSTER_NUM=1
 # The pam environment variable "email" is provided by:
 # https://github.com/devkral/pam_email_extractor
 # PAM_ENABLED=true
-# Fallback Suffix for email address generation (nil by default)
-# PAM_DEFAULT_SUFFIX=pam
+# Fallback email domain for email address generation (LOCAL_DOMAIN by default)
+# PAM_EMAIL_DOMAIN=example.com
 # Name of the pam service (pam "auth" section is evaluated)
 # PAM_DEFAULT_SERVICE=rpam
 # Name of the pam service used for checking if an user can register (pam "account" section is evaluated) (nil (disabled) by default)
diff --git a/Gemfile b/Gemfile
index 22192db4d..195ff6e14 100644
--- a/Gemfile
+++ b/Gemfile
@@ -33,7 +33,9 @@ gem 'cld3', '~> 3.2.0'
 gem 'devise', '~> 4.4'
 gem 'devise-two-factor', '~> 3.0'
 
-gem 'devise_pam_authenticatable2', '~> 8.0', install_if: -> { ENV['PAM_ENABLED'] == 'true' }
+group :pam_authentication, optional: true do
+  gem 'devise_pam_authenticatable2', '~> 9.0'
+end
 gem 'net-ldap', '~> 0.10'
 gem 'omniauth-cas', '~> 1.1'
 gem 'omniauth-saml', '~> 1.10'
diff --git a/Gemfile.lock b/Gemfile.lock
index 693773d36..4ae407f79 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -141,7 +141,7 @@ GEM
       devise (~> 4.0)
       railties (< 5.2)
       rotp (~> 2.0)
-    devise_pam_authenticatable2 (8.0.1)
+    devise_pam_authenticatable2 (9.0.0)
       devise (>= 4.0.0)
       rpam2 (~> 3.0)
     diff-lcs (1.3)
@@ -634,7 +634,7 @@ DEPENDENCIES
   climate_control (~> 0.2)
   devise (~> 4.4)
   devise-two-factor (~> 3.0)
-  devise_pam_authenticatable2 (~> 8.0)
+  devise_pam_authenticatable2 (~> 9.0)
   doorkeeper (~> 4.2)
   dotenv-rails (~> 2.2)
   fabrication (~> 2.18)
diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index 4928930fe..73680a1a1 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -60,10 +60,10 @@
   "compose_form.placeholder": "فيمَ تفكّر؟",
   "compose_form.publish": "بوّق",
   "compose_form.publish_loud": "{publish}!",
-  "compose_form.sensitive.marked": "Media is marked as sensitive",
+  "compose_form.sensitive.marked": "لقد تم تحديد هذه الصورة كحساسة",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
-  "compose_form.spoiler.marked": "Text is hidden behind warning",
-  "compose_form.spoiler.unmarked": "Text is not hidden",
+  "compose_form.spoiler.marked": "إنّ النص مخفي وراء تحذير",
+  "compose_form.spoiler.unmarked": "النص غير مخفي",
   "compose_form.spoiler_placeholder": "تنبيه عن المحتوى",
   "confirmation_modal.cancel": "إلغاء",
   "confirmations.block.confirm": "حجب",
@@ -254,9 +254,9 @@
   "status.sensitive_warning": "محتوى حساس",
   "status.share": "مشاركة",
   "status.show_less": "إعرض أقلّ",
-  "status.show_less_all": "Show less for all",
+  "status.show_less_all": "طي الكل",
   "status.show_more": "أظهر المزيد",
-  "status.show_more_all": "Show more for all",
+  "status.show_more_all": "توسيع الكل",
   "status.unmute_conversation": "فك الكتم عن المحادثة",
   "status.unpin": "فك التدبيس من الملف الشخصي",
   "tabs_bar.federated_timeline": "الموحَّد",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index 1dea42ed4..1741445ed 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -3,7 +3,7 @@
   "account.block_domain": "Piilota kaikki sisältö verkkotunnuksesta {domain}",
   "account.blocked": "Estetty",
   "account.disclaimer_full": "Alla olevat käyttäjän profiilitiedot saattavat olla epätäydellisiä.",
-  "account.domain_blocked": "Domain hidden",
+  "account.domain_blocked": "Verkko-osoite piilotettu",
   "account.edit_profile": "Muokkaa",
   "account.follow": "Seuraa",
   "account.followers": "Seuraajia",
@@ -60,10 +60,10 @@
   "compose_form.placeholder": "Mitä sinulla on mielessä?",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
-  "compose_form.sensitive.marked": "Media is marked as sensitive",
-  "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
-  "compose_form.spoiler.marked": "Text is hidden behind warning",
-  "compose_form.spoiler.unmarked": "Text is not hidden",
+  "compose_form.sensitive.marked": "Media on merkitty arkaluontoiseksi",
+  "compose_form.sensitive.unmarked": "Mediaa ei ole merkitty arkaluontoiseksi",
+  "compose_form.spoiler.marked": "Teksti on piilotettu varoituksen taakse",
+  "compose_form.spoiler.unmarked": "Teksti ei ole piilotettu",
   "compose_form.spoiler_placeholder": "Content warning",
   "confirmation_modal.cancel": "Peruuta",
   "confirmations.block.confirm": "Estä",
@@ -182,13 +182,13 @@
   "onboarding.page_four.notifications": "Ilmoitukset-sarake näyttää sinulle, kun joku on viestii kanssasi.",
   "onboarding.page_one.federation": "Mastodon on yhteisöpalvelu, joka toimii monen itsenäisen palvelimen muodostamassa verkossa. Me kutsumme näitä palvelimia instansseiksi.",
   "onboarding.page_one.full_handle": "Koko käyttäjänimesi",
-  "onboarding.page_one.handle_hint": "This is what you would tell your friends to search for.",
+  "onboarding.page_one.handle_hint": "Tämä on se, mitä voisit ehdottaa ystäviäsi etsimään.",
   "onboarding.page_one.welcome": "Tervetuloa Mastodoniin!",
   "onboarding.page_six.admin": "Instanssisi ylläpitäjä on {admin}.",
   "onboarding.page_six.almost_done": "Melkein valmista...",
   "onboarding.page_six.appetoot": "Bon Appetööt!",
   "onboarding.page_six.apps_available": "{apps} on saatavilla iOS:lle, Androidille ja muille alustoille.",
-  "onboarding.page_six.github": "Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.",
+  "onboarding.page_six.github": "Mastodon on ilmainen, vapaan lähdekoodin ohjelma. Voit raportoida bugeja, pyytää ominaisuuksia tai osallistua kehittämiseen GitHub-palvelussa: {github}.",
   "onboarding.page_six.guidelines": "yhteisön säännöt",
   "onboarding.page_six.read_guidelines": "Ole hyvä ja lue {domain}:n {guidelines}!",
   "onboarding.page_six.various_app": "mobiilisovellukset",
@@ -254,12 +254,12 @@
   "status.sensitive_warning": "Arkaluontoista sisältöä",
   "status.share": "Jaa",
   "status.show_less": "Näytä vähemmän",
-  "status.show_less_all": "Show less for all",
+  "status.show_less_all": "Näytä vähemmän kaikista",
   "status.show_more": "Näytä lisää",
-  "status.show_more_all": "Show more for all",
+  "status.show_more_all": "Näytä enemmän kaikista",
   "status.unmute_conversation": "Poista mykistys keskustelulta",
   "status.unpin": "Irrota profiilista",
-  "tabs_bar.federated_timeline": "Federated",
+  "tabs_bar.federated_timeline": "Yleinen",
   "tabs_bar.home": "Koti",
   "tabs_bar.local_timeline": "Paikallinen",
   "tabs_bar.notifications": "Ilmoitukset",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index 2cb249d2a..683f2aadb 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -18,7 +18,7 @@
   "account.muted": "Utíšený/á",
   "account.posts": "Hlášky",
   "account.posts_with_replies": "Príspevky s odpoveďami",
-  "account.report": "Nahlásiť @{name}",
+  "account.report": "Nahlás @{name}",
   "account.requested": "Čaká na schválenie. Kliknite pre zrušenie žiadosti",
   "account.share": "Zdieľať @{name} profil",
   "account.show_reblogs": "Zobraziť povýšenia od @{name}",
@@ -35,13 +35,13 @@
   "bundle_modal_error.close": "Zatvoriť",
   "bundle_modal_error.message": "Nastala chyba pri načítaní tohto komponentu.",
   "bundle_modal_error.retry": "Skúsiť znova",
-  "column.blocks": "Blokovaní používatelia",
+  "column.blocks": "Blokovaní užívatelia",
   "column.community": "Lokálna časová os",
   "column.favourites": "Obľúbené",
   "column.follow_requests": "Žiadosti o sledovaní",
   "column.home": "Domov",
   "column.lists": "Zoznamy",
-  "column.mutes": "Ignorovaní používatelia",
+  "column.mutes": "Ignorovaní užívatelia",
   "column.notifications": "Notifikácie",
   "column.pins": "Pripnuté toots",
   "column.public": "Federovaná časová os",
@@ -50,20 +50,20 @@
   "column_header.moveLeft_settings": "Presunúť stĺpec doľava",
   "column_header.moveRight_settings": "Presunúť stĺpec doprava",
   "column_header.pin": "Pripnúť",
-  "column_header.show_settings": "Ukázať nastavenia",
+  "column_header.show_settings": "Ukáž nastavenia",
   "column_header.unpin": "Odopnúť",
   "column_subheading.navigation": "Navigácia",
   "column_subheading.settings": "Nastavenia",
-  "compose_form.hashtag_warning": "Tento toot nebude zobrazený pod žiadným haštagom lebo nieje listovaný. Iba verejné toots môžu byť nájdené podľa haštagu.",
+  "compose_form.hashtag_warning": "Tento toot nebude zobrazený pod žiadným haštagom lebo nieje listovaný. Iba verejné tooty môžu byť nájdené podľa haštagu.",
   "compose_form.lock_disclaimer": "Váš účet nie je zamknutý. Ktokoľvek ťa môže nasledovať a vidieť tvoje správy pre sledujúcich.",
   "compose_form.lock_disclaimer.lock": "zamknutý",
   "compose_form.placeholder": "Na čo myslíš?",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
-  "compose_form.sensitive.marked": "Media is marked as sensitive",
-  "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
-  "compose_form.spoiler.marked": "Text is hidden behind warning",
-  "compose_form.spoiler.unmarked": "Text is not hidden",
+  "compose_form.sensitive.marked": "Médiálny obsah je označený ako chúlostivý",
+  "compose_form.sensitive.unmarked": "Médiálny obsah nieje označený ako chúlostivý",
+  "compose_form.spoiler.marked": "Text je ukrytý za varovaním",
+  "compose_form.spoiler.unmarked": "Text nieje ukrytý",
   "compose_form.spoiler_placeholder": "Sem napíšte vaše varovanie",
   "confirmation_modal.cancel": "Zrušiť",
   "confirmations.block.confirm": "Blokovať",
@@ -101,14 +101,14 @@
   "empty_column.list": "Tento zoznam je ešte prázdny. Keď ale členovia tohoto zoznamu napíšu nové správy, tak tie sa objavia priamo tu.",
   "empty_column.notifications": "Nemáte ešte žiadne notifikácie. Napíšte niekomu, následujte niekoho a komunikujte s ostatnými aby diskusia mohla začať.",
   "empty_column.public": "Ešte tu nič nie je. Napíšte niečo verejne alebo začnite sledovať používateľov z iných Mastodon serverov aby tu niečo pribudlo",
-  "follow_request.authorize": "Povoliť prístup",
-  "follow_request.reject": "Odmietnúť",
+  "follow_request.authorize": "Povoľ prístup",
+  "follow_request.reject": "Odmietni",
   "getting_started.appsshort": "Aplikácie",
-  "getting_started.faq": "FAQ",
-  "getting_started.heading": "Začíname",
+  "getting_started.faq": "Časté otázky",
+  "getting_started.heading": "Začni tu",
   "getting_started.open_source_notice": "Mastodon má otvorený kód. Nahlásiť chyby, alebo prispievať vlastným kódom môžete na GitHube v {github}.",
   "getting_started.userguide": "Používateľská príručka",
-  "home.column_settings.advanced": "Rozšírené",
+  "home.column_settings.advanced": "Pokročilé",
   "home.column_settings.basic": "Základné",
   "home.column_settings.filter_regex": "Filtrovať použitím regulárnych výrazov",
   "home.column_settings.show_reblogs": "Zobraziť povýšené",
@@ -147,7 +147,7 @@
   "missing_indicator.label": "Nenájdené",
   "missing_indicator.sublabel": "Tento zdroj sa nepodarilo nájsť",
   "mute_modal.hide_notifications": "Skryť notifikácie od tohoto užívateľa?",
-  "navigation_bar.blocks": "Blokovaní používatelia",
+  "navigation_bar.blocks": "Blokovaní užívatelia",
   "navigation_bar.community_timeline": "Lokálna časová os",
   "navigation_bar.edit_profile": "Upraviť profil",
   "navigation_bar.favourites": "Obľúbené",
@@ -156,9 +156,9 @@
   "navigation_bar.keyboard_shortcuts": "Klávesové skratky",
   "navigation_bar.lists": "Zoznamy",
   "navigation_bar.logout": "Odhlásiť",
-  "navigation_bar.mutes": "Ignorovaní používatelia",
+  "navigation_bar.mutes": "Ignorovaní užívatelia",
   "navigation_bar.pins": "Pripnuté toots",
-  "navigation_bar.preferences": "Možnosti",
+  "navigation_bar.preferences": "Voľby",
   "navigation_bar.public_timeline": "Federovaná časová os",
   "notification.favourite": "{name} sa páči tvoj status",
   "notification.follow": "{name} ťa začal/a následovať",
@@ -254,9 +254,9 @@
   "status.sensitive_warning": "Chúlostivý obsah",
   "status.share": "Zdieľať",
   "status.show_less": "Zobraz menej",
-  "status.show_less_all": "Show less for all",
+  "status.show_less_all": "Všetkým ukáž menej",
   "status.show_more": "Zobraz viac",
-  "status.show_more_all": "Show more for all",
+  "status.show_more_all": "Všetkým ukáž viac",
   "status.unmute_conversation": "Prestať ignorovať konverzáciu",
   "status.unpin": "Odopnúť z profilu",
   "tabs_bar.federated_timeline": "Federovaná",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 3451212d0..4fa129173 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -60,10 +60,10 @@
   "compose_form.placeholder": "Vad funderar du på?",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
-  "compose_form.sensitive.marked": "Media is marked as sensitive",
-  "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
-  "compose_form.spoiler.marked": "Text is hidden behind warning",
-  "compose_form.spoiler.unmarked": "Text is not hidden",
+  "compose_form.sensitive.marked": "Media har markerats som känsligt",
+  "compose_form.sensitive.unmarked": "Media har inte markerats som känsligt",
+  "compose_form.spoiler.marked": "Texten har dolts bakom en varning",
+  "compose_form.spoiler.unmarked": "Texten är inte dold",
   "compose_form.spoiler_placeholder": "Skriv din varning här",
   "confirmation_modal.cancel": "Ångra",
   "confirmations.block.confirm": "Blockera",
@@ -254,9 +254,9 @@
   "status.sensitive_warning": "Känsligt innehåll",
   "status.share": "Dela",
   "status.show_less": "Visa mindre",
-  "status.show_less_all": "Show less for all",
+  "status.show_less_all": "Visa mindre för alla",
   "status.show_more": "Visa mer",
-  "status.show_more_all": "Show more for all",
+  "status.show_more_all": "Visa mer för alla",
   "status.unmute_conversation": "Öppna konversation",
   "status.unpin": "Ångra fäst i profil",
   "tabs_bar.federated_timeline": "Förenad",
diff --git a/app/lib/ostatus/atom_serializer.rb b/app/lib/ostatus/atom_serializer.rb
index 656e45822..46d0a8b37 100644
--- a/app/lib/ostatus/atom_serializer.rb
+++ b/app/lib/ostatus/atom_serializer.rb
@@ -351,7 +351,7 @@ class OStatus::AtomSerializer
     append_element(entry, 'summary', status.spoiler_text, 'xml:lang': status.language) if status.spoiler_text?
     append_element(entry, 'content', Formatter.instance.format(status).to_str, type: 'html', 'xml:lang': status.language)
 
-    status.mentions.each do |mentioned|
+    status.mentions.order(:id).each do |mentioned|
       append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': OStatus::TagManager::TYPES[:person], href: OStatus::TagManager.instance.uri_for(mentioned.account))
     end
 
diff --git a/app/models/user.rb b/app/models/user.rb
index 0346cf8ae..803eb8a33 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -52,6 +52,8 @@ class User < ApplicationRecord
   devise :registerable, :recoverable, :rememberable, :trackable, :validatable,
          :confirmable
 
+  devise :pam_authenticatable if ENV['PAM_ENABLED'] == 'true'
+
   devise :omniauthable
 
   belongs_to :account, inverse_of: :user
@@ -96,7 +98,7 @@ class User < ApplicationRecord
 
   def pam_conflict?
     return false unless Devise.pam_authentication
-    encrypted_password.present? && is_pam_account?
+    encrypted_password.present? && pam_managed_user?
   end
 
   def pam_get_name
@@ -267,22 +269,22 @@ class User < ApplicationRecord
   end
 
   def self.pam_get_user(attributes = {})
-    if attributes[:email]
-      resource =
-        if Devise.check_at_sign && !attributes[:email].index('@')
-          joins(:account).find_by(accounts: { username: attributes[:email] })
-        else
-          find_by(email: attributes[:email])
-        end
-
-      if resource.blank?
-        resource = new(email: attributes[:email])
-        if Devise.check_at_sign && !resource[:email].index('@')
-          resource[:email] = "#{attributes[:email]}@#{resource.find_pam_suffix}"
-        end
+    return nil unless attributes[:email]
+    resource =
+      if Devise.check_at_sign && !attributes[:email].index('@')
+        joins(:account).find_by(accounts: { username: attributes[:email] })
+      else
+        find_by(email: attributes[:email])
+      end
+
+    if resource.blank?
+      resource = new(email: attributes[:email])
+      if Devise.check_at_sign && !resource[:email].index('@')
+        resource[:email] = Rpam2.getenv(resource.find_pam_service, attributes[:email], attributes[:password], 'email', false)
+        resource[:email] = "#{attributes[:email]}@#{resource.find_pam_suffix}" unless resource[:email]
       end
-      resource
     end
+    resource
   end
 
   def self.ldap_get_user(attributes = {})
diff --git a/app/serializers/activitypub/note_serializer.rb b/app/serializers/activitypub/note_serializer.rb
index d0e6290c1..abaf29047 100644
--- a/app/serializers/activitypub/note_serializer.rb
+++ b/app/serializers/activitypub/note_serializer.rb
@@ -57,7 +57,7 @@ class ActivityPub::NoteSerializer < ActiveModel::Serializer
   end
 
   def virtual_tags
-    object.mentions + object.tags + object.emojis
+    object.mentions.order(:id) + object.tags + object.emojis
   end
 
   def atom_uri
diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb
index e6270f902..67da92cd5 100644
--- a/app/serializers/rest/status_serializer.rb
+++ b/app/serializers/rest/status_serializer.rb
@@ -15,7 +15,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
   belongs_to :account, serializer: REST::AccountSerializer
 
   has_many :media_attachments, serializer: REST::MediaAttachmentSerializer
-  has_many :mentions
+  has_many :ordered_mentions, key: :mentions
   has_many :tags
   has_many :emojis, serializer: REST::CustomEmojiSerializer
 
@@ -86,6 +86,10 @@ class REST::StatusSerializer < ActiveModel::Serializer
       %w(public unlisted).include?(object.visibility)
   end
 
+  def ordered_mentions
+    object.mentions.order(:id)
+  end
+
   class ApplicationSerializer < ActiveModel::Serializer
     attributes :name, :website
   end
diff --git a/app/views/notification_mailer/_status.html.haml b/app/views/notification_mailer/_status.html.haml
index f82ada146..57b5688bd 100644
--- a/app/views/notification_mailer/_status.html.haml
+++ b/app/views/notification_mailer/_status.html.haml
@@ -24,6 +24,11 @@
                                       %bdi= display_name(status.account)
                                       = "@#{status.account.acct}"
 
+                              - if status.spoiler_text?
+                                %div{ dir: rtl_status?(status) ? 'rtl' : 'ltr' }
+                                  %p
+                                    = Formatter.instance.format_spoiler(status)
+
                               %div{ dir: rtl_status?(status) ? 'rtl' : 'ltr' }
                                 = Formatter.instance.format(status)
 
diff --git a/app/views/notification_mailer/_status.text.erb b/app/views/notification_mailer/_status.text.erb
index 85a0136b7..8999a1f8e 100644
--- a/app/views/notification_mailer/_status.text.erb
+++ b/app/views/notification_mailer/_status.text.erb
@@ -1,3 +1,8 @@
+<% if status.spoiler_text? %>
+<%= raw status.spoiler_text %>
+----
+
+<% end %>
 <%= raw Formatter.instance.plaintext(status) %>
 
 <%= raw t('application_mailer.view')%> <%= web_url("statuses/#{status.id}") %>
diff --git a/app/views/user_mailer/email_changed.html.haml b/app/views/user_mailer/email_changed.html.haml
index 7e82f23e4..0802aaf96 100644
--- a/app/views/user_mailer/email_changed.html.haml
+++ b/app/views/user_mailer/email_changed.html.haml
@@ -38,7 +38,7 @@
                           %table.input{ align: 'center', cellspacing: 0, cellpadding: 0 }
                             %tbody
                               %tr
-                                %td= @resource.unconfirmed_email
+                                %td= @resource.try(:unconfirmed_email) ? @resource.unconfirmed_email : @resource.email
 
 %table.email-table{ cellspacing: 0, cellpadding: 0 }
   %tbody
diff --git a/app/views/user_mailer/email_changed.text.erb b/app/views/user_mailer/email_changed.text.erb
index 2b58415f5..345b16a2c 100644
--- a/app/views/user_mailer/email_changed.text.erb
+++ b/app/views/user_mailer/email_changed.text.erb
@@ -4,6 +4,6 @@
 
 <%= t 'devise.mailer.email_changed.explanation' %>
 
-<%= @resource.unconfirmed_email %>
+<%= @resource.try(:unconfirmed_email) ? @resource.unconfirmed_email : @resource.email %>
 
 <%= t 'devise.mailer.email_changed.extra' %>
diff --git a/config/application.rb b/config/application.rb
index f63746e34..4319167dc 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -17,6 +17,8 @@ require_relative '../lib/devise/ldap_authenticatable'
 
 Dotenv::Railtie.load
 
+Bundler.require(:pam_authentication) if ENV['PAM_ENABLED'] == 'true'
+
 require_relative '../lib/mastodon/redis_config'
 
 module Mastodon
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index df45dcd1f..97757d0fb 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -342,7 +342,7 @@ Devise.setup do |config|
     config.usernamefield          = nil
     config.emailfield             = 'email'
     config.check_at_sign          = true
-    config.pam_default_suffix     = ENV.fetch('PAM_DEFAULT_SUFFIX') { nil }
+    config.pam_default_suffix     = ENV.fetch('PAM_EMAIL_DOMAIN') { ENV['LOCAL_DOMAIN'] }
     config.pam_default_service    = ENV.fetch('PAM_DEFAULT_SERVICE') { 'rpam' }
     config.pam_controlled_service = ENV.fetch('PAM_CONTROLLED_SERVICE') { nil }
   end
diff --git a/config/locales/ar.yml b/config/locales/ar.yml
index ad674a346..e6447cab3 100644
--- a/config/locales/ar.yml
+++ b/config/locales/ar.yml
@@ -513,6 +513,8 @@ ar:
     over_character_limit: تم تجاوز حد الـ %{max} حرف المسموح بها
     pin_errors:
       ownership: لا يمكن تدبيس تبويق نشره شخص آخر
+      private: لا يمكن تثبيت تبويق لم يُنشر للعامة
+      reblog: لا يمكن تثبيت ترقية
     show_more: أظهر المزيد
     title: '%{name} : "%{quote}"'
     visibilities:
@@ -524,6 +526,7 @@ ar:
       unlisted_long: يُمكن لأيٍ كان رُؤيتَه و لكن لن يُعرَض على الخيوط العامة
   stream_entries:
     click_to_show: إضغط للعرض
+    pinned: تبويق مثبّت
     reblogged: رقى
     sensitive_content: محتوى حساس
   terms:
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 13c3e235a..199253d6f 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -275,6 +275,7 @@ es:
         username: Nombre de usuario
       hero:
         desc_html: Mostrado en la página principal. Recomendable al menos 600x100px. Por defecto se establece a la miniatura de la instancia
+        title: Imagen de portada
       peers_api_enabled:
         desc_html: Nombres de dominio que esta instancia ha encontrado en el fediverso
         title: Publicar lista de instancias descubiertas
diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml
index a5cded1ce..34605c4f6 100644
--- a/config/locales/simple_form.fi.yml
+++ b/config/locales/simple_form.fi.yml
@@ -4,13 +4,19 @@ fi:
     hints:
       defaults:
         avatar: PNG, GIF tai JPG. Korkeintaan 2MB. Skaalataan kokoon 400x400px
-        digest: Lähetetään vain pitkän poissaolon jälkeen, ja vain jos olet vastaanottanut yksityisviestejä poissaolosi aikana.
+        digest: Lähetetään vain pitkän poissaolon jälkeen, ja vain jos olet vastaanottanut yksityisviestejä poissaolosi aikana
         display_name: Korkeintaan 30 merkkiä
         header: PNG, GIF tai JPG. Korkeintaan 2MB. Skaalataan kokoon 700x335px
-        locked: Vaatii sinun manuaalisesti hyväksymään seuraajat, ja asettaa julkaisujen yksityisyyden vain seuraajille
+        locked: Vaatii sinua manuaalisesti hyväksymään seuraajat
         note: Korkeintaan 160 merkkiä
+        setting_noindex: Vaikuttaa julkiseen profiiliisi ja statuspäivityksiisi
+        setting_theme: Vaikuttaa siihen, miltä Mastodon näyttää kun olet kirjautuneena milllä tahansa laitteella.
       imports:
-        data: CSV tiedosto tuotu toiselta Mastodon palvelimelta
+        data: CSV tiedosto, joka on tuotu toiselta Mastodon-palvelimelta
+      sessions:
+        otp: Syötä kaksivaiheisen tunnistuksen koodi puhelimestasi tai käytä yhtä palautuskoodeistasi.
+      user:
+        filtered_languages: Valitut kielet suodatetaan julkisilta aikajanoilta
     labels:
       defaults:
         avatar: Profiilikuva
@@ -18,22 +24,37 @@ fi:
         confirm_password: Varmista salasana
         current_password: Nykyinen salasana
         data: Data
-        display_name: Näykyvä nimi
+        display_name: Nimimerkki
         email: Sähköpostiosoite
-        header: Otsake
+        expires_in: Vanhentuu
+        filtered_languages: Suodatetut kielet
+        header: Otsakekuva
         locale: Kieli
         locked: Tee tilistä yksityinen
         max_uses: Max käyttökerrat
         new_password: Uusi salasana
-        note: Bio
+        note: Kuvaus
         otp_attempt: Kaksivaiheinen koodi
         password: Salasana
+        setting_auto_play_gif: Animoitujen GIFfien automaattitoisto
+        setting_boost_modal: Näytä vahvistusikkuna ennen boostausta
         setting_default_privacy: Julkaisun yksityisyys
+        setting_default_sensitive: Merkitse media aina arkaluontoiseksi
+        setting_delete_modal: Näytä vahvistusikkuna ennen töötin poistamista
+        setting_display_sensitive_media: Näytä aina arkaluontoiseksi merkitty media
+        setting_noindex: Jättäydy pois hakukoneindeksoinnista
+        setting_reduce_motion: Vähennä liikettä animaatioissa
+        setting_system_font_ui: Käytä käyttöjärjestelmän oletusfonttia
+        setting_theme: Sivuston teema
+        setting_unfollow_modal: Näytä vahvistusikkuna ennen seuraamisen lopettamista
+        severity: Vakavuusaste
         type: Tuontityyppi
         username: Käyttäjänimi
+        username_or_email: Käyttäjänimi tai sähköposti
       interactions:
-        must_be_follower: Estä ilmoitukset käyttäjiltä jotka eivät seuraa sinua
-        must_be_following: Estä ilmoitukset käyttäjiltä joita et seuraa
+        must_be_follower: Estä ilmoitukset käyttäjiltä, jotka eivät seuraa sinua
+        must_be_following: Estä ilmoitukset käyttäjiltä, joita et seuraa
+        must_be_following_dm: Estä suorat viestit ihmisiltä, joita et seuraa
       notification_emails:
         digest: Lähetä koosteviestejä sähköpostilla
         favourite: Lähetä sähköposti, kun joku tykkää statuksestasi
@@ -44,5 +65,5 @@ fi:
     'no': Ei
     required:
       mark: "*"
-      text: vaaditaan
+      text: pakollinen tieto
     'yes': Kyllä
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index dd8120193..e391974c6 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -593,7 +593,7 @@ sk:
     title: Sezóna
   settings:
     authorized_apps: Autorizované aplikácie
-    back: Naspäť na stránku
+    back: Späť do Mastodonu
     delete: Zmazanie účtu
     development: Vývoj
     edit_profile: Upraviť profil
@@ -630,8 +630,15 @@ sk:
     title: Podmienky užívania, a pravidlá o súkromí pre %{instance}
   two_factor_authentication:
     enable: Povoliť
+    enabled: Dvoj-faktorové overovanie je povolené
+    enabled_success: Dvoj-faktorové overovanie bolo úspešne povolené
     generate_recovery_codes: Vygeneruj zálohové kódy
+    lost_recovery_codes: Zálohové kódy ti umožnia dostať sa k svojmu účtu ak stratíš telefón. Pokiaľ si stratila svoje zálohové kódy, môžeš si ich tu znovu vygenerovať. Tvoje staré zálohové kódy budú zneplatnené.
+    manual_instructions: 'Pokiaľ nemôžeš oskenovať daný QR kód, a potrebuješ ho zadať ručne, tu je tajomstvo v textovom formáte:'
+    recovery_codes: Zálohuj kódy pre obnovu
+    recovery_codes_regenerated: Zálohové kódy boli úspešne zvova vygenerované
     setup: Nastavenie
+    wrong_code: Zadaný kód bol neplatný. Je serverový čas a čas na zariadení správny?
   user_mailer:
     backup_ready:
       explanation: Vyžiadal/a si si úplnú zálohu tvojho Mastodon účtu. Táto záloha je teraz pripravená na stiahnutie!
@@ -639,12 +646,17 @@ sk:
       title: Odber archívu
     welcome:
       edit_profile_action: Nastav profil
+      edit_profile_step: Profil si môžeš prispôsobiť nahratím portrétu a hlavičky, môžeš upraviť svoje meno a viac. Pokiaľ chceš preverovať nových následovateľov predtým než ťa budú môcť sledovať, môžeš uzamknúť svoj účet.
       explanation: Tu nájdeš nejaké tipy do začiatku
       final_action: Začni prispievať
       final_step: 'Začnite písať! Aj bez následovníkov budú vaše verejné správy videné ostatnými, napríklad na lokálnej osi a pod haštagmi. Môžete sa ostatným predstaviť pod haštagom #introductions.'
       full_handle: Adresa tvojho profilu v celom formáte
+      full_handle_hint: Toto je čo musíš dať vedieť svojím priateľom aby ti mohli posielať správy, alebo ťa následovať z inej instancie.
       review_preferences_action: Zmeniť nastavenia
       subject: Vitaj na Mastodone
+      tip_bridge_html: Ak prichádzaš z Twitteru, môžeš svojích priateľov nájsť na Mastodone pomocou tzv. <a href="%{bridge_url}">mostíkovej aplikácie</a>. Ale tá funguje iba ak ju aj oni niekedy použili!
+      tip_federated_timeline: Federovaná os zobrazuje sieť Mastodonu až po jej hranice. Ale zahŕňa iba ľúdí ktorých ostatní okolo teba sledujú, takže predsa nieje úplne celistvá.
+      tip_following: Správcu servera následuješ automaticky. Môžeš ale nájsť mnoho iných zaujímavých ľudí ak prezrieš tak lokálnu, ako aj globálne federovanú os.
       tip_local_timeline: Lokálna os je celkový pohľad na aktivitu užívateľov %{instance}. Toto sú tvoji najbližší susedia!
       tip_mobile_webapp: Pokiaľ ti prehliadač ponúkne možnosť pridať Mastodon na tvoju obrazovku, môžeš potom dostávať notifikácie skoro ako z natívnej aplikácie!
       tips: Tipy
diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb
index fefe63276..78a2dd901 100644
--- a/lib/mastodon/version.rb
+++ b/lib/mastodon/version.rb
@@ -21,7 +21,7 @@ module Mastodon
     end
 
     def flags
-      'rc2'
+      'rc3'
     end
 
     def to_a