diff --git a/.github/stylelint-matcher.json b/.github/stylelint-matcher.json deleted file mode 100644 index cdfd4086bd..0000000000 --- a/.github/stylelint-matcher.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "problemMatcher": [ - { - "owner": "stylelint", - "pattern": [ - { - "regexp": "^([^\\s].*)$", - "file": 1 - }, - { - "regexp": "^\\s+((\\d+):(\\d+))?\\s+(✖|×)\\s+(.*)\\s{2,}(.*)$", - "line": 2, - "column": 3, - "message": 5, - "code": 6, - "loop": true - } - ] - } - ] -} diff --git a/.github/workflows/lint-css.yml b/.github/workflows/lint-css.yml index e5f4874877..d3b8035cd8 100644 --- a/.github/workflows/lint-css.yml +++ b/.github/workflows/lint-css.yml @@ -38,9 +38,5 @@ jobs: - name: Set up Javascript environment uses: ./.github/actions/setup-javascript - - uses: xt0rted/stylelint-problem-matcher@v1 - - - run: echo "::add-matcher::.github/stylelint-matcher.json" - - name: Stylelint - run: yarn lint:css + run: yarn lint:css -f github diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 6570d143c6..0b6f63ff7e 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -42,14 +42,6 @@ RSpec/MultipleMemoizedHelpers: RSpec/NestedGroups: Max: 6 -# Configuration parameters: Include. -# Include: app/models/**/*.rb -Rails/HasAndBelongsToMany: - Exclude: - - 'app/models/concerns/account/associations.rb' - - 'app/models/status.rb' - - 'app/models/tag.rb' - Rails/OutputSafety: Exclude: - 'config/initializers/simple_form.rb' diff --git a/Gemfile b/Gemfile index a10613b30b..eb507e9d18 100644 --- a/Gemfile +++ b/Gemfile @@ -31,7 +31,7 @@ gem 'browser' gem 'charlock_holmes', '~> 0.7.7' gem 'chewy', '~> 7.3' gem 'devise', '~> 4.9' -gem 'devise-two-factor', '~> 4.1' +gem 'devise-two-factor' group :pam_authentication, optional: true do gem 'devise_pam_authenticatable2', '~> 9.2' diff --git a/Gemfile.lock b/Gemfile.lock index 3394930e0d..cb36bc2ddc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -97,8 +97,6 @@ GEM activerecord (>= 3.2, < 8.0) rake (>= 10.4, < 14.0) ast (2.4.2) - attr_encrypted (4.0.0) - encryptor (~> 3.0.0) attr_required (1.0.2) awrence (1.2.1) aws-eventstream (1.3.0) @@ -204,9 +202,8 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) - devise-two-factor (4.1.1) + devise-two-factor (5.0.0) activesupport (~> 7.0) - attr_encrypted (>= 1.3, < 5, != 2) devise (~> 4.0) railties (~> 7.0) rotp (~> 6.0) @@ -236,7 +233,6 @@ GEM htmlentities (~> 4.3.3) launchy (~> 2.1) mail (~> 2.7) - encryptor (3.0.0) erubi (1.12.0) et-orbi (1.2.11) tzinfo @@ -655,8 +651,8 @@ GEM rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.31.2) - parser (>= 3.3.0.4) + rubocop-ast (1.31.3) + parser (>= 3.3.1.0) rubocop-capybara (2.20.0) rubocop (~> 1.41) rubocop-factory_bot (2.25.1) @@ -669,7 +665,7 @@ GEM rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (2.29.1) + rubocop-rspec (2.29.2) rubocop (~> 1.40) rubocop-capybara (~> 2.17) rubocop-factory_bot (~> 2.22) @@ -842,7 +838,7 @@ DEPENDENCIES database_cleaner-active_record debug (~> 1.8) devise (~> 4.9) - devise-two-factor (~> 4.1) + devise-two-factor devise_pam_authenticatable2 (~> 9.2) discard (~> 1.2) doorkeeper (~> 5.6) diff --git a/app/controllers/api/v1/admin/domain_blocks_controller.rb b/app/controllers/api/v1/admin/domain_blocks_controller.rb index b589d277d5..ae94ac59cd 100644 --- a/app/controllers/api/v1/admin/domain_blocks_controller.rb +++ b/app/controllers/api/v1/admin/domain_blocks_controller.rb @@ -29,10 +29,11 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController def create authorize :domain_block, :create? + @domain_block = DomainBlock.new(resource_params) existing_domain_block = resource_params[:domain].present? ? DomainBlock.rule_for(resource_params[:domain]) : nil - return render json: existing_domain_block, serializer: REST::Admin::ExistingDomainBlockErrorSerializer, status: 422 if existing_domain_block.present? + return render json: existing_domain_block, serializer: REST::Admin::ExistingDomainBlockErrorSerializer, status: 422 if conflicts_with_existing_block?(@domain_block, existing_domain_block) - @domain_block = DomainBlock.create!(resource_params) + @domain_block.save! DomainBlockWorker.perform_async(@domain_block.id) log_action :create, @domain_block render json: @domain_block, serializer: REST::Admin::DomainBlockSerializer @@ -55,6 +56,10 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController private + def conflicts_with_existing_block?(domain_block, existing_domain_block) + existing_domain_block.present? && (existing_domain_block.domain == TagManager.instance.normalize_domain(domain_block.domain) || !domain_block.stricter_than?(existing_domain_block)) + end + def set_domain_blocks @domain_blocks = filtered_domain_blocks.order(id: :desc).to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id)) end diff --git a/app/javascript/entrypoints/two_factor_authentication.js b/app/javascript/entrypoints/two_factor_authentication.js deleted file mode 100644 index e77965c757..0000000000 --- a/app/javascript/entrypoints/two_factor_authentication.js +++ /dev/null @@ -1,119 +0,0 @@ -import * as WebAuthnJSON from '@github/webauthn-json'; -import axios from 'axios'; - -import ready from '../mastodon/ready'; -import 'regenerator-runtime/runtime'; - -function getCSRFToken() { - var CSRFSelector = document.querySelector('meta[name="csrf-token"]'); - if (CSRFSelector) { - return CSRFSelector.getAttribute('content'); - } else { - return null; - } -} - -function hideFlashMessages() { - Array.from(document.getElementsByClassName('flash-message')).forEach(function(flashMessage) { - flashMessage.classList.add('hidden'); - }); -} - -function callback(url, body) { - axios.post(url, JSON.stringify(body), { - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'X-CSRF-Token': getCSRFToken(), - }, - credentials: 'same-origin', - }).then(function(response) { - window.location.replace(response.data.redirect_path); - }).catch(function(error) { - if (error.response.status === 422) { - const errorMessage = document.getElementById('security-key-error-message'); - errorMessage.classList.remove('hidden'); - console.error(error.response.data.error); - } else { - console.error(error); - } - }); -} - -ready(() => { - if (!WebAuthnJSON.supported()) { - const unsupported_browser_message = document.getElementById('unsupported-browser-message'); - if (unsupported_browser_message) { - unsupported_browser_message.classList.remove('hidden'); - document.querySelector('.btn.js-webauthn').disabled = true; - } - } - - - const webAuthnCredentialRegistrationForm = document.getElementById('new_webauthn_credential'); - if (webAuthnCredentialRegistrationForm) { - webAuthnCredentialRegistrationForm.addEventListener('submit', (event) => { - event.preventDefault(); - - var nickname = event.target.querySelector('input[name="new_webauthn_credential[nickname]"]'); - if (nickname.value) { - axios.get('/settings/security_keys/options') - .then((response) => { - const credentialOptions = response.data; - - WebAuthnJSON.create({ 'publicKey': credentialOptions }).then((credential) => { - var params = { 'credential': credential, 'nickname': nickname.value }; - callback('/settings/security_keys', params); - }).catch((error) => { - const errorMessage = document.getElementById('security-key-error-message'); - errorMessage.classList.remove('hidden'); - console.error(error); - }); - }).catch((error) => { - console.error(error.response.data.error); - }); - } else { - nickname.focus(); - } - }); - } - - const webAuthnCredentialAuthenticationForm = document.getElementById('webauthn-form'); - if (webAuthnCredentialAuthenticationForm) { - webAuthnCredentialAuthenticationForm.addEventListener('submit', (event) => { - event.preventDefault(); - - axios.get('sessions/security_key_options') - .then((response) => { - const credentialOptions = response.data; - - WebAuthnJSON.get({ 'publicKey': credentialOptions }).then((credential) => { - var params = { 'user': { 'credential': credential } }; - callback('sign_in', params); - }).catch((error) => { - const errorMessage = document.getElementById('security-key-error-message'); - errorMessage.classList.remove('hidden'); - console.error(error); - }); - }).catch((error) => { - console.error(error.response.data.error); - }); - }); - - const otpAuthenticationForm = document.getElementById('otp-authentication-form'); - - const linkToOtp = document.getElementById('link-to-otp'); - linkToOtp.addEventListener('click', () => { - webAuthnCredentialAuthenticationForm.classList.add('hidden'); - otpAuthenticationForm.classList.remove('hidden'); - hideFlashMessages(); - }); - - const linkToWebAuthn = document.getElementById('link-to-webauthn'); - linkToWebAuthn.addEventListener('click', () => { - otpAuthenticationForm.classList.add('hidden'); - webAuthnCredentialAuthenticationForm.classList.remove('hidden'); - hideFlashMessages(); - }); - } -}); diff --git a/app/javascript/entrypoints/two_factor_authentication.ts b/app/javascript/entrypoints/two_factor_authentication.ts new file mode 100644 index 0000000000..981481694b --- /dev/null +++ b/app/javascript/entrypoints/two_factor_authentication.ts @@ -0,0 +1,197 @@ +import * as WebAuthnJSON from '@github/webauthn-json'; +import axios, { AxiosError } from 'axios'; + +import ready from '../mastodon/ready'; + +import 'regenerator-runtime/runtime'; + +type PublicKeyCredentialCreationOptionsJSON = + WebAuthnJSON.CredentialCreationOptionsJSON['publicKey']; + +function exceptionHasAxiosError( + error: unknown, +): error is AxiosError<{ error: unknown }> { + return ( + error instanceof AxiosError && + typeof error.response?.data === 'object' && + 'error' in error.response.data + ); +} + +function logAxiosResponseError(error: unknown) { + if (exceptionHasAxiosError(error)) console.error(error); +} + +function getCSRFToken() { + return document + .querySelector('meta[name="csrf-token"]') + ?.getAttribute('content'); +} + +function hideFlashMessages() { + document.querySelectorAll('.flash-message').forEach((flashMessage) => { + flashMessage.classList.add('hidden'); + }); +} + +async function callback( + url: string, + body: + | { + credential: WebAuthnJSON.PublicKeyCredentialWithAttestationJSON; + nickname: string; + } + | { + user: { credential: WebAuthnJSON.PublicKeyCredentialWithAssertionJSON }; + }, +) { + try { + const response = await axios.post<{ redirect_path: string }>( + url, + JSON.stringify(body), + { + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + 'X-CSRF-Token': getCSRFToken(), + }, + }, + ); + + window.location.replace(response.data.redirect_path); + } catch (error) { + if (error instanceof AxiosError && error.response?.status === 422) { + const errorMessage = document.getElementById( + 'security-key-error-message', + ); + errorMessage?.classList.remove('hidden'); + + logAxiosResponseError(error); + } else { + console.error(error); + } + } +} + +async function handleWebauthnCredentialRegistration(nickname: string) { + try { + const response = await axios.get( + '/settings/security_keys/options', + ); + + const credentialOptions = response.data; + + try { + const credential = await WebAuthnJSON.create({ + publicKey: credentialOptions, + }); + + const params = { + credential: credential, + nickname: nickname, + }; + + await callback('/settings/security_keys', params); + } catch (error) { + const errorMessage = document.getElementById( + 'security-key-error-message', + ); + errorMessage?.classList.remove('hidden'); + console.error(error); + } + } catch (error) { + logAxiosResponseError(error); + } +} + +async function handleWebauthnCredentialAuthentication() { + try { + const response = await axios.get( + 'sessions/security_key_options', + ); + + const credentialOptions = response.data; + + try { + const credential = await WebAuthnJSON.get({ + publicKey: credentialOptions, + }); + + const params = { user: { credential: credential } }; + void callback('sign_in', params); + } catch (error) { + const errorMessage = document.getElementById( + 'security-key-error-message', + ); + errorMessage?.classList.remove('hidden'); + console.error(error); + } + } catch (error) { + logAxiosResponseError(error); + } +} + +ready(() => { + if (!WebAuthnJSON.supported()) { + const unsupported_browser_message = document.getElementById( + 'unsupported-browser-message', + ); + if (unsupported_browser_message) { + unsupported_browser_message.classList.remove('hidden'); + const button = document.querySelector( + 'button.btn.js-webauthn', + ); + if (button) button.disabled = true; + } + } + + const webAuthnCredentialRegistrationForm = + document.querySelector('form#new_webauthn_credential'); + if (webAuthnCredentialRegistrationForm) { + webAuthnCredentialRegistrationForm.addEventListener('submit', (event) => { + event.preventDefault(); + + if (!(event.target instanceof HTMLFormElement)) return; + + const nickname = event.target.querySelector( + 'input[name="new_webauthn_credential[nickname]"]', + ); + + if (nickname?.value) { + void handleWebauthnCredentialRegistration(nickname.value); + } else { + nickname?.focus(); + } + }); + } + + const webAuthnCredentialAuthenticationForm = + document.getElementById('webauthn-form'); + if (webAuthnCredentialAuthenticationForm) { + webAuthnCredentialAuthenticationForm.addEventListener('submit', (event) => { + event.preventDefault(); + void handleWebauthnCredentialAuthentication(); + }); + + const otpAuthenticationForm = document.getElementById( + 'otp-authentication-form', + ); + + const linkToOtp = document.getElementById('link-to-otp'); + + linkToOtp?.addEventListener('click', () => { + webAuthnCredentialAuthenticationForm.classList.add('hidden'); + otpAuthenticationForm?.classList.remove('hidden'); + hideFlashMessages(); + }); + + const linkToWebAuthn = document.getElementById('link-to-webauthn'); + linkToWebAuthn?.addEventListener('click', () => { + otpAuthenticationForm?.classList.add('hidden'); + webAuthnCredentialAuthenticationForm.classList.remove('hidden'); + hideFlashMessages(); + }); + } +}).catch((e: unknown) => { + throw e; +}); diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 1b969639dc..d30038d9cc 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Benque tu conto non es serrate, le personal de {domain} pensa que es un bon idea que tu revide manualmente le sequente requestas de iste contos.", "follow_suggestions.curated_suggestion": "Selection del equipa", "follow_suggestions.dismiss": "Non monstrar novemente", + "follow_suggestions.featured_longer": "Seligite con cura per le equipa de {domain}", + "follow_suggestions.friends_of_friends_longer": "Popular inter le gente que tu seque", "follow_suggestions.hints.featured": "Iste profilo ha essite seligite manualmente per le equipa de {domain}.", "follow_suggestions.hints.friends_of_friends": "Iste profilo es popular inter le gente que tu seque.", "follow_suggestions.hints.most_followed": "Iste profilo es un del plus sequites sur {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Iste profilo es similar al profilos que tu ha recentemente sequite.", "follow_suggestions.personalized_suggestion": "Suggestion personalisate", "follow_suggestions.popular_suggestion": "Suggestion personalisate", + "follow_suggestions.popular_suggestion_longer": "Popular sur {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Similar al profilos que tu ha sequite recentemente", "follow_suggestions.view_all": "Vider toto", "follow_suggestions.who_to_follow": "Qui sequer", "followed_tags": "Hashtags sequite", @@ -470,6 +474,14 @@ "notification.follow_request": "{name} ha requestate de sequer te", "notification.mention": "{name} te ha mentionate", "notification.moderation-warning.learn_more": "Apprender plus", + "notification.moderation_warning": "Tu ha recipite un advertimento de moderation", + "notification.moderation_warning.action_delete_statuses": "Alcunes de tu messages ha essite removite.", + "notification.moderation_warning.action_disable": "Tu conto ha essite disactivate.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Alcunes de tu messages ha essite marcate como sensibile.", + "notification.moderation_warning.action_none": "Tu conto ha recipite un advertimento de moderation.", + "notification.moderation_warning.action_sensitive": "Tu messages essera marcate como sensibile a partir de ora.", + "notification.moderation_warning.action_silence": "Tu conto ha essite limitate.", + "notification.moderation_warning.action_suspend": "Tu conto ha essite suspendite.", "notification.own_poll": "Tu sondage ha finite", "notification.poll": "Un sondage in le qual tu ha votate ha finite", "notification.reblog": "{name} ha impulsate tu message", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 6bda11058f..b11daeaaa7 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Apesar de seu perfil não ser trancado, {domain} exige que você revise a solicitação para te seguir destes perfis manualmente.", "follow_suggestions.curated_suggestion": "Escolha da equipe", "follow_suggestions.dismiss": "Não mostrar novamente", + "follow_suggestions.featured_longer": "Escolhido à mão pela equipe de {domain}", + "follow_suggestions.friends_of_friends_longer": "Popular entre as pessoas que você segue", "follow_suggestions.hints.featured": "Este perfil foi escolhido a dedo pela equipe {domain}.", "follow_suggestions.hints.friends_of_friends": "Este perfil é popular entre as pessoas que você segue.", "follow_suggestions.hints.most_followed": "Este perfil é um dos mais seguidos em {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Este perfil é semelhante aos perfis que você seguiu recentemente.", "follow_suggestions.personalized_suggestion": "Sugestão personalizada", "follow_suggestions.popular_suggestion": "Sugestão popular", + "follow_suggestions.popular_suggestion_longer": "Popular em {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Similar a perfis que você seguiu recentemente", "follow_suggestions.view_all": "Visualizar tudo", "follow_suggestions.who_to_follow": "Quem seguir", "followed_tags": "Hashtags seguidas", @@ -469,6 +473,15 @@ "notification.follow": "{name} te seguiu", "notification.follow_request": "{name} quer te seguir", "notification.mention": "{name} te mencionou", + "notification.moderation-warning.learn_more": "Aprender mais", + "notification.moderation_warning": "Você recebeu um aviso de moderação", + "notification.moderation_warning.action_delete_statuses": "Algumas das suas publicações foram removidas.", + "notification.moderation_warning.action_disable": "Sua conta foi desativada.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Algumas de suas publicações foram marcadas por ter conteúdo sensível.", + "notification.moderation_warning.action_none": "Sua conta recebeu um aviso de moderação.", + "notification.moderation_warning.action_sensitive": "Suas publicações serão marcadas como sensíveis a partir de agora.", + "notification.moderation_warning.action_silence": "Sua conta foi limitada.", + "notification.moderation_warning.action_suspend": "Sua conta foi suspensa.", "notification.own_poll": "Sua enquete terminou", "notification.poll": "Uma enquete que você votou terminou", "notification.reblog": "{name} deu boost no teu toot", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index e126fdef02..2863442415 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -448,6 +448,7 @@ "notification.own_poll": "Vaša anketa sa skončila", "notification.poll": "Anketa, v ktorej ste hlasovali, sa skončila", "notification.reblog": "{name} zdieľa váš príspevok", + "notification.relationships_severance_event": "Stratené prepojenia s {name}", "notification.relationships_severance_event.learn_more": "Zisti viac", "notification.status": "{name} uverejňuje niečo nové", "notification.update": "{name} upravuje príspevok", @@ -490,6 +491,7 @@ "notifications.policy.filter_new_accounts_title": "Nové účty", "notifications.policy.filter_not_followers_title": "Ľudia, ktorí ťa nenasledujú", "notifications.policy.filter_not_following_title": "Ľudia, ktorých nenasleduješ", + "notifications.policy.filter_private_mentions_title": "Nevyžiadané priame spomenutia", "notifications.policy.title": "Filtrovať oznámenia od…", "notifications_permission_banner.enable": "Povoliť upozornenia na ploche", "notifications_permission_banner.how_to_control": "Ak chcete dostávať upozornenia, keď Mastodon nie je otvorený, povoľte upozornenia na ploche. Po ich zapnutí môžete presne kontrolovať, ktoré typy interakcií generujú upozornenia na ploche, a to prostredníctvom tlačidla {icon} vyššie.", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 3eea87d5ec..67b706fa13 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Iako vaš nalog nije zaključan, osoblje {domain} smatra da biste možda želeli da ručno pregledate zahteve za praćenje sa ovih naloga.", "follow_suggestions.curated_suggestion": "Izbor osoblja", "follow_suggestions.dismiss": "Ne prikazuj ponovo", + "follow_suggestions.featured_longer": "Ručno odabrao tim {domain}", + "follow_suggestions.friends_of_friends_longer": "Popularno među ljudima koje pratite", "follow_suggestions.hints.featured": "Ovaj profil je ručno izabrao tim {domain}.", "follow_suggestions.hints.friends_of_friends": "Ovaj profil je popularan među ljudima koje pratite.", "follow_suggestions.hints.most_followed": "Ovaj profil je jedan od najpraćenijih na {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Ovaj profil je sličan profilima koje ste nedavno zapratili.", "follow_suggestions.personalized_suggestion": "Personalizovani predlog", "follow_suggestions.popular_suggestion": "Popularni predlog", + "follow_suggestions.popular_suggestion_longer": "Popularno na {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Slično profilima koje ste nedavno zapratili", "follow_suggestions.view_all": "Prikaži sve", "follow_suggestions.who_to_follow": "Koga pratiti", "followed_tags": "Praćene heš oznake", @@ -469,6 +473,15 @@ "notification.follow": "{name} vas je zapratio", "notification.follow_request": "{name} je zatražio da vas prati", "notification.mention": "{name} vas je pomenuo", + "notification.moderation-warning.learn_more": "Saznajte više", + "notification.moderation_warning": "Dobili ste moderatorsko upozorenje", + "notification.moderation_warning.action_delete_statuses": "Neke od vaših objava su uklonjene.", + "notification.moderation_warning.action_disable": "Vaš nalog je onemogućen.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Neke od vaših objava su obeležene kao osetljive.", + "notification.moderation_warning.action_none": "Vaš nalog je dobio moderatorsko upozorenje.", + "notification.moderation_warning.action_sensitive": "Vaše objave će ubuduće biti označene kao osetljive.", + "notification.moderation_warning.action_silence": "Vaš nalog je ograničen.", + "notification.moderation_warning.action_suspend": "Vaš nalog je suspendovan.", "notification.own_poll": "Vaša anketa je završena", "notification.poll": "Završena je anketa u kojoj ste glasali", "notification.reblog": "{name} je podržao vašu objavu", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index 69f755a0b6..9898a10a3e 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Иако ваш налог није закључан, особље {domain} сматра да бисте можда желели да ручно прегледате захтеве за праћење са ових налога.", "follow_suggestions.curated_suggestion": "Избор особља", "follow_suggestions.dismiss": "Не приказуј поново", + "follow_suggestions.featured_longer": "Ручно одабрао тим {domain}", + "follow_suggestions.friends_of_friends_longer": "Популарно међу људима које пратите", "follow_suggestions.hints.featured": "Овај профил је ручно изабрао тим {domain}.", "follow_suggestions.hints.friends_of_friends": "Овај профил је популаран међу људима које пратите.", "follow_suggestions.hints.most_followed": "Овај профил је један од најпраћенијих на {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Овај профил је сличан профилима које сте недавно запратили.", "follow_suggestions.personalized_suggestion": "Персонализовани предлог", "follow_suggestions.popular_suggestion": "Популарни предлог", + "follow_suggestions.popular_suggestion_longer": "Популарно на {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Слично профилима које сте недавно запратили", "follow_suggestions.view_all": "Прикажи све", "follow_suggestions.who_to_follow": "Кога пратити", "followed_tags": "Праћене хеш ознаке", @@ -469,6 +473,15 @@ "notification.follow": "{name} вас је запратио", "notification.follow_request": "{name} је затражио да вас прати", "notification.mention": "{name} вас је поменуо", + "notification.moderation-warning.learn_more": "Сазнајте више", + "notification.moderation_warning": "Добили сте модераторско упозорење", + "notification.moderation_warning.action_delete_statuses": "Неке од ваших објава су уклоњене.", + "notification.moderation_warning.action_disable": "Ваш налог је онемогућен.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Неке од ваших објава су обележене као осетљиве.", + "notification.moderation_warning.action_none": "Ваш налог је добио модераторско упозорење.", + "notification.moderation_warning.action_sensitive": "Ваше објаве ће убудуће бити означене као осетљиве.", + "notification.moderation_warning.action_silence": "Ваш налог је ограничен.", + "notification.moderation_warning.action_suspend": "Ваш налог је суспендован.", "notification.own_poll": "Ваша анкета је завршена", "notification.poll": "Завршена је анкета у којој сте гласали", "notification.reblog": "{name} је подржао вашу објаву", diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 546a143283..af41ab3bcc 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -10145,6 +10145,7 @@ noscript { font-weight: 500; font-size: 11px; line-height: 16px; + word-break: keep-all; &__badge { background: $ui-button-background-color; diff --git a/app/models/concerns/account/associations.rb b/app/models/concerns/account/associations.rb index b2e9d255fd..1c67b07e51 100644 --- a/app/models/concerns/account/associations.rb +++ b/app/models/concerns/account/associations.rb @@ -62,7 +62,7 @@ module Account::Associations has_many :aliases, class_name: 'AccountAlias', dependent: :destroy, inverse_of: :account # Hashtags - has_and_belongs_to_many :tags + has_and_belongs_to_many :tags # rubocop:disable Rails/HasAndBelongsToMany has_many :featured_tags, -> { includes(:tag) }, dependent: :destroy, inverse_of: :account # Account deletion requests diff --git a/app/models/concerns/legacy_otp_secret.rb b/app/models/concerns/legacy_otp_secret.rb new file mode 100644 index 0000000000..466c4ec9bb --- /dev/null +++ b/app/models/concerns/legacy_otp_secret.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +# TODO: This file is here for legacy support during devise-two-factor upgrade. +# It should be removed after all records have been migrated. + +module LegacyOtpSecret + extend ActiveSupport::Concern + + private + + # Decrypt and return the `encrypted_otp_secret` attribute which was used in + # prior versions of devise-two-factor + # @return [String] The decrypted OTP secret + def legacy_otp_secret + return nil unless self[:encrypted_otp_secret] + return nil unless self.class.otp_secret_encryption_key + + hmac_iterations = 2000 # a default set by the Encryptor gem + key = self.class.otp_secret_encryption_key + salt = Base64.decode64(encrypted_otp_secret_salt) + iv = Base64.decode64(encrypted_otp_secret_iv) + + raw_cipher_text = Base64.decode64(encrypted_otp_secret) + # The last 16 bytes of the ciphertext are the authentication tag - we use + # Galois Counter Mode which is an authenticated encryption mode + cipher_text = raw_cipher_text[0..-17] + auth_tag = raw_cipher_text[-16..-1] # rubocop:disable Style/SlicingWithRange + + # this alrorithm lifted from + # https://github.com/attr-encrypted/encryptor/blob/master/lib/encryptor.rb#L54 + + # create an OpenSSL object which will decrypt the AES cipher with 256 bit + # keys in Galois Counter Mode (GCM). See + # https://ruby.github.io/openssl/OpenSSL/Cipher.html + cipher = OpenSSL::Cipher.new('aes-256-gcm') + + # tell the cipher we want to decrypt. Symmetric algorithms use a very + # similar process for encryption and decryption, hence the same object can + # do both. + cipher.decrypt + + # Use a Password-Based Key Derivation Function to generate the key actually + # used for encryptoin from the key we got as input. + cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(key, salt, hmac_iterations, cipher.key_len) + + # set the Initialization Vector (IV) + cipher.iv = iv + + # The tag must be set after calling Cipher#decrypt, Cipher#key= and + # Cipher#iv=, but before calling Cipher#final. After all decryption is + # performed, the tag is verified automatically in the call to Cipher#final. + # + # If the auth_tag does not verify, then #final will raise OpenSSL::Cipher::CipherError + cipher.auth_tag = auth_tag + + # auth_data must be set after auth_tag has been set when decrypting See + # http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-auth_data-3D + # we are not adding any authenticated data but OpenSSL docs say this should + # still be called. + cipher.auth_data = '' + + # #update is (somewhat confusingly named) the method which actually + # performs the decryption on the given chunk of data. Our OTP secret is + # short so we only need to call it once. + # + # It is very important that we call #final because: + # + # 1. The authentication tag is checked during the call to #final + # 2. Block based cipher modes (e.g. CBC) work on fixed size chunks. We need + # to call #final to get it to process the last chunk properly. The output + # of #final should be appended to the decrypted value. This isn't + # required for streaming cipher modes but including it is a best practice + # so that your code will continue to function correctly even if you later + # change to a block cipher mode. + cipher.update(cipher_text) + cipher.final + end +end diff --git a/app/models/concerns/user/ldap_authenticable.rb b/app/models/concerns/user/ldap_authenticable.rb index 180df9d310..c8e9fa9348 100644 --- a/app/models/concerns/user/ldap_authenticable.rb +++ b/app/models/concerns/user/ldap_authenticable.rb @@ -22,7 +22,7 @@ module User::LdapAuthenticable safe_username = safe_username.gsub(keys, replacement) end - resource = joins(:account).find_by(accounts: { username: safe_username }) + resource = joins(:account).merge(Account.where(Account.arel_table[:username].lower.eq safe_username.downcase)).take if resource.blank? resource = new( diff --git a/app/models/status.rb b/app/models/status.rb index 05e7274c76..42c94a261d 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -84,7 +84,7 @@ class Status < ApplicationRecord has_many :local_reblogged, -> { merge(Account.local) }, through: :reblogs, source: :account has_many :local_bookmarked, -> { merge(Account.local) }, through: :bookmarks, source: :account - has_and_belongs_to_many :tags + has_and_belongs_to_many :tags # rubocop:disable Rails/HasAndBelongsToMany has_one :preview_cards_status, inverse_of: :status, dependent: :delete diff --git a/app/models/tag.rb b/app/models/tag.rb index 58baa48c05..35be921e2d 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -21,8 +21,10 @@ class Tag < ApplicationRecord include Paginable + # rubocop:disable Rails/HasAndBelongsToMany has_and_belongs_to_many :statuses has_and_belongs_to_many :accounts + # rubocop:enable Rails/HasAndBelongsToMany has_many :passive_relationships, class_name: 'TagFollow', inverse_of: :tag, dependent: :destroy has_many :featured_tags, dependent: :destroy, inverse_of: :tag diff --git a/app/models/user.rb b/app/models/user.rb index b49ebb14f9..3bd87c2817 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -39,6 +39,7 @@ # role_id :bigint(8) # settings :text # time_zone :string +# otp_secret :string # class User < ApplicationRecord @@ -72,6 +73,8 @@ class User < ApplicationRecord devise :two_factor_authenticatable, otp_secret_encryption_key: Rails.configuration.x.otp_secret + include LegacyOtpSecret # Must be after the above `devise` line in order to override the legacy method + devise :two_factor_backupable, otp_number_of_backup_codes: 10 @@ -131,11 +134,6 @@ class User < ApplicationRecord normalizes :time_zone, with: ->(time_zone) { ActiveSupport::TimeZone[time_zone].nil? ? nil : time_zone } normalizes :chosen_languages, with: ->(chosen_languages) { chosen_languages.compact_blank.presence } - # This avoids a deprecation warning from Rails 5.1 - # It seems possible that a future release of devise-two-factor will - # handle this itself, and this can be removed from our User class. - attribute :otp_secret - has_many :session_activations, dependent: :destroy delegate :can?, to: :role diff --git a/config/environments/development.rb b/config/environments/development.rb index a855f5a16b..a3254125c0 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -87,8 +87,7 @@ Rails.application.configure do # Otherwise, use letter_opener, which launches a browser window to view sent mail. config.action_mailer.delivery_method = ENV['HEROKU'] || ENV['VAGRANT'] || ENV['REMOTE_DEV'] ? :letter_opener_web : :letter_opener - # We provide a default secret for the development environment here. - # This value should not be used in production environments! + # TODO: Remove once devise-two-factor data migration complete config.x.otp_secret = ENV.fetch('OTP_SECRET', '1fc2b87989afa6351912abeebe31ffc5c476ead9bf8b3d74cbc4a302c7b69a45b40b1bbef3506ddad73e942e15ed5ca4b402bf9a66423626051104f4b5f05109') # Raise error when a before_action's only/except options reference missing actions diff --git a/config/environments/production.rb b/config/environments/production.rb index 4a75eb27ca..b32bad0ece 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -158,6 +158,7 @@ Rails.application.configure do 'Referrer-Policy' => 'same-origin', } + # TODO: Remove once devise-two-factor data migration complete config.x.otp_secret = ENV.fetch('OTP_SECRET') # Enable DNS rebinding protection and other `Host` header attacks. diff --git a/config/environments/test.rb b/config/environments/test.rb index 13e1973380..49b0c1f303 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -44,6 +44,7 @@ Rails.application.configure do # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr + # TODO: Remove once devise-two-factor data migration complete config.x.otp_secret = '100c7faeef00caa29242f6b04156742bf76065771fd4117990c4282b8748ff3d99f8fdae97c982ab5bd2e6756a159121377cce4421f4a8ecd2d67bd7749a3fb4' # Generate random VAPID keys diff --git a/config/initializers/active_record_encryption.rb b/config/initializers/active_record_encryption.rb index f99585b4ad..7cda8c621c 100644 --- a/config/initializers/active_record_encryption.rb +++ b/config/initializers/active_record_encryption.rb @@ -6,9 +6,9 @@ ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY ).each do |key| ENV.fetch(key) do - raise <<~MESSAGE + abort <<~MESSAGE - The ActiveRecord encryption feature requires that these variables are set: + Mastodon now requires that these variables are set: - ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY - ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT diff --git a/config/locales/devise.ia.yml b/config/locales/devise.ia.yml index d180a46a6f..6c89f4c6d4 100644 --- a/config/locales/devise.ia.yml +++ b/config/locales/devise.ia.yml @@ -16,6 +16,7 @@ ia: pending: Tu conto es ancora sub revision. timeout: Tu session ha expirate. Per favor reaperi session pro continuar. unauthenticated: Es necessari aperir session o crear un conto ante de continuar. + unconfirmed: Es necessari confirmar tu adresse de e-mail ante de continuar. mailer: confirmation_instructions: action: Verificar adresse de e-mail diff --git a/config/locales/doorkeeper.fy.yml b/config/locales/doorkeeper.fy.yml index a43defc427..51f0055ff6 100644 --- a/config/locales/doorkeeper.fy.yml +++ b/config/locales/doorkeeper.fy.yml @@ -174,6 +174,7 @@ fy: read:filters: jo filters besjen read:follows: de accounts dy’tsto folgest besjen read:lists: jo listen besjen + read:me: allinnich de basisgegevens fan jo account lêze read:mutes: jo negearre brûkers besjen read:notifications: jo meldingen besjen read:reports: jo rapportearre berjochten besjen diff --git a/config/locales/doorkeeper.sr-Latn.yml b/config/locales/doorkeeper.sr-Latn.yml index a4eb7bd33e..58ed5e8b68 100644 --- a/config/locales/doorkeeper.sr-Latn.yml +++ b/config/locales/doorkeeper.sr-Latn.yml @@ -174,6 +174,7 @@ sr-Latn: read:filters: pogledaj svoje filtere read:follows: pogledaj koga pratiš read:lists: pogledaj svoje liste + read:me: čita samo osnovne informacije o vašem nalogu read:mutes: pogledaj ignorisanja read:notifications: pogledaj svoja obaveštenja read:reports: pogledaj svoje prijave diff --git a/config/locales/doorkeeper.sr.yml b/config/locales/doorkeeper.sr.yml index 010eb23eb5..f40a05e90d 100644 --- a/config/locales/doorkeeper.sr.yml +++ b/config/locales/doorkeeper.sr.yml @@ -174,6 +174,7 @@ sr: read:filters: погледај своје филтере read:follows: погледај кога пратиш read:lists: погледај своје листе + read:me: чита само основне информације о вашем налогу read:mutes: погледај игнорисања read:notifications: погледај своја обавештења read:reports: погледај своје пријаве diff --git a/config/locales/fy.yml b/config/locales/fy.yml index 1d62f7c6af..1f1a27fec4 100644 --- a/config/locales/fy.yml +++ b/config/locales/fy.yml @@ -597,6 +597,9 @@ fy: actions_description_html: Beslis hokker maatregel nommen wurde moat om dizze rapportaazje op te lossen. Wannear’t jo in (straf)maatregel tsjin it rapportearre account nimme, kriget de account in e-mailmelding, behalve wannear’t de spam-kategory keazen is. actions_description_remote_html: Beslút hokker aksje nommen wurde moat om dizze rapportaazje ôf te hanneljen. Dit hat allinnich ynfloed op hoe’t jo server kommunisearret mei dizze eksterne account en omgiet mei de ynhâld. add_to_report: Mear oan de rapportaazje tafoegje + already_suspended_badges: + local: Al opskoarte op dizze server + remote: Al opskoarte op harren server are_you_sure: Binne jo wis? assign_to_self: Oan my tawize assigned: Tawizen moderator @@ -748,6 +751,7 @@ fy: desc_html: Dit is ôfhinklik fan eksterne scripts fan hCaptcha, wat feilichheids- en privacyrisiko’s meibringe kin. Boppe dat kin dit it registraasjeproses bot minder tagonklik meitsje foar guon (foaral handicapte) minsken. Om dizze redenen kinne jo it beste alternative maatregels oerweagje, lykas registraasje op basis fan goedkarring of op útnûging. title: Nije brûkers moatte in CAPTCHA oplosse om harren account te befêstigjen content_retention: + danger_zone: Gefaresône preamble: Tafersjoch hâlde op hoe’t berjochten en media fan brûkers op Mastodon bewarre wurde. title: Bewartermyn berjochten default_noindex: @@ -767,6 +771,7 @@ fy: disabled: Oan net ien users: Oan oanmelde lokale brûkers registrations: + moderation_recommandation: Soargje derfoar dat jo in adekwaat en responsyf moderaasjeteam hawwe eardat jo registraasjes foar elkenien iepenstelle! preamble: Tafersjoch hâlde op wa’t in account op dizze server registrearje kin. title: Registraasjes registrations_mode: @@ -1647,13 +1652,24 @@ fy: import: Ymportearje import_and_export: Ymportearje en eksportearje migrate: Accountmigraasje + notifications: E-mailmeldingen preferences: Ynstellingen profile: Profyl relationships: Folgers en folgjenden + severed_relationships: Ferbrutsen folchrelaasjes statuses_cleanup: Automatysk berjochten fuortsmite strikes: Fêststelde skeiningen two_factor_authentication: Twa-stapsferifikaasje webauthn_authentication: Befeiligingskaaien + severed_relationships: + download: Downloade (%{count}) + event_type: + account_suspension: Accountopskoarting (%{target_name}) + domain_block: Serveropskoarting (%{target_name}) + user_domain_block: Jo hawwe %{target_name} blokkearre + lost_followers: Ferlerne folgers + lost_follows: Ferlerne folge accounts + type: Barren statuses: attached: audio: @@ -1747,6 +1763,7 @@ fy: contrast: Mastodon (heech kontrast) default: Mastodon (donker) mastodon-light: Mastodon (ljocht) + system: Automatysk (systeemtema brûke) time: formats: default: "%d %B %Y om %H:%M" @@ -1838,13 +1855,30 @@ fy: apps_ios_action: Fia de App Store downloade apps_step: Us offisjele apps downloade apps_title: Mastodon-apps + checklist_subtitle: 'Litte wy oan dit nije sosjale aventoer begjinne:' + checklist_title: Wolkomstkontrôlelist edit_profile_action: Personalisearje + edit_profile_step: Wannear’t jo mear oer josels fertelle, krije jo mear ynteraksje mei oare minsken. edit_profile_title: Jo profyl personalisearje explanation: Hjir binne inkelde tips om jo op wei te helpen feature_action: Mear ynfo + feature_audience: Mastodon biedt jo in unike mooglikheid om jo publyk te behearen sûnder tuskenpersoanen. Mastodon, ymplemintearre yn jo eigen ynfrastruktuer, stelt jo yn steat om elke oare Mastodon-server online te folgjen en troch harren folge te wurden, en stiet ûnder kontrôle fan net ien, útsein dy fan jo. + feature_audience_title: Bou jo publyk yn fertrouwen op + feature_control: Jo witte sels it bêste wat jo op jo tiidline sjen wolle. Gjin algoritmen of advertinsjes om jo tiid te fergriemen. Folgje elkenien op elke Mastodon-server fan ien account ôf en ûntfang harren berjochten yn gronologyske folchoarder, en meitsje jo hoekje op it ynternet in bytsje mear as josels. + feature_control_title: Hâld kontrôle oer jo eigen tiidline + feature_creativity: Mastodon stipet audio-, fideo- en fotoberjochten, tagonklikheidsbeskriuwingen, enkêten, ynhâldswarskôgingen, animearre avatars, oanpaste emoji, kontrôle oer it bywurkjen fan miniatueren en mear, om jo te helpen josels online te uterjen. Oft jo no jo keunst, muzyk of podcast publisearje, Mastodon stiet foar jo klear. + feature_creativity_title: Bjusterbaarlike kreativiteit + feature_moderation: Mastodon leit de beslútfoarming wer yn jo hannen. Elke server makket harren eigen rigels en foarskriften, dy’t lokaal hanthavene wurde en net fan boppe ôf, lykas sosjale media fan bedriuwen, wêrtroch it it meast fleksibel is yn it reagearjen op de behoeften fan ferskate groepen minsken. Wurd lid fan in server mei de rigels wêrmei’t jo akkoard geane, of host jo eigen. + feature_moderation_title: Moderaasje sa as it heart follow_action: Folgje + follow_step: Op Mastodon draait it hielendal om it folgjen fan ynteressante minsken. + follow_title: Personalisearje jo starttiidline + follows_subtitle: Folgje bekende accounts follows_title: Wa te folgjen follows_view_more: Mear minsken om te folgjen besjen + hashtags_recent_count: + one: "%{people} persoan yn de ôfrûne 2 dagen" + other: "%{people} persoanen yn de ôfrûne 2 dagen" hashtags_subtitle: Wat der yn de ôfrûne 2 dagen bard is ferkenne hashtags_title: Populêre hashtags hashtags_view_more: Mear populêre hashtags besjen diff --git a/config/locales/ia.yml b/config/locales/ia.yml index 9ec64b1390..59dd2dbc0f 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -111,12 +111,23 @@ ia: public: Public push_subscription_expires: Subscription PuSH expira le redownload: Actualisar profilo + redownloaded_msg: Le profilo de %{username} ha essite actualisate desde le origine + reject: Rejectar + rejected_msg: Le demanda de inscription de %{username} ha essite rejectate + remote_suspension_irreversible: Le datos de iste conto ha essite irreversibilemente delite. + remote_suspension_reversible_hint_html: Le conto ha essite suspendite sur su servitor, e le datos essera removite completemente le %{date}. Usque alora, le servitor remote pote restaurar iste conto sin effectos negative. Si tu vole remover immediatemente tote le datos del conto, tu pote facer lo hic infra. + remove_avatar: Remover avatar + remove_header: Remover capite + removed_avatar_msg: Le imagine de avatar de %{username} ha essite removite + removed_header_msg: Le imagine de capite de %{username} ha essite removite resend_confirmation: already_confirmed: Iste usator jam es confirmate send: Reinviar ligamine de confirmation success: Ligamine de confirmation inviate con successo! reset: Reinitialisar reset_password: Reinitialisar contrasigno + resubscribe: Resubscriber + role: Rolo search: Cercar search_same_email_domain: Altere usatores con le mesme dominio de e-mail search_same_ip: Altere usatores con le mesme IP @@ -124,52 +135,118 @@ ia: security_measures: only_password: Solmente contrasigno password_and_2fa: Contrasigno e 2FA + sensitive: Fortiar sensibile + sensitized: Marcate como sensibile + shared_inbox_url: URL del cassa de entrata condividite show: created_reports: Reportos facite targeted_reports: Signalate per alteres + silence: Limitar silenced: Limitate statuses: Messages + strikes: Previe admonitiones subscribe: Subscriber suspend: Suspender suspended: Suspendite + suspension_irreversible: Le datos de iste conto ha essite irreversibilemente delite. Tu pote disfacer le suspension de iste conto pro render lo usabile, ma isto non recuperara alcun datos precedente. + suspension_reversible_hint_html: Le conto ha essite suspendite, e le datos essera removite completemente le %{date}. Usque alora, le conto pote esser restaurate sin effectos negative. Si tu vole remover immediatemente tote le datos del conto, tu pote facer lo hic infra. title: Contos unblock_email: Disblocar adresse de e-mail unblocked_email_msg: Adresse de e-mail de %{username} disblocate con successo unconfirmed_email: E-mail non confirmate + undo_sensitized: Non plus fortiar sensibile undo_silenced: Disfacer le limite undo_suspension: Disfacer le suspension + unsilenced_msg: Le limite del conto de %{username} ha essite cancellate + unsubscribe: Desubscriber + unsuspended_msg: Annullate suspension del conto %{username} con successo username: Nomine de usator view_domain: Vider summario de dominio + warn: Avisar + web: Web + whitelisted: Permittite pro federation action_logs: action_types: + approve_appeal: Approbar appello + approve_user: Approbar usator + assigned_to_self_report: Assignar reporto change_email_user: Cambiar e-mail pro le usator change_role_user: Cambiar le rolo del usator confirm_user: Confirmar le usator create_account_warning: Crear un advertimento create_announcement: Crear annuncio + create_canonical_email_block: Crear blocada de email + create_custom_emoji: Crear emoticone personalisate + create_domain_allow: Crear permisso de dominio + create_domain_block: Crear blocada de dominio + create_email_domain_block: Crear blocada de dominio email create_ip_block: Crear un regula IP + create_unavailable_domain: Crear dominio indisponibile + create_user_role: Crear un rolo + demote_user: Degradar usator destroy_announcement: Deler annuncio + destroy_canonical_email_block: Deler blocada de email + destroy_custom_emoji: Deler emoticone personalisate + destroy_domain_allow: Deler permisso de dominio + destroy_domain_block: Deler blocada de dominio + destroy_email_domain_block: Crear blocada de dominio email + destroy_instance: Purgar dominio destroy_ip_block: Deler le regula IP destroy_status: Deler le message destroy_unavailable_domain: Deler le dominio non disponibile + destroy_user_role: Destruer rolo disable_2fa_user: Disactivar 2FA disable_custom_emoji: Disactivar emoji personalisate + disable_sign_in_token_auth_user: Disactivar le authentication per testimonio via email pro usator disable_user: Disactivar le usator enable_custom_emoji: Activar emoji personalisate + enable_sign_in_token_auth_user: Activar le authentication per testimonio via email pro usator enable_user: Activar le usator + memorialize_account: Commemorar conto promote_user: Promover usator + reject_appeal: Rejectar appello + reject_user: Rejectar usator + remove_avatar_user: Remover avatar + reopen_report: Reaperir reporto resend_user: Reinviar message de confirmation reset_password_user: Reinitialisar contrasigno + resolve_report: Resolver reporto + sensitive_account: Marcar como sensibile le medios del conto silence_account: Limitar conto + suspend_account: Suspender conto + unassigned_report: Disassignar reporto unblock_email_account: Disblocar adresse de e-mail + unsensitive_account: Dismarcar como sensibile le medios del conto unsilence_account: Disfacer le limite de conto + unsuspend_account: Annullar suspension de conto update_announcement: Actualisar annuncio update_custom_emoji: Actualisar emoji personalisate + update_domain_block: Actualisar blocada de dominio update_ip_block: Actualisar le regula IP update_status: Actualisar le message + update_user_role: Actualisar rolo actions: + approve_appeal_html: "%{name} approbava appello del decision de moderation de %{target}" + approve_user_html: "%{name} approbava inscription de %{target}" + assigned_to_self_report_html: "%{name} assignava reporto %{target} a se mesme" change_email_user_html: "%{name} cambiava le adresse de e-mail address del usator %{target}" + change_role_user_html: "%{name} cambiava rolo de %{target}" + confirm_user_html: "%{name} confirmava le adresse email del usator %{target}" + create_account_warning_html: "%{name} inviava un advertimento a %{target}" create_announcement_html: "%{name} creava un nove annuncio %{target}" + create_canonical_email_block_html: "%{name} blocava email con le hash %{target}" + create_custom_emoji_html: "%{name} cargava nove emoticone %{target}" + create_domain_allow_html: "%{name} permitteva federation con dominio %{target}" + create_domain_block_html: "%{name} blocava dominio %{target}" + create_email_domain_block_html: "%{name} blocava dominio email %{target}" + create_ip_block_html: "%{name} creava regula pro IP %{target}" + create_unavailable_domain_html: "%{name} stoppava consignation a dominio %{target}" + create_user_role_html: "%{name} creava rolo de %{target}" + demote_user_html: "%{name} degradava usator %{target}" + destroy_announcement_html: "%{name} deleva annuncio %{target}" + destroy_custom_emoji_html: "%{name} deleva emoji %{target}" + destroy_domain_block_html: "%{name} disblocava dominio %{target}" + destroy_user_role_html: "%{name} deleva le rolo de %{target}" deleted_account: conto delite announcements: destroyed_msg: Annuncio delite con successo! @@ -205,6 +282,7 @@ ia: media_storage: Immagazinage de medios new_users: nove usatores opened_reports: reportos aperte + software: Software top_languages: Linguas le plus active top_servers: Servitores le plus active website: Sito web @@ -220,6 +298,10 @@ ia: edit: Modificar un bloco de dominio export: Exportar import: Importar + new: + severity: + silence: Limitar + suspend: Suspender private_comment: Commento private public_comment: Commento public email_domain_blocks: @@ -239,9 +321,16 @@ ia: status: Stato title: Sequer le recommendationes instances: + back_to_all: Toto + back_to_limited: Limitate back_to_warning: Advertimento by_domain: Dominio content_policies: + comment: Nota interne + policies: + silence: Limitar + suspend: Suspender + policy: Politica reason: Ration public dashboard: instance_accounts_dimension: Contos le plus sequite @@ -249,14 +338,23 @@ ia: delivery: unavailable: Non disponibile empty: Necun dominios trovate. + moderation: + all: Toto + limited: Limitate + title: Moderation private_comment: Commento private public_comment: Commento public + title: Federation total_blocked_by_us: Blocate per nos total_followed_by_us: Sequite per nos invites: deactivate_all: Disactivar toto filter: + all: Toto available: Disponibile + expired: Expirate + title: Filtro + title: Invitationes ip_blocks: add_new: Crear regula delete: Deler @@ -264,15 +362,19 @@ ia: '1209600': 2 septimanas '15778476': 6 menses '2629746': 1 mense + '31556952': 1 anno '86400': 1 die + '94670856': 3 annos new: title: Crear un nove regula IP title: Regulas IP relays: delete: Deler + description_html: Un repetitor de federation es un servitor intermediari que excambia grande volumines de messages public inter le servitores que se inscribe e publica a illo. Illo pote adjutar le servitores micre e medie a discoperir le contento del fediverso, sin requirer que le usatores local seque manualmente altere personas sur servitores distante. disable: Disactivar disabled: Disactivate enable: Activar + enable_hint: Un vice activate, tu servitor se inscribera a tote le messages public de iste repetitor, e comenciara a inviar le messages public de iste servitor a illo. enabled: Activate save_and_enable: Salveguardar e activar status: Stato @@ -283,9 +385,11 @@ ia: category: Categoria confirm: Confirmar delete_and_resolve: Deler le messages + no_one_assigned: Nemo notes: create: Adder un nota delete: Deler + title: Notas skip_to_actions: Saltar al actiones status: Stato updated_at: Actualisate @@ -294,6 +398,11 @@ ia: assigned_users: one: "%{count} usator" other: "%{count} usatores" + categories: + invites: Invitationes + moderation: Moderation + special: Special + delete: Deler everyone: Permissiones predefinite privileges: delete_user_data: Deler le datos de usator @@ -302,6 +411,7 @@ ia: manage_rules: Gerer le regulas manage_settings: Gerer le parametros manage_users: Gerer usatores + title: Rolos rules: delete: Deler settings: @@ -317,8 +427,25 @@ ia: title: Parametros de servitor site_uploads: delete: Deler file incargate + software_updates: + documentation_link: Pro saper plus + title: Actualisationes disponibile + type: Typo + types: + major: Version major + minor: Version minor + version: Version statuses: + account: Autor + application: Application + batch: + report: Reporto + deleted: Delite + favourites: Favoritos + history: Chronologia del versiones language: Lingua + media: + title: Medios metadata: Metadatos open: Aperir message original_status: Message original @@ -337,6 +464,8 @@ ia: action: Vider le actualisationes disponibile upload_check_privacy_error: action: Verifica hic pro plus de information + application_mailer: + unsubscribe: Desubscriber edit_profile: other: Alteres existing_username_validator: @@ -397,6 +526,21 @@ ia: login_activities: authentication_methods: password: contrasigno + mail_subscriptions: + unsubscribe: + action: Si, desubscriber + complete: Desubscribite + confirmation_html: Es tu secur de voler cancellar le subscription al %{type} de Mastodon sur %{domain} pro tu adresse de e-mail %{email}? Tu pote sempre resubscriber te a partir del parametros de notification in e-mail. + emails: + notification_emails: + favourite: notificationes de favorites in e-mail + follow: notificationes de sequimento in e-mail + follow_request: requestas de sequimento in e-mail + mention: notificationes de mentiones in e-mail + reblog: notificationes de impulsos in e-mail + resubscribe_html: Si tu ha cancellate le subscription in error, tu pote resubscriber te a partir del parametros de notification in e-mail. + success_html: Tu non recipera plus %{type} pro Mastodon sur %{domain} a tu adresse de e-mail %{email}. + title: Desubcriber migrations: errors: not_found: non poterea esser trovate diff --git a/config/locales/simple_form.fy.yml b/config/locales/simple_form.fy.yml index fa1633c901..8d599324b3 100644 --- a/config/locales/simple_form.fy.yml +++ b/config/locales/simple_form.fy.yml @@ -77,10 +77,13 @@ fy: warn: Ferstopje de filtere ynhâld efter in warskôging, mei de titel fan it filter as warskôgingstekst form_admin_settings: activity_api_enabled: Tal lokaal publisearre artikelen, aktive brûkers en nije registraasjes yn wyklikse werjefte + backups_retention_period: Brûkers hawwe de mooglikheid om argiven fan harren berjochten te generearjen om letter te downloaden. Wannear ynsteld op in positive wearde, wurde dizze argiven automatysk fuortsmiten út jo ûnthâld nei it opjûne oantal dagen. bootstrap_timeline_accounts: Dizze accounts wurde boppe oan de oanrekommandaasjes oan nije brûkers toand. Meardere brûkersnammen troch komma’s skiede. closed_registrations_message: Werjûn wannear’t registraasje fan nije accounts útskeakele is + content_cache_retention_period: Alle berjochten fan oare servers (ynklusyf boosts en reaksjes) wurde fuortsmiten nei it opjûne oantal dagen, nettsjinsteande iennige lokale brûkersynteraksje mei dy berjochten. Dit oanbelanget ek berjochten dy’t in lokale brûker oan harren blêdwizers tafoege hat of as favoryt markearre hat. Priveeberjochten tusken brûkers fan ferskate servers gean ek ferlern en binne ûnmooglik te werstellen. It gebrûk fan dizze ynstelling is bedoeld foar servers dy’t in spesjaal doel tsjinje en oertrêdet in protte brûkersferwachtingen wannear’t dizze foar algemien gebrûk ymplemintearre wurdt. custom_css: Jo kinne oanpaste CSS tapasse op de webferzje fan dizze Mastodon-server. mascot: Oerskriuwt de yllustraasje yn de avansearre webomjouwing. + media_cache_retention_period: Mediabestannen fan berjochten fan eksterne brûkers wurde op jo server yn de buffer bewarre. Wannear ynsteld op in positive wearde, wurde media fuortsmiten nei it opjûne oantal dagen. As de mediagegevens opfrege wurde neidat se fuortsmiten binne, wurde se opnij download wannear de orizjinele ynhâld noch hieltyd beskikber is. Fanwegen beheiningen op hoe faak keppelingsfoarbylden websites fan tredden rieplachtsje, wurdt oanrekommandearre om dizze wearde yn te stellen op op syn minste 14 dagen. Oars wurde keppelingsfoarbylden net op oanfraach bywurke. peers_api_enabled: In list mei domeinnammen, dêr’t dizze server yn fediverse kontakt hân mei hat. Hjir wurdt gjin data dield, oft jo mei in bepaalde server federearrest, mar alinnich, dat jo server dat wit. Dit wurdt foar tsjinsten brûkt, dy’t statistiken oer federaasje yn algemiene sin sammelet. profile_directory: De brûkersgids befettet in list fan alle brûkers dy¥t derfoar keazen hawwe om ûntdekt wurde te kinnen. require_invite_text: Meitsje it ynfoljen fan ‘Wêrom wolle jo jo hjir registrearje?’ ferplicht yn stee fan opsjoneel, wannear’t registraasjes hânmjittich goedkard wurde moatte @@ -240,6 +243,7 @@ fy: backups_retention_period: Bewartermyn brûkersargyf bootstrap_timeline_accounts: Accounts dy’t altyd oan nije brûkers oanrekommandearre wurde closed_registrations_message: Oanpast berjocht wannear registraasje útskeakele is + content_cache_retention_period: Bewartermyn foar eksterne ynhâld custom_css: Oanpaste CSS mascot: Oanpaste maskotte (legacy) media_cache_retention_period: Bewartermyn mediabuffer diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml index 5e9dda2a13..b5ec14e60e 100644 --- a/config/locales/simple_form.ia.yml +++ b/config/locales/simple_form.ia.yml @@ -3,12 +3,96 @@ ia: simple_form: hints: account: + discoverable: Tu messages public e tu profilo pote esser consiliate o recommendate in varie areas de Mastodon e tu profilo pote esser suggerite a altere usatores. + display_name: Tu prenomine e nomine de familia o tu pseudonymo. + fields: Tu pagina principal, pronomines, etate, toto lo que tu vole. + indexable: Tu messages public pote apparer in resultatos del recerca sur Mastodon. Illes qui ha interagite con tu messages totevia pote cercar les. note: 'Tu pote @mentionar altere personas o #hashtags.' + show_collections: Le personas potera navigar per tu sequites e sequaces. Le personas potera navigar per tu sequites e sequaces. + unlocked: Le personas potera sequer te sin requestar approbation. Dismarca si tu desira revider le requestas de sequer e selige si acceptar o rejectar nove sequaces. + account_alias: + acct: Specifica le nomine_de_usator@dominio del conto ab que tu vole mover + account_migration: + acct: Specifica le nomine_de_usator@dominio del conto a que tu vole mover + account_warning_preset: + text: Tu pote usar le syntaxe de message, tal como URLs, hashtags e mentiones + title: Optional. Non visibile al destinatario + admin_account_action: + include_statuses: Le usator videra que messages ha causate le action o aviso de moderation + send_email_notification: Le usator recipera un explication de cosa eveniva con lor conto + text_html: Optional. Tu pote usar le syntaxe de message. Tu pote adder avisos preconfigurate pro sparniar tempore + type_html: Selige lo que tu vole facer con %{acct} + types: + disable: Impedir al usator de usar lor conto, sin deler o celar lor contentos. + none: Usar lo pro inviar un aviso al usator, sin discatenar ulle altere action. + sensitive: Fortiar tote le annexos multimedial de iste usator a esser signalate como sensibile. + silence: Impedir al usator de poter publicar messages con public visibilitate, celar lor messages e notificationes ab gente non sequente illes. Clauder tote le reportos contra iste conto. + suspend: Impedir ulle interaction de o a iste conto e deler su contentos. Reversibile intra 30 dies. Clauder tote le reportos contra iste conto. + warning_preset_id: Optional. Tu pote ancora adder personal texto a fin del preconfigurate + announcement: + all_day: Si marcate, solo le datas del campo tempore sera monstrate + ends_at: Le annuncio sera automaticamente obscurate a iste tempore + scheduled_at: Lassar blanc pro publicar le annuncio immediatemente + starts_at: Optional. In caso tu annuncio es ligate con un specific campo tempore + text: Tu pote usar le syntaxe de message. Presta attention al spatio que le annuncio occupara sur le schermo de usator + appeal: + text: Tu pote solo appellar te un vice defaults: + autofollow: Illes qui se inscribe per le invitation automaticamente devenira tu sequaces + avatar: WEBP, PNG, GIF or JPG. Al maximo %{size}. Sera diminuite a %{dimensions}px + bot: Signala a alteres que le conto principalmente exeque actiones automatisate e poterea non esser surveliate + context: Un o plure contextos ubi le filtro deberea applicar se + current_password: Pro propositos de securitate insere le contrasigno del conto actual + current_username: Pro confirmar, insere le nomine de usator del conto actual + digest: Solo inviate post un longe periodo de inactivitate e solo si tu ha recipite alcun messages personal in tu absentia + email: Te sera inviate un email de confirmation + header: WEBP, PNG, GIF or JPG. Al maximo %{size}. Sera diminuite a %{dimensions}px + inbox_url: Copia le URL ab le pagina principal del repetitor que tu vole usar + irreversible: Le messages filtrate disparera irreversibilemente, mesmo si le filtro es plus tarde removite + locale: Le lingua del interfacie de usator, del emails e del notificationes pulsate password: Usa al minus 8 characteres + phrase: Sera concordate ignorante majuscule/minuscule in le texto o avisos de contento de un message + scopes: A que APIs sera permittite acceder al application. Si tu selige un ambito de maxime nivello, tu non besonia de seliger los singulemente. + setting_aggregate_reblogs: Non monstra nove stimulos pro messages que ha essite recentemente stimulate (stimulos solo affice los novemente recipite) + setting_always_send_emails: Normalmente le avisos de email non sera inviate quando tu activemente usa Mastodon + setting_default_sensitive: Le medios sensibile es celate de ordinario e pote esser revelate con un clic + setting_display_media_default: Celar le medios marcate como sensibile setting_display_media_hide_all: Sempre celar le medios setting_display_media_show_all: Sempre monstrar le medios + setting_use_blurhash: Le imagines degradate es basate sur le colores del medios visual celate, ma illos offusca qualcunque detalios + setting_use_pending_items: Celar le classification temporal detra un clic in vice que automaticamente rolante le fluxo username: Tu pote usar litteras, numeros e tractos de sublineamento + whole_word: Quando le parola o expression clave es solo alphanumeric, illo sera solo applicate si illo concorda con tote le parola + domain_allow: + domain: Iste dominio potera reportar datos ab iste servitor e le datos in ingresso ab illo sera processate e immagazinate + email_domain_block: + domain: Isto pote esser le nomine de dominio que apparera in le adresse email o le registration MX que illo usa. Illos sera verificate durante le inscription. + with_dns_records: Un tentativa sera facite pro resolver le registrationes de DNS del dominio date e le resultatos sera alsi blocate + featured_tag: + name: 'Ecce alcun del hashtags que tu usava le plus recentemente:' + filters: + action: Selige que action exequer quando un message concorda con le filtro + actions: + hide: Completemente celar le contento filtrate, comportar se como si illo non existerea + warn: Celar le contento filtrate detra un aviso citante le titulo del filtro + form_admin_settings: + activity_api_enabled: Numeros de messages localmente publicate, usatores active, e nove registrationes in gruppos septimanal + backups_retention_period: Le usatores pote generar archivos de lor messages pro discargar los plus tarde. Quando predefinite a un valor positive, iste archivos sera automaticamente delite de tu immagazinage post le specificate numero de dies. + bootstrap_timeline_accounts: Iste contos sera appunctate al summitate del recommendationes a sequer del nove usatores. + closed_registrations_message: Monstrate quando le inscriptiones es claudite + content_cache_retention_period: Tote messages de altere servitores (includite stimulos e responsas) sera delite post le specificate numero de dies, sin considerar alcun interaction de usator local con ille messages. Isto include messages ubi un usator local los ha marcate como marcapaginas o favoritos. Mentiones private inter usatores de differente instantias sera alsi perdite e impossibile a restaurar. Le uso de iste parametros es intendite pro specific instantias e infringe multe expectationes de usator quando implementate pro uso general. + custom_css: Tu pote applicar stilos personalisate sur le version de web de Mastodon. + mascot: Illo substitue le illustration in le interfacie web avantiate. + media_cache_retention_period: Le files multimedial de messages producite per usatores remote es in cache sur tu servitor. Quando predefinite a un valor positive, le medios sera delite post le numero de dies specificate. Le datos multimedial requirite post que illo es delite, sera re-discargate, si le contento original sera ancora disponibile. Per limitationes sur le frequentia con que le schedas de pre-visualisation de ligamine scruta le sitos de tertie partes, il es recommendate de predefinir iste valor a al minus 14 dies, o le schedas de pre-visualisation de ligamine non sera actualisate sur demanda ante ille tempore. + peers_api_enabled: Un lista de nomines de dominio que iste servitor ha incontrate in le fediverso. Nulle datos es includite ci re tu federation con un date servitor, justo que tu servitor lo cognosce. Isto es usate per servicios que collige statistica re le federation in senso general. + profile_directory: Le directorio de profilo lista tote le usatores qui ha optate pro esser detectabile. + require_invite_text: Quando le inscriptiones require approbation manual, rende obligatori, plus tosto que optional, le entrata de texto “Perque vole tu junger te?” + site_contact_email: Como pote contactar te le personas pro questiones legal o de supporto. + site_contact_username: Como pote contactar te le personas re Mastodon. + site_extended_description: Qualcunque information additional que pote esser utile al visitatores e a tu usatores. Pote esser structurate con syntaxe de markdown. + ip_block: + severities: + no_access: Blocar accesso a tote le ressources webhook: events: Selige le eventos a inviar url: Ubi le eventos essera inviate @@ -22,15 +106,20 @@ ia: show_collections: Monstrar sequites e sequitores in le profilo unlocked: Acceptar automaticamente nove sequitores account_warning_preset: + text: Texto predefinite title: Titulo admin_account_action: + send_email_notification: Notificar le usator per e-mail + text: Advertimento personalisate type: Action types: disable: Gelar none: Inviar un advertimento + sensitive: Sensibile silence: Limitar suspend: Suspender announcement: + starts_at: Initio del evento text: Annuncio defaults: autofollow: Invitar a sequer tu conto @@ -38,25 +127,41 @@ ia: chosen_languages: Filtrar linguas confirm_new_password: Confirmar nove contrasigno confirm_password: Confirmar contrasigno + context: Contextos del filtro current_password: Contrasigno actual + data: Datos display_name: Nomine a monstrar email: Adresse de e-mail + expires_in: Expira post + fields: Campos extra + header: Imagine titulo + honeypot: "%{label} (non compilar)" + inbox_url: URL del cassa de ingresso de repetitor locale: Lingua de interfacie + max_uses: Numero max de usos new_password: Nove contrasigno + note: Bio + otp_attempt: Codice a duo factores password: Contrasigno + phrase: Parola o phrase clave setting_advanced_layout: Activar le interfacie web avantiate setting_always_send_emails: Sempre inviar notificationes per e-mail setting_default_language: Lingua de publication + setting_display_media: Visualisation de medios setting_display_media_default: Predefinite setting_display_media_hide_all: Celar toto setting_display_media_show_all: Monstrar toto setting_system_font_ui: Usar typo de litteras predefinite del systema setting_theme: Thema de sito setting_trends: Monstrar le tendentias de hodie + setting_use_pending_items: Modo lente + severity: Severitate sign_in_token_attempt: Codice de securitate title: Titulo + type: Importar le typo username: Nomine de usator username_or_email: Nomine de usator o e-mail + whole_word: Parola integre featured_tag: name: Hashtag filters: @@ -74,11 +179,18 @@ ia: site_title: Nomine de servitor status_page_url: URL del pagina de stato theme: Thema predefinite + thumbnail: Miniatura de servitor trends: Activar tendentias + invite: + comment: Commento ip_block: comment: Commento + ip: IP + severities: + no_access: Blocar le accesso severity: Regula notification_emails: + digest: Inviar emails compendio software_updates: all: Notificar sur tote le actualisationes critical: Notificar solmente sur actualisationes critic @@ -94,13 +206,18 @@ ia: name: Hashtag usable: Permitter al messages usar iste hashtag user: + role: Rolo time_zone: Fuso horari user_role: name: Nomine permissions_as_keys: Permissiones position: Prioritate + webhook: + events: Eventos activate + 'no': 'No' not_recommended: Non recommendate recommended: Recommendate required: + mark: "*" text: requirite 'yes': Si diff --git a/config/locales/simple_form.pt-BR.yml b/config/locales/simple_form.pt-BR.yml index f68eef8a63..9044546f2b 100644 --- a/config/locales/simple_form.pt-BR.yml +++ b/config/locales/simple_form.pt-BR.yml @@ -240,6 +240,7 @@ pt-BR: backups_retention_period: Período de retenção do arquivo de usuário bootstrap_timeline_accounts: Sempre recomendar essas contas para novos usuários closed_registrations_message: Mensagem personalizada quando inscrições não estão disponíveis + content_cache_retention_period: Período de retenção de conteúdo remoto custom_css: CSS personalizável mascot: Mascote personalizado (legado) media_cache_retention_period: Período de retenção do cachê de mídia diff --git a/config/locales/simple_form.sr-Latn.yml b/config/locales/simple_form.sr-Latn.yml index bc4eafb965..6bee31a42c 100644 --- a/config/locales/simple_form.sr-Latn.yml +++ b/config/locales/simple_form.sr-Latn.yml @@ -77,10 +77,13 @@ sr-Latn: warn: Sakrij filtrirani sadržaj iza upozorenja u kome se navodi naziv filtera form_admin_settings: activity_api_enabled: Brojevi lokalno postavljenih objava, aktivnih korisnika i novih registracija na nedeljnoj bazi + backups_retention_period: Korisnici imaju mogućnost da generišu arhive svojih objava za kasnije preuzimanje. Kada se podese na pozitivnu vrednost, ove arhive će se automatski izbrisati iz vašeg skladišta nakon navedenog broja dana. bootstrap_timeline_accounts: Ovi nalozi će biti zakačeni na vrh preporuka za praćenje novih korisnika. closed_registrations_message: Prikazuje se kada su registracije zatvorene + content_cache_retention_period: Sve objave sa drugih servera (uključujući podržavanja i odgovore) će biti izbrisane nakon navedenog broja dana, bez obzira na bilo kakvu interakciju lokalnog korisnika sa tim objavama. Ovo uključuje objave u kojima ih je lokalni korisnik označio kao obeleživače ili omiljene. Privatna pominjanja između korisnika sa različitih instanci će takođe biti izgubljena i nemoguće ih je vratiti. Korišćenje ove postavke je namenjeno za slučajeve posebne namene i krši mnoga očekivanja korisnika kada se primeni za upotrebu opšte namene. custom_css: Možete da primenite prilagođene stilove na veb verziji Mastodon-a. mascot: Zamenjuje ilustraciju u naprednom veb okruženju. + media_cache_retention_period: Medijske datoteke iz objava udaljenih korisnika se keširaju na vašem serveru. Kada se podesi na pozitivnu vrednost, mediji će biti izbrisani nakon navedenog broja dana. Ako se medijski podaci zahtevaju nakon brisanja, biće ponovo preuzeti, ako je izvorni sadržaj i dalje dostupan. Zbog ograničenja koliko često kartice za pregled veza anketiraju sajtove trećih strana, preporučuje se da ovu vrednost postavite na najmanje 14 dana, inače kartice za pregled veza neće biti ažurirane na zahtev pre tog vremena. peers_api_enabled: Lista domena sa kojima se ovaj server susreo u fediverzumu. Ovde nisu sadržani podaci o tome da li se Vaš server federiše sa drugim serverima, već samo da Vaš server zna za njih. Ove informacije koriste servisi koji prikupljaju podatke i vode statistiku o federaciji u širem smislu. profile_directory: Direktorijum profila navodi sve korisnike koji su se opredelili da budu vidljivi. require_invite_text: Kada registracije zahtevaju ručno odobrenje, postavite da odgovor na „Zašto želite da se pridružite?“ bude obavezan, a ne opcionalan @@ -240,6 +243,7 @@ sr-Latn: backups_retention_period: Period čuvanja korisničke arhive bootstrap_timeline_accounts: Uvek preporuči ove naloge novim korisnicima closed_registrations_message: Prilagođena poruka kada prijave nisu moguće + content_cache_retention_period: Period zadržavanja udaljenog sadržaja custom_css: Prilagođeni CSS mascot: Prilagođena maskota (nasleđe) media_cache_retention_period: Period čuvanja keša medija diff --git a/config/locales/simple_form.sr.yml b/config/locales/simple_form.sr.yml index 006f4cf6d2..4ec8374075 100644 --- a/config/locales/simple_form.sr.yml +++ b/config/locales/simple_form.sr.yml @@ -77,10 +77,13 @@ sr: warn: Сакриј филтрирани садржај иза упозорења у коме се наводи назив филтера form_admin_settings: activity_api_enabled: Бројеви локално постављених објава, активних корисника и нових регистрација на недељној бази + backups_retention_period: Корисници имају могућност да генеришу архиве својих објава за касније преузимање. Када се подесе на позитивну вредност, ове архиве ће се аутоматски избрисати из вашег складишта након наведеног броја дана. bootstrap_timeline_accounts: Ови налози ће бити закачени на врх препорука за праћење нових корисника. closed_registrations_message: Приказује се када су регистрације затворене + content_cache_retention_period: Све објаве са других сервера (укључујући подржавања и одговоре) ће бити избрисане након наведеног броја дана, без обзира на било какву интеракцију локалног корисника са тим објавама. Ово укључује објаве у којима их је локални корисник означио као обележиваче или омиљене. Приватна помињања између корисника са различитих инстанци ће такође бити изгубљена и немогуће их је вратити. Коришћење ове поставке је намењено за случајеве посебне намене и крши многа очекивања корисника када се примени за употребу опште намене. custom_css: Можете да примените прилагођене стилове на веб верзији Mastodon-а. mascot: Замењује илустрацију у напредном веб окружењу. + media_cache_retention_period: Медијске датотеке из објава удаљених корисника се кеширају на вашем серверу. Када се подеси на позитивну вредност, медији ће бити избрисани након наведеног броја дана. Ако се медијски подаци захтевају након брисања, биће поново преузети, ако је изворни садржај и даље доступан. Због ограничења колико често картице за преглед веза анкетирају сајтове трећих страна, препоручује се да ову вредност поставите на најмање 14 дана, иначе картице за преглед веза неће бити ажуриране на захтев пре тог времена. peers_api_enabled: Листа домена са којима се овај сервер сусрео у федиверзуму. Овде нису садржани подаци о томе да ли се Ваш сервер федерише са другим серверима, већ само да Ваш сервер зна за њих. Ове информације користе сервиси који прикупљају податке и воде статистику о федерацији у ширем смислу. profile_directory: Директоријум профила наводи све кориснике који су се определили да буду видљиви. require_invite_text: Када регистрације захтевају ручно одобрење, поставите да одговор на „Зашто желите да се придружите?“ буде обавезан, а не опционалан @@ -240,6 +243,7 @@ sr: backups_retention_period: Период чувања корисничке архиве bootstrap_timeline_accounts: Увек препоручи ове налоге новим корисницима closed_registrations_message: Прилагођена порука када пријаве нису могуће + content_cache_retention_period: Период задржавања удаљеног садржаја custom_css: Прилагођени CSS mascot: Прилагођена маскота (наслеђе) media_cache_retention_period: Период чувања кеша медија diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml index 3ab16bf69b..5e5c6f9549 100644 --- a/config/locales/simple_form.sv.yml +++ b/config/locales/simple_form.sv.yml @@ -77,10 +77,13 @@ sv: warn: Dölj det filtrerade innehållet bakom en varning som visar filtrets rubrik form_admin_settings: activity_api_enabled: Antalet lokalt publicerade inlägg, aktiva användare och nya registrerade konton per vecka + backups_retention_period: Användare har möjlighet att generera arkiv av sina inlägg för att ladda ned senare. När det sätts till ett positivt värde raderas dessa arkiv automatiskt från din lagring efter det angivna antalet dagar. bootstrap_timeline_accounts: Dessa konton kommer fästas högst upp i nya användares följrekommendationer. closed_registrations_message: Visas när nyregistreringar är avstängda + content_cache_retention_period: Alla inlägg från andra servrar (inklusive booster och svar) kommer att raderas efter det angivna antalet dagar, utan hänsyn till någon lokal användarinteraktion med dessa inlägg. Detta inkluderar inlägg där en lokal användare har markerat det som bokmärke eller favoriter. Privata omnämnanden mellan användare från olika instanser kommer också att gå förlorade och blir omöjliga att återställa. Användningen av denna inställning är avsedd för specialfall och bryter många användarförväntningar när de implementeras för allmänt bruk. custom_css: Du kan använda anpassade stilar på webbversionen av Mastodon. mascot: Åsidosätter illustrationen i det avancerade webbgränssnittet. + media_cache_retention_period: Mediafiler från inlägg som gjorts av fjärranvändare cachas på din server. När inställd på ett positivt värde kommer media att raderas efter det angivna antalet dagar. Om mediadatat begärs efter att det har raderats, kommer det att laddas ned igen om källinnehållet fortfarande är tillgängligt. På grund av begränsningar för hur ofta förhandsgranskningskort för länkar hämtas från tredjepartswebbplatser, rekommenderas det att ange detta värde till minst 14 dagar, annars kommer förhandsgranskningskorten inte att uppdateras på begäran före den tiden. peers_api_enabled: En lista över domänen den här servern har stött på i fediversum. Ingen data inkluderas om du har federerat med servern, bara att din server känner till den. Detta används av tjänster som samlar statistik om federering i allmänhet. profile_directory: Profilkatalogen visar alla användare som har samtyckt till att bli upptäckbara. require_invite_text: Gör fältet "Varför vill du gå med?" obligatoriskt när nyregistreringar kräver manuellt godkännande @@ -240,6 +243,7 @@ sv: backups_retention_period: Lagringsperiod för användararkivet bootstrap_timeline_accounts: Rekommendera alltid dessa konton till nya användare closed_registrations_message: Anpassat meddelande när nyregistreringar inte är tillgängliga + content_cache_retention_period: Förvaringsperiod för fjärrinnehåll custom_css: Anpassad CSS mascot: Anpassad maskot (tekniskt arv) media_cache_retention_period: Tid för bibehållande av mediecache diff --git a/config/locales/sk.yml b/config/locales/sk.yml index d4cd865854..400059770b 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -236,10 +236,12 @@ sk: confirm_user_html: "%{name} potvrdil/a emailovú adresu používateľa %{target}" create_account_warning_html: "%{name} poslal/a upozornenie užívateľovi %{target}" create_announcement_html: "%{name} vytvoril/a nové oboznámenie %{target}" + create_canonical_email_block_html: "%{name} zablokoval/a email s hašom %{target}" create_custom_emoji_html: "%{name} nahral/a novú emotikonu %{target}" create_domain_allow_html: "%{name} povolil/a federáciu s doménou %{target}" create_domain_block_html: "%{name} zablokoval/a doménu %{target}" create_email_domain_block_html: "%{name} zablokoval/a e-mailovú doménu %{target}" + create_ip_block_html: "%{name} vytvoril/a pravidlo pre IP %{target}" create_user_role_html: "%{name} vytvoril/a rolu pre %{target}" demote_user_html: "%{name} degradoval/a užívateľa %{target}" destroy_announcement_html: "%{name} vymazal/a oboznámenie %{target}" @@ -621,6 +623,7 @@ sk: branding: title: Značka content_retention: + danger_zone: Riziková zóna title: Ponechanie obsahu discovery: follow_recommendations: Odporúčania pre nasledovanie @@ -726,10 +729,16 @@ sk: tags: dashboard: tag_accounts_measure: unikátnych použití + tag_languages_dimension: Najpoužívanejšie jazyky + tag_servers_dimension: Najpoužívanejšie servery tag_servers_measure: iné servery tag_uses_measure: užívateľov celkovo + listable: Môže byť navrhnutý + not_listable: Nebude navrhnutý + not_trendable: Neobjaví sa medzi trendmi not_usable: Nemôže byť použitý title: Populárne štítky + trendable: Môže sa objaviť medzi trendmi trending_rank: 'Populárne #%{rank}' usable: Môže byť použitý title: Trendy @@ -752,6 +761,7 @@ sk: new_appeal: actions: delete_statuses: vymazať ich príspevky + disable: zmraziť ich účet none: varovanie silence: obmedziť ich účet new_pending_account: @@ -888,14 +898,21 @@ sk: strikes: action_taken: Vykonaný zákrok appeal: Namietni + appeal_submitted_at: Námietka odoslaná appeals: submit: Pošli námietku approve_appeal: Schváľ námietku created_at: Dátumom recipient: Adresované pre + reject_appeal: Zamietni námietku title_actions: + disable: Zmrazenie účtu + mark_statuses_as_sensitive: Označenie príspevkov za chúlostivé none: Varovanie + sensitive: Označenie účtu ako chúlostivý silence: Obmedzenie účtu + your_appeal_approved: Tvoja námietka bola schválená + your_appeal_pending: Odoslal si námietku domain_validator: invalid_domain: nieje správny tvar domény edit_profile: @@ -956,7 +973,11 @@ sk: expires_on: Expiruje dňa %{date} title: Triedenia new: + save: Uložiť nový filter title: Pridaj nové triedenie + statuses: + batch: + remove: Odstrániť z filtrovania generic: all: Všetko cancel: Zruš @@ -975,15 +996,28 @@ sk: imports: errors: over_rows_processing_limit: obsahuje viac než %{count} riadkov + too_large: Súbor je príliš veľký + failures: Zlyhaní(a) + imported: Nahrané modes: merge: Spoj dohromady merge_long: Ponechaj existujúce záznamy a pridaj k nim nové overwrite: Prepíš overwrite_long: Nahraď súčasné záznamy novými preface: Môžeš nahrať dáta ktoré si exportoval/a z iného Mastodon serveru, ako sú napríklad zoznamy ľudí ktorých sleduješ, alebo blokuješ. + recent_imports: Nedávne nahrania + states: + finished: Dokončené + unconfirmed: Nepotvrdených + status: Stav success: Tvoje dáta boli nahraté úspešne, a teraz budú spracované v danom čase + titles: + bookmarks: Nahrávanie záložiek + domain_blocking: Nahrávanie blokovaných domén + lists: Nahrávanie zoznamov type_groups: constructive: Sledovania a záložky + destructive: Blokovania a utíšenia types: blocking: Zoznam blokovaných bookmarks: Záložky @@ -1026,6 +1060,9 @@ sk: sign_in_token: emailovým bezpečtnostným kódom webauthn: bezpečnostnými kľúčmi title: História overení + mail_subscriptions: + unsubscribe: + title: Ukonči odber media_attachments: validations: images_and_video: K príspevku ktorý už obsahuje obrázky nemôžeš priložiť video @@ -1121,7 +1158,11 @@ sk: posting_defaults: Východiskové nastavenia príspevkov public_timelines: Verejné časové osi privacy: + privacy: Súkromie + search: Vyhľadávanie title: Súkromie a dosah + privacy_policy: + title: Pravidlá ochrany súkromia reactions: errors: limit_reached: Maximálny počet rôznorodých reakcií bol dosiahnutý @@ -1152,6 +1193,11 @@ sk: status: Stav účtu remote_follow: missing_resource: Nemožno nájsť potrebnú presmerovaciu adresu k tvojmu účtu + rss: + content_warning: 'Varovanie o obsahu:' + descriptions: + account: Verejné príspevky od @%{acct} + tag: 'Verejné príspevky otagované #%{hashtag}' scheduled_statuses: over_daily_limit: Prekročil/a si denný limit %{limit} predplánovaných príspevkov over_total_limit: Prekročil/a si limit %{limit} predplánovaných príspevkov @@ -1203,6 +1249,7 @@ sk: profile: Profil relationships: Sledovania a následovatelia two_factor_authentication: Dvojfázové overenie + webauthn_authentication: Bezpečnostné kľúče severed_relationships: lost_followers: Stratení nasledovatelia lost_follows: Stratené sledovania @@ -1216,11 +1263,13 @@ sk: other: "%{count} obrázky" boosted_from_html: Vyzdvihnuté od %{acct_link} content_warning: 'Varovanie o obsahu: %{warning}' + default_language: Rovnaký ako jazyk rozhrania disallowed_hashtags: few: 'obsah nepovolených haštagov: %{tags}' many: 'obsah nepovolených haštagov: %{tags}' one: 'obsahoval nepovolený haštag: %{tags}' other: 'obsahoval nepovolené haštagy: %{tags}' + edited_at_html: Upravené %{date} errors: in_reply_not_found: Príspevok, na ktorý sa snažíš odpovedať, pravdepodobne neexistuje. open_in_web: Otvor v okne na webe @@ -1245,6 +1294,7 @@ sk: show_thread: Ukáž diskusné vlákno title: '%{name}: „%{quote}"' visibilities: + direct: Súkromne private: Iba pre sledovateľov private_long: Ukáž iba následovateľom public: Verejné @@ -1252,10 +1302,24 @@ sk: unlisted: Nezaradené unlisted_long: Všetci môžu vidieť, ale nieje zaradené do verejnej osi statuses_cleanup: + exceptions: Výnimky + ignore_favs: Ignoruj obľúbené + ignore_reblogs: Ignoruj vyzdvihnutia + keep_direct: Ponechaj súkromné správy keep_pinned: Ponechaj pripnuté príspevky keep_pinned_hint: Nevymaže žiadne s tvojich pripnutých príspevkov + keep_polls: Ponechaj ankety keep_self_bookmark: Ponechaj príspevky, ktoré sú záložkami keep_self_fav: Ponechať príspevky, ktoré si si obľúbil/a + min_age: + '1209600': 2 týždne + '15778476': 6 mesačné + '2629746': 1 mesačné + '31556952': 1 ročné + '5259492': 2 mesačné + '604800': 1 týždeň + '63113904': 2 ročné + '7889238': 3 mesačné stream_entries: sensitive_content: Senzitívny obsah tags: @@ -1282,8 +1346,10 @@ sk: user_mailer: appeal_approved: action: Nastavenia účtu + title: Námietka schválená appeal_rejected: subtitle: Tvoje odvolanie bolo zamietnuté. + title: Námietka zamietnutá backup_ready: explanation: Vyžiadal/a si si úplnú zálohu svojho Mastodon účtu. extra: Teraz je pripravená na stiahnutie! @@ -1291,23 +1357,36 @@ sk: title: Odber archívu failed_2fa: details: 'Tu sú podrobnosti o pokuse o prihlásenie:' + suspicious_sign_in: + change_password: zmeň svoje heslo + title: Nové prihlásenie warning: + appeal: Pošli námietku + reason: 'Dôvod:' subject: disable: Tvoj účet %{acct} bol zamrazený none: Varovanie pre %{acct} silence: Tvoj účet %{acct} bol obmedzený suspend: Tvoj účet %{acct} bol vylúčený title: + delete_statuses: Príspevky vymazané disable: Účet bol zamrazený + mark_statuses_as_sensitive: Príspevky označené za chúlostivé none: Varovanie + sensitive: Účet označený za chúlostivý silence: Účet bol obmedzený suspend: Tvoj účet bol vylúčený welcome: + apps_android_action: Získaj ju na Google Play + apps_ios_action: Stiahni z App Store + apps_step: Stiahni naše oficiálne aplikácie. apps_title: Mastodon aplikácie edit_profile_action: Prispôsob + edit_profile_title: Prispôsob si svoj profil explanation: Tu nájdeš nejaké tipy do začiatku feature_action: Zisti viac follow_action: Nasleduj + follows_title: Koho nasledovať post_title: Vytvor svoj prvý príspevok share_action: Zdieľaj sign_in_action: Prihlás sa diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index e0fe9a710d..b4976f8985 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -765,6 +765,7 @@ sr-Latn: desc_html: Ovo se oslanja na eksterne skripte iz hCaptcha, što može predstavljati zabrinutost za bezbednost i privatnost. Pored toga, ovo može učiniti proces registracije znatno manje dostupnim nekim (posebno osobama sa invaliditetom). Iz ovih razloga, razmotrite alternativne mere kao što je registracija zasnovana na odobrenju ili na pozivu. title: Zahtevaj od novih korisnika da reše CAPTCHA da bi potvrdili svoj nalog content_retention: + danger_zone: Opasna zona preamble: Kontrolišite kako se sadržaj generisan od strane korisnika skladišti na Mastodon-u. title: Zadržavanje sadržaja default_noindex: diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 1c4ffc8c09..aec6d399d5 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -765,6 +765,7 @@ sr: desc_html: Ово се ослања на екстерне скрипте из hCaptcha, што може представљати забринутост за безбедност и приватност. Поред тога, ово може учинити процес регистрације знатно мање доступним неким (посебно особама са инвалидитетом). Из ових разлога, размотрите алтернативне мере као што је регистрација заснована на одобрењу или на позиву. title: Захтевај од нових корисника да реше CAPTCHA да би потврдили свој налог content_retention: + danger_zone: Опасна зона preamble: Контролишите како се садржај генерисан од стране корисника складишти на Mastodon-у. title: Задржавање садржаја default_noindex: diff --git a/db/migrate/20231210154528_add_otp_secret_to_user.rb b/db/migrate/20231210154528_add_otp_secret_to_user.rb new file mode 100644 index 0000000000..b2ce0a4f79 --- /dev/null +++ b/db/migrate/20231210154528_add_otp_secret_to_user.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddOtpSecretToUser < ActiveRecord::Migration[7.1] + def change + add_column :users, :otp_secret, :string + end +end diff --git a/db/post_migrate/20240307180905_migrate_devise_two_factor_secrets.rb b/db/post_migrate/20240307180905_migrate_devise_two_factor_secrets.rb new file mode 100644 index 0000000000..360e4806da --- /dev/null +++ b/db/post_migrate/20240307180905_migrate_devise_two_factor_secrets.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +class MigrateDeviseTwoFactorSecrets < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + class MigrationUser < ApplicationRecord + self.table_name = :users + + devise :two_factor_authenticatable, + otp_secret_encryption_key: Rails.configuration.x.otp_secret + + include LegacyOtpSecret # Must be after the above `devise` line in order to override the legacy method + end + + def up + MigrationUser.reset_column_information + + users_with_otp_enabled.find_each do |user| + # Gets the new value on already-updated users + # Falls back to legacy value on not-yet-migrated users + otp_secret = user.otp_secret + + Rails.logger.debug { "Processing #{user.email}" } + + # This is a no-op for migrated users and updates format for not migrated + user.update!(otp_secret: otp_secret) + end + end + + def down + raise ActiveRecord::IrreversibleMigration + end + + private + + def users_with_otp_enabled + MigrationUser.where(otp_required_for_login: true, otp_secret: nil) + end +end diff --git a/db/schema.rb b/db/schema.rb index 0e4dffe4f3..b43f57b000 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1202,6 +1202,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.bigint "role_id" t.text "settings" t.string "time_zone" + t.string "otp_secret" t.index ["account_id"], name: "index_users_on_account_id" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["created_by_application_id"], name: "index_users_on_created_by_application_id", where: "(created_by_application_id IS NOT NULL)" diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index 4208c2ae4b..07de087766 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -1,6 +1,22 @@ # frozen_string_literal: true +# We are providing our own task with our own format +Rake::Task['db:encryption:init'].clear + namespace :db do + namespace :encryption do + desc 'Generate a set of keys for configuring Active Record encryption in a given environment' + task init: :environment do + puts <<~MSG + Add these environment variables to your Mastodon environment:#{' '} + + ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=#{SecureRandom.alphanumeric(32)} + ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=#{SecureRandom.alphanumeric(32)} + ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=#{SecureRandom.alphanumeric(32)} + MSG + end + end + namespace :migrate do desc 'Setup the db or migrate depending on state of db' task setup: :environment do diff --git a/lib/tasks/tests.rake b/lib/tasks/tests.rake index 0caebf92a1..c8e0312bbd 100644 --- a/lib/tasks/tests.rake +++ b/lib/tasks/tests.rake @@ -127,6 +127,14 @@ namespace :tests do exit(1) end + # This is checking the attribute rather than the method, to avoid the legacy fallback + # and ensure the data has been migrated + unless Account.find_local('qcuser').user[:otp_secret] == 'anotpsecretthatshouldbeencrypted' + puts "DEBUG: #{Account.find_local('qcuser').user.inspect}" + puts 'OTP secret for user not preserved as expected' + exit(1) + end + puts 'No errors found. Database state is consistent with a successful migration process.' end @@ -213,9 +221,15 @@ namespace :tests do (4, 10, 'kmruser@localhost', now(), now(), false, 'ku', '{en,kmr,ku,ckb}'); INSERT INTO "users" - (id, account_id, email, created_at, updated_at, locale) + (id, account_id, email, created_at, updated_at, locale, + encrypted_otp_secret, encrypted_otp_secret_iv, encrypted_otp_secret_salt, + otp_required_for_login) VALUES - (5, 11, 'qcuser@localhost', now(), now(), 'fr-QC'); + (5, 11, 'qcuser@localhost', now(), now(), 'fr-QC', + E'Fttsy7QAa0edaDfdfSz094rRLAxc8cJweDQ4BsWH/zozcdVA8o9GLqcKhn2b\nGi/V\n', + 'rys3THICkr60BoWC', + '_LMkAGvdg7a+sDIKjI3mR2Q==', + true); INSERT INTO "settings" (id, thing_type, thing_id, var, value, created_at, updated_at) diff --git a/package.json b/package.json index 769d09397d..1b2a8f624e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/mastodon", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.1.1", + "packageManager": "yarn@4.2.1", "engines": { "node": ">=18" }, diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 714d595dc1..fa0a0503a6 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -9,14 +9,25 @@ RSpec.describe User do it_behaves_like 'two_factor_backupable' - describe 'otp_secret' do + describe 'legacy_otp_secret' do it 'is encrypted with OTP_SECRET environment variable' do user = Fabricate(:user, encrypted_otp_secret: "Fttsy7QAa0edaDfdfSz094rRLAxc8cJweDQ4BsWH/zozcdVA8o9GLqcKhn2b\nGi/V\n", encrypted_otp_secret_iv: 'rys3THICkr60BoWC', encrypted_otp_secret_salt: '_LMkAGvdg7a+sDIKjI3mR2Q==') - expect(user.otp_secret).to eq 'anotpsecretthatshouldbeencrypted' + expect(user.send(:legacy_otp_secret)).to eq 'anotpsecretthatshouldbeencrypted' + end + end + + describe 'otp_secret' do + it 'encrypts the saved value' do + user = Fabricate(:user, otp_secret: '123123123') + + user.reload + + expect(user.otp_secret).to eq '123123123' + expect(user.attributes_before_type_cast[:otp_secret]).to_not eq '123123123' end end diff --git a/spec/requests/api/v1/admin/domain_blocks_spec.rb b/spec/requests/api/v1/admin/domain_blocks_spec.rb index 47aaf44d80..415281a932 100644 --- a/spec/requests/api/v1/admin/domain_blocks_spec.rb +++ b/spec/requests/api/v1/admin/domain_blocks_spec.rb @@ -130,7 +130,7 @@ RSpec.describe 'Domain Blocks' do it_behaves_like 'forbidden for wrong role', '' it_behaves_like 'forbidden for wrong role', 'Moderator' - it 'returns expected domain name and severity', :aggregate_failures do + it 'creates a domain block with the expected domain name and severity', :aggregate_failures do subject body = body_as_json @@ -146,7 +146,44 @@ RSpec.describe 'Domain Blocks' do expect(DomainBlock.find_by(domain: 'foo.bar.com')).to be_present end - context 'when a stricter domain block already exists' do + context 'when a looser domain block already exists on a higher level domain' do + let(:params) { { domain: 'foo.bar.com', severity: :suspend } } + + before do + Fabricate(:domain_block, domain: 'bar.com', severity: :silence) + end + + it 'creates a domain block with the expected domain name and severity', :aggregate_failures do + subject + + body = body_as_json + + expect(response).to have_http_status(200) + expect(body).to match a_hash_including( + { + domain: 'foo.bar.com', + severity: 'suspend', + } + ) + + expect(DomainBlock.find_by(domain: 'foo.bar.com')).to be_present + end + end + + context 'when a domain block already exists on the same domain' do + before do + Fabricate(:domain_block, domain: 'foo.bar.com', severity: :silence) + end + + it 'returns existing domain block in error', :aggregate_failures do + subject + + expect(response).to have_http_status(422) + expect(body_as_json[:existing_domain_block][:domain]).to eq('foo.bar.com') + end + end + + context 'when a stricter domain block already exists on a higher level domain' do before do Fabricate(:domain_block, domain: 'bar.com', severity: :suspend) end diff --git a/spec/validators/status_length_validator_spec.rb b/spec/validators/status_length_validator_spec.rb index 614f5d3909..ead69dfe21 100644 --- a/spec/validators/status_length_validator_spec.rb +++ b/spec/validators/status_length_validator_spec.rb @@ -4,6 +4,8 @@ require 'rails_helper' describe StatusLengthValidator do describe '#validate' do + before { stub_const("#{described_class}::MAX_CHARS", 500) } # Example values below are relative to this baseline + it 'does not add errors onto remote statuses' do status = instance_double(Status, local?: false) allow(status).to receive(:errors) @@ -22,32 +24,27 @@ describe StatusLengthValidator do expect(status).to_not have_received(:errors) end - it 'adds an error when content warning is over MAX_CHARS characters' do - chars = StatusLengthValidator::MAX_CHARS + 1 - status = instance_double(Status, spoiler_text: 'a' * chars, text: '', errors: activemodel_errors, local?: true, reblog?: false) + it 'adds an error when content warning is over character limit' do + status = status_double(spoiler_text: 'a' * 520) subject.validate(status) expect(status.errors).to have_received(:add) end - it 'adds an error when text is over MAX_CHARS characters' do - chars = StatusLengthValidator::MAX_CHARS + 1 - status = instance_double(Status, spoiler_text: '', text: 'a' * chars, errors: activemodel_errors, local?: true, reblog?: false) + it 'adds an error when text is over character limit' do + status = status_double(text: 'a' * 520) subject.validate(status) expect(status.errors).to have_received(:add) end - it 'adds an error when text and content warning are over MAX_CHARS characters total' do - chars1 = 20 - chars2 = StatusLengthValidator::MAX_CHARS + 1 - chars1 - status = instance_double(Status, spoiler_text: 'a' * chars1, text: 'b' * chars2, errors: activemodel_errors, local?: true, reblog?: false) + it 'adds an error when text and content warning are over character limit total' do + status = status_double(spoiler_text: 'a' * 250, text: 'b' * 251) subject.validate(status) expect(status.errors).to have_received(:add) end it 'counts URLs as 23 characters flat' do - chars = StatusLengthValidator::MAX_CHARS - 1 - 23 - text = ('a' * chars) + " http://#{'b' * 30}.com/example" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) + text = ('a' * 476) + " http://#{'b' * 30}.com/example" + status = status_double(text: text) subject.validate(status) expect(status.errors).to_not have_received(:add) @@ -55,7 +52,7 @@ describe StatusLengthValidator do it 'does not count non-autolinkable URLs as 23 characters flat' do text = ('a' * 476) + "http://#{'b' * 30}.com/example" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) + status = status_double(text: text) subject.validate(status) expect(status.errors).to have_received(:add) @@ -63,16 +60,14 @@ describe StatusLengthValidator do it 'does not count overly long URLs as 23 characters flat' do text = "http://example.com/valid?#{'#foo?' * 1000}" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) + status = status_double(text: text) subject.validate(status) expect(status.errors).to have_received(:add) end it 'counts only the front part of remote usernames' do - username = '@alice' - chars = StatusLengthValidator::MAX_CHARS - 1 - username.length - text = ('a' * chars) + " #{username}@#{'b' * 30}.com" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) + text = ('a' * 475) + " @alice@#{'b' * 30}.com" + status = status_double(text: text) subject.validate(status) expect(status.errors).to_not have_received(:add) @@ -80,7 +75,7 @@ describe StatusLengthValidator do it 'does count both parts of remote usernames for overly long domains' do text = "@alice@#{'b' * 500}.com" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) + status = status_double(text: text) subject.validate(status) expect(status.errors).to have_received(:add) @@ -89,6 +84,17 @@ describe StatusLengthValidator do private + def status_double(spoiler_text: '', text: '') + instance_double( + Status, + spoiler_text: spoiler_text, + text: text, + errors: activemodel_errors, + local?: true, + reblog?: false + ) + end + def activemodel_errors instance_double(ActiveModel::Errors, add: nil) end diff --git a/streaming/package.json b/streaming/package.json index a0e7d96bb5..c4dcccf1f5 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/streaming", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.1.1", + "packageManager": "yarn@4.2.1", "engines": { "node": ">=18" },