Merge commit 'b7902225d698a107df2cf8b4ca221caad38fa464' into glitch-soc/merge-upstream
Conflicts: - `spec/validators/status_length_validator_spec.rb`: Upstream refactored tests to stub `StatusLengthValidator::MAX_CHARS` while glitch-soc had custom code to read from `MAX_TOOT_CHARS`. Switched to using upstream's implementation of the tests.
This commit is contained in:
commit
3789d9f825
49 changed files with 911 additions and 205 deletions
21
.github/stylelint-matcher.json
vendored
21
.github/stylelint-matcher.json
vendored
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
6
.github/workflows/lint-css.yml
vendored
6
.github/workflows/lint-css.yml
vendored
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
2
Gemfile
2
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'
|
||||
|
|
14
Gemfile.lock
14
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
});
|
197
app/javascript/entrypoints/two_factor_authentication.ts
Normal file
197
app/javascript/entrypoints/two_factor_authentication.ts
Normal file
|
@ -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<HTMLMetaElement>('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<PublicKeyCredentialCreationOptionsJSON>(
|
||||
'/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<PublicKeyCredentialCreationOptionsJSON>(
|
||||
'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<HTMLButtonElement>(
|
||||
'button.btn.js-webauthn',
|
||||
);
|
||||
if (button) button.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
const webAuthnCredentialRegistrationForm =
|
||||
document.querySelector<HTMLFormElement>('form#new_webauthn_credential');
|
||||
if (webAuthnCredentialRegistrationForm) {
|
||||
webAuthnCredentialRegistrationForm.addEventListener('submit', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (!(event.target instanceof HTMLFormElement)) return;
|
||||
|
||||
const nickname = event.target.querySelector<HTMLInputElement>(
|
||||
'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;
|
||||
});
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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} је подржао вашу објаву",
|
||||
|
|
|
@ -10145,6 +10145,7 @@ noscript {
|
|||
font-weight: 500;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
word-break: keep-all;
|
||||
|
||||
&__badge {
|
||||
background: $ui-button-background-color;
|
||||
|
|
|
@ -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
|
||||
|
|
77
app/models/concerns/legacy_otp_secret.rb
Normal file
77
app/models/concerns/legacy_otp_secret.rb
Normal file
|
@ -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
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -174,6 +174,7 @@ sr:
|
|||
read:filters: погледај своје филтере
|
||||
read:follows: погледај кога пратиш
|
||||
read:lists: погледај своје листе
|
||||
read:me: чита само основне информације о вашем налогу
|
||||
read:mutes: погледај игнорисања
|
||||
read:notifications: погледај своја обавештења
|
||||
read:reports: погледај своје пријаве
|
||||
|
|
|
@ -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 <strong>spam</strong>-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 <strong>jo</strong> 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 <strong>dit it registraasjeproses bot minder tagonklik meitsje foar guon (foaral handicapte) minsken</strong>. 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
|
||||
|
|
|
@ -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 <strong>repetitor de federation</strong> es un servitor intermediari que excambia grande volumines de messages public inter le servitores que se inscribe e publica a illo. <strong>Illo pote adjutar le servitores micre e medie a discoperir le contento del fediverso</strong>, 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 <a href="%{settings_path}">parametros de notification in e-mail</a>.
|
||||
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 <a href="%{settings_path}">parametros de notification in e-mail</a>.
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <a href="%{path}">adder avisos preconfigurate</a> pro sparniar tempore
|
||||
type_html: Selige lo que tu vole facer con <strong>%{acct}</strong>
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: Период чувања кеша медија
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, <strong>ovo može učiniti proces registracije znatno manje dostupnim nekim (posebno osobama sa invaliditetom)</strong>. 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:
|
||||
|
|
|
@ -765,6 +765,7 @@ sr:
|
|||
desc_html: Ово се ослања на екстерне скрипте из hCaptcha, што може представљати забринутост за безбедност и приватност. Поред тога, <strong>ово може учинити процес регистрације знатно мање доступним неким (посебно особама са инвалидитетом)</strong>. Из ових разлога, размотрите алтернативне мере као што је регистрација заснована на одобрењу или на позиву.
|
||||
title: Захтевај од нових корисника да реше CAPTCHA да би потврдили свој налог
|
||||
content_retention:
|
||||
danger_zone: Опасна зона
|
||||
preamble: Контролишите како се садржај генерисан од стране корисника складишти на Mastodon-у.
|
||||
title: Задржавање садржаја
|
||||
default_noindex:
|
||||
|
|
7
db/migrate/20231210154528_add_otp_secret_to_user.rb
Normal file
7
db/migrate/20231210154528_add_otp_secret_to_user.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddOtpSecretToUser < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
add_column :users, :otp_secret, :string
|
||||
end
|
||||
end
|
|
@ -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
|
|
@ -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)"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue