diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt index 4b6d470a1c..3c268af808 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt @@ -37,6 +37,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip05DnsIdentifiers.Nip05Client import com.vitorpamplona.quartz.nip06KeyDerivation.Nip06 +import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser import com.vitorpamplona.quartz.nip19Bech32.decodePrivateKeyAsHexOrNull import com.vitorpamplona.quartz.nip19Bech32.decodePublicKeyAsHexOrNull @@ -202,14 +203,17 @@ class AccountSessionManager( packageName: String = "", onError: (String?) -> Unit, ) { + // Accepts keys copied by hand from the backup screen: UPPERCASE, and split + // into groups by spaces, dashes or line breaks. + val cleanKey = Bech32Transcription.normalize(key) scope.launch(Dispatchers.IO) { - if (key.startsWith("ncryptsec")) { + if (cleanKey.startsWith("ncryptsec")) { val newKey = try { - if (key.isEmpty() || password.isEmpty()) { + if (cleanKey.isEmpty() || password.isEmpty()) { null } else { - Nip49().decrypt(key, password) + Nip49().decrypt(cleanKey, password) } } catch (e: Exception) { if (e is CancellationException) throw e @@ -223,24 +227,24 @@ class AccountSessionManager( } else { loginSync(newKey, transientAccount, loginWithExternalSigner, packageName, onError) } - } else if (EMAIL_PATTERN.matcher(key).matches()) { + } else if (EMAIL_PATTERN.matcher(cleanKey).matches()) { // Delegate to the shared quartz resolver so NIP-05 handling stays in // lockstep with the CLI and anywhere else we accept user identifiers. try { val hex = com.vitorpamplona.quartz.nip05DnsIdentifiers - .resolveUserHexOrNull(key, nip05ClientBuilder()) + .resolveUserHexOrNull(cleanKey, nip05ClientBuilder()) if (hex == null) { - onError("User not found in the nip05 server: $key") + onError("User not found in the nip05 server: $cleanKey") } else { loginSync(Hex.decode(hex).toNpub(), transientAccount, loginWithExternalSigner, packageName, onError) } } catch (e: Exception) { if (e is CancellationException) throw e - onError("Could not load nip05 address from the server: $key. ${e.message}") + onError("Could not load nip05 address from the server: $cleanKey. ${e.message}") } } else { - loginSync(key, transientAccount, loginWithExternalSigner, packageName, onError) + loginSync(cleanKey, transientAccount, loginWithExternalSigner, packageName, onError) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/AccountBackupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/AccountBackupScreen.kt index de2b248ff6..5468d27777 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/AccountBackupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/AccountBackupScreen.kt @@ -24,36 +24,46 @@ import android.app.Activity import android.content.ClipData import android.content.Context import android.content.ContextWrapper +import android.os.PersistableBundle import android.view.WindowManager import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.ActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.MutableState +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -62,77 +72,90 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.autofill.ContentType +import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.ClipEntry import androidx.compose.ui.platform.Clipboard import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.semantics.contentType import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation -import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.fragment.app.FragmentActivity -import com.halilibo.richtext.commonmark.CommonMarkdownParseOptions -import com.halilibo.richtext.commonmark.CommonmarkAstNodeParser -import com.halilibo.richtext.markdown.BasicMarkdown -import com.halilibo.richtext.ui.RichTextStyle -import com.halilibo.richtext.ui.material3.RichText -import com.halilibo.richtext.ui.resolveDefaults -import com.vitorpamplona.amethyst.R +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.compose.LifecycleEventEffect +import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.icons.symbols.Icon +import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.resources.Res -import com.vitorpamplona.amethyst.commons.resources.account_backup_tips2_md -import com.vitorpamplona.amethyst.commons.resources.account_backup_tips3_md +import com.vitorpamplona.amethyst.commons.resources.account_backup_encrypt +import com.vitorpamplona.amethyst.commons.resources.account_backup_encrypt_again +import com.vitorpamplona.amethyst.commons.resources.account_backup_encrypted_body +import com.vitorpamplona.amethyst.commons.resources.account_backup_encrypted_password +import com.vitorpamplona.amethyst.commons.resources.account_backup_encrypted_password_mismatch +import com.vitorpamplona.amethyst.commons.resources.account_backup_encrypted_repeat_password +import com.vitorpamplona.amethyst.commons.resources.account_backup_encrypted_saved_hint +import com.vitorpamplona.amethyst.commons.resources.account_backup_encrypted_title +import com.vitorpamplona.amethyst.commons.resources.account_backup_encrypting +import com.vitorpamplona.amethyst.commons.resources.account_backup_headline +import com.vitorpamplona.amethyst.commons.resources.account_backup_intro +import com.vitorpamplona.amethyst.commons.resources.account_backup_password_min_length +import com.vitorpamplona.amethyst.commons.resources.account_backup_qr_code +import com.vitorpamplona.amethyst.commons.resources.account_backup_tap_to_reveal +import com.vitorpamplona.amethyst.commons.resources.account_backup_tip_developers +import com.vitorpamplona.amethyst.commons.resources.account_backup_tip_storage +import com.vitorpamplona.amethyst.commons.resources.account_backup_tip_trust +import com.vitorpamplona.amethyst.commons.resources.account_backup_write_down_hint import com.vitorpamplona.amethyst.commons.resources.backup_keys -import com.vitorpamplona.amethyst.commons.resources.copies_the_nsec_id_your_password_to_the_clipboard_for_backup -import com.vitorpamplona.amethyst.commons.resources.copy_my_secret_key -import com.vitorpamplona.amethyst.commons.resources.encrypt_and_copy_my_secret_key +import com.vitorpamplona.amethyst.commons.resources.backup_keys_copy +import com.vitorpamplona.amethyst.commons.resources.backup_keys_external_signer +import com.vitorpamplona.amethyst.commons.resources.backup_keys_hide +import com.vitorpamplona.amethyst.commons.resources.backup_keys_reveal +import com.vitorpamplona.amethyst.commons.resources.backup_keys_secret_label import com.vitorpamplona.amethyst.commons.resources.failed_to_encrypt_key import com.vitorpamplona.amethyst.commons.resources.hide_password -import com.vitorpamplona.amethyst.commons.resources.ncryptsec_password -import com.vitorpamplona.amethyst.commons.resources.password_is_required import com.vitorpamplona.amethyst.commons.resources.secret_key_copied_to_clipboard -import com.vitorpamplona.amethyst.commons.resources.show_encrypted_private_key_qr_code import com.vitorpamplona.amethyst.commons.resources.show_password -import com.vitorpamplona.amethyst.commons.resources.show_private_key_qr_code +import com.vitorpamplona.amethyst.commons.ui.components.KeyTranscriptionGrid import com.vitorpamplona.amethyst.commons.ui.components.util.getText import com.vitorpamplona.amethyst.commons.ui.components.util.setText +import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder -import com.vitorpamplona.amethyst.commons.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.ui.note.authenticate import com.vitorpamplona.amethyst.ui.note.rememberAuthPromptLabels -import com.vitorpamplona.amethyst.ui.painterRes import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.BackButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer -import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip19Bech32.toNsec import com.vitorpamplona.quartz.nip49PrivKeyEnc.Nip49 import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import org.jetbrains.compose.resources.StringResource +import kotlinx.coroutines.withContext /** Best-effort delay before the plaintext nsec is wiped from the clipboard. */ private const val CLIPBOARD_CLEAR_DELAY_MS = 60_000L +private val CardShape = RoundedCornerShape(16.dp) + @Composable fun AccountBackupScreen( accountViewModel: AccountViewModel, @@ -152,7 +175,6 @@ fun AccountBackupScreenPreview() { } } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun AccountBackupScreenContent( accountViewModel: AccountViewModel, @@ -162,8 +184,6 @@ private fun AccountBackupScreenContent( // screen is on-screen. Cleared on dispose so the flag never leaks to other // screens. This is the only FLAG_SECURE usage in the app — scoped on purpose. val context = LocalContext.current - val authLabels = rememberAuthPromptLabels() - val authLabelCopyKey = stringRes(Res.string.copy_my_secret_key) DisposableEffect(context) { val window = context.getFragmentActivity()?.window window?.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE) @@ -184,217 +204,554 @@ private fun AccountBackupScreenContent( Modifier .fillMaxSize() .padding(it) - .padding(horizontal = 20.dp, vertical = 10.dp) - .verticalScroll(rememberScrollState()), - horizontalAlignment = Alignment.CenterHorizontally, + .consumeWindowInsets(it) + // Keeps the password fields and the Encrypt button above the keyboard. + .imePaddingSafe() + .verticalScroll(rememberScrollState()) + .padding(horizontal = 16.dp, vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), ) { - val content1 = stringRes(Res.string.account_backup_tips2_md) + BackupHeader() - val astNode1 = - remember { - CommonmarkAstNodeParser(CommonMarkdownParseOptions.MarkdownWithLinks).parse(content1) + val nsec = + remember(accountViewModel) { + accountViewModel.account.settings.keyPair.privKey + ?.toNsec() } - RichText( - style = RichTextStyle().resolveDefaults(), - renderer = null, - ) { - BasicMarkdown(astNode1) + if (nsec == null) { + TipRow(MaterialSymbols.Info, stringRes(Res.string.backup_keys_external_signer)) + } else { + val gate = rememberKeyAccessGate(accountViewModel) + + SecretKeyCard(nsec, gate, accountViewModel) + + EncryptedKeyCard(accountViewModel, gate) + + BackupTips() } - - Spacer(modifier = Modifier.height(20.dp)) - - Row { - Column { - NSecCopyButton(accountViewModel) - } - - Column { - QrCodeButton(accountViewModel) - } - } - - Spacer(modifier = Modifier.height(30.dp)) - - val content = stringRes(Res.string.account_backup_tips3_md) - - val astNode = - remember { - CommonmarkAstNodeParser(CommonMarkdownParseOptions.MarkdownWithLinks).parse(content) - } - - RichText( - style = RichTextStyle().resolveDefaults(), - renderer = null, - ) { - BasicMarkdown(astNode) - } - - val password = remember { mutableStateOf(TextFieldValue("")) } - var errorMessage by remember { mutableStateOf("") } - var showCharsPassword by remember { mutableStateOf(false) } - - Spacer(modifier = Modifier.height(20.dp)) - - OutlinedTextField( - modifier = - Modifier - .semantics { contentType = ContentType.Password }, - value = password.value, - onValueChange = { - password.value = it - if (errorMessage.isNotEmpty()) { - errorMessage = "" - } - }, - keyboardOptions = - KeyboardOptions( - autoCorrectEnabled = false, - keyboardType = KeyboardType.Password, - imeAction = ImeAction.Go, - ), - placeholder = { - Text( - text = stringRes(Res.string.ncryptsec_password), - color = MaterialTheme.colorScheme.placeholderText, - ) - }, - trailingIcon = { - Row { - IconButton(onClick = { showCharsPassword = !showCharsPassword }) { - Icon( - symbol = if (showCharsPassword) MaterialSymbols.VisibilityOff else MaterialSymbols.Visibility, - contentDescription = - if (showCharsPassword) { - stringRes(Res.string.show_password) - } else { - stringRes( - Res.string.hide_password, - ) - }, - ) - } - } - }, - visualTransformation = - if (showCharsPassword) VisualTransformation.None else PasswordVisualTransformation(), - ) - - if (errorMessage.isNotBlank()) { - Text( - text = errorMessage, - color = MaterialTheme.colorScheme.error, - style = MaterialTheme.typography.bodySmall, - ) - } - - Spacer(modifier = Modifier.height(10.dp)) - - EncryptNSecCopyButton(accountViewModel, password) } } } @Composable -private fun NSecCopyButton(accountViewModel: AccountViewModel) { - val clipboardManager = LocalClipboard.current +private fun BackupHeader() { + Column( + modifier = Modifier.fillMaxWidth().padding(top = 8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Box( + modifier = + Modifier + .size(56.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.primaryContainer), + contentAlignment = Alignment.Center, + ) { + Icon( + symbol = MaterialSymbols.Key, + contentDescription = null, + tint = MaterialTheme.colorScheme.onPrimaryContainer, + modifier = Modifier.size(28.dp), + ) + } + Spacer(Modifier.height(12.dp)) + Text( + text = stringRes(Res.string.account_backup_headline), + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.SemiBold, + textAlign = TextAlign.Center, + ) + Spacer(Modifier.height(6.dp)) + Text( + text = stringRes(Res.string.account_backup_intro), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center, + ) + } +} + +@Composable +private fun SecretKeyCard( + nsec: String, + gate: KeyAccessGate, + accountViewModel: AccountViewModel, +) { + val context = LocalContext.current + val clipboard = LocalClipboard.current + + var revealed by remember { mutableStateOf(false) } + var showQr by remember { mutableStateOf(false) } + + // Never leave the key on screen while the app is in the background. + LifecycleEventEffect(Lifecycle.Event.ON_STOP) { + revealed = false + showQr = false + gate.lock() + } + + val reveal = { gate.withAccess { revealed = true } } + + Surface( + modifier = Modifier.fillMaxWidth(), + shape = CardShape, + color = MaterialTheme.colorScheme.surfaceContainerHigh, + ) { + Column(Modifier.padding(start = 16.dp, end = 8.dp, top = 8.dp, bottom = 16.dp)) { + Row(verticalAlignment = Alignment.CenterVertically) { + CardTitle(MaterialSymbols.Key, stringRes(Res.string.backup_keys_secret_label), Modifier.weight(1f)) + IconButton(onClick = { if (revealed) revealed = false else reveal() }) { + Icon( + symbol = if (revealed) MaterialSymbols.VisibilityOff else MaterialSymbols.Visibility, + contentDescription = stringRes(if (revealed) Res.string.backup_keys_hide else Res.string.backup_keys_reveal), + ) + } + } + + Column(Modifier.padding(end = 8.dp)) { + Box( + modifier = + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .background(MaterialTheme.colorScheme.surface) + .clickable(enabled = !revealed, onClick = reveal) + .padding(horizontal = 12.dp, vertical = 16.dp), + contentAlignment = Alignment.Center, + ) { + KeyTranscriptionGrid( + bech32 = nsec, + masked = !revealed, + color = if (revealed) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.outlineVariant, + modifier = Modifier.fillMaxWidth(), + ) + if (!revealed) { + RevealChip() + } + } + + Spacer(Modifier.height(8.dp)) + + Text( + text = stringRes(Res.string.account_backup_write_down_hint), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + + Spacer(Modifier.height(12.dp)) + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + FilledTonalButton( + modifier = Modifier.weight(1f), + onClick = { gate.withAccess { copyNSec(context, accountViewModel.viewModelScope, nsec, clipboard) } }, + ) { + ButtonContent(MaterialSymbols.ContentCopy, stringRes(Res.string.backup_keys_copy)) + } + FilledTonalButton( + modifier = Modifier.weight(1f), + onClick = { gate.withAccess { showQr = true } }, + ) { + ButtonContent(MaterialSymbols.QrCode2, stringRes(Res.string.account_backup_qr_code)) + } + } + } + } + } + + if (showQr) { + ShowKeyQRDialog(nsec, onClose = { showQr = false }) + } +} + +@Composable +private fun RevealChip() { + Surface( + shape = CircleShape, + color = MaterialTheme.colorScheme.secondaryContainer, + contentColor = MaterialTheme.colorScheme.onSecondaryContainer, + shadowElevation = 2.dp, + ) { + Row( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon(MaterialSymbols.Visibility, contentDescription = null, modifier = Modifier.size(18.dp)) + Spacer(Modifier.width(8.dp)) + Text(stringRes(Res.string.account_backup_tap_to_reveal), style = MaterialTheme.typography.labelLarge) + } + } +} + +@Composable +private fun EncryptedKeyCard( + accountViewModel: AccountViewModel, + gate: KeyAccessGate, +) { + val context = LocalContext.current + val clipboard = LocalClipboard.current + val scope = rememberCoroutineScope() + val keyboardController = LocalSoftwareKeyboardController.current + + var expanded by remember { mutableStateOf(false) } + var password by remember { mutableStateOf("") } + var repeated by remember { mutableStateOf("") } + var showPassword by remember { mutableStateOf(false) } + var working by remember { mutableStateOf(false) } + var encrypted by remember { mutableStateOf(null) } + var showQr by remember { mutableStateOf(false) } + + // Drop the result while in the background. A password not yet used is kept so switching to + // a password manager to fetch it doesn't wipe the fields; a used one is cleared on success. + LifecycleEventEffect(Lifecycle.Event.ON_STOP) { + encrypted = null + showQr = false + } + + // A typo in the password makes the backup permanently useless, so it must be typed twice. + val mismatch = repeated.isNotEmpty() && repeated != password + val longEnough = Nip49.isLongEnough(password) + val canEncrypt = longEnough && repeated == password && !working + + fun encrypt() { + if (!canEncrypt) return + gate.withAccess { + val privKey = accountViewModel.account.settings.keyPair.privKey ?: return@withAccess + val currentPassword = password + working = true + // NIP-49 runs scrypt, which takes a noticeable moment: keep it off the main thread. + scope.launch { + val result = + withContext(Dispatchers.Default) { + runCatching { + Nip49().encrypt(privKey, currentPassword, Nip49.DEFAULT_LOG_N, Nip49.EncryptedInfo.CLIENT_DOES_NOT_TRACK) + }.getOrNull() + } + working = false + if (result != null) { + encrypted = result + // The password has done its job: don't leave it in the fields behind the result. + password = "" + repeated = "" + } else { + Toast.makeText(context, loadStringRes(Res.string.failed_to_encrypt_key), Toast.LENGTH_SHORT).show() + } + } + } + } + + Surface( + modifier = Modifier.fillMaxWidth(), + shape = CardShape, + color = MaterialTheme.colorScheme.surfaceContainerHigh, + ) { + Column { + Row( + modifier = + Modifier + .fillMaxWidth() + .clickable { expanded = !expanded } + .padding(start = 16.dp, end = 12.dp, top = 16.dp, bottom = if (expanded) 8.dp else 16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Column(Modifier.weight(1f)) { + CardTitle(MaterialSymbols.Lock, stringRes(Res.string.account_backup_encrypted_title)) + Spacer(Modifier.height(4.dp)) + Text( + text = stringRes(Res.string.account_backup_encrypted_body), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(start = 28.dp), + ) + } + Spacer(Modifier.width(8.dp)) + Icon( + symbol = if (expanded) MaterialSymbols.KeyboardArrowUp else MaterialSymbols.KeyboardArrowDown, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + + AnimatedVisibility(visible = expanded) { + Column(Modifier.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)) { + val encryptedValue = encrypted + if (encryptedValue == null) { + val visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation() + + OutlinedTextField( + modifier = + Modifier + .fillMaxWidth() + .semantics { contentType = ContentType.NewPassword }, + value = password, + onValueChange = { password = it }, + // What gets encrypted is the password at tap time: don't let it change underneath. + enabled = !working, + singleLine = true, + label = { Text(stringRes(Res.string.account_backup_encrypted_password)) }, + supportingText = { + Text( + text = stringRes(Res.string.account_backup_password_min_length, Nip49.MIN_PASSWORD_LENGTH), + color = if (longEnough) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant, + ) + }, + keyboardOptions = + KeyboardOptions( + autoCorrectEnabled = false, + keyboardType = KeyboardType.Password, + imeAction = ImeAction.Next, + ), + trailingIcon = { + IconButton(onClick = { showPassword = !showPassword }) { + Icon( + symbol = if (showPassword) MaterialSymbols.VisibilityOff else MaterialSymbols.Visibility, + contentDescription = stringRes(if (showPassword) Res.string.hide_password else Res.string.show_password), + ) + } + }, + visualTransformation = visualTransformation, + ) + + Spacer(Modifier.height(8.dp)) + + OutlinedTextField( + modifier = + Modifier + .fillMaxWidth() + .semantics { contentType = ContentType.NewPassword }, + value = repeated, + onValueChange = { repeated = it }, + enabled = !working, + singleLine = true, + label = { Text(stringRes(Res.string.account_backup_encrypted_repeat_password)) }, + isError = mismatch, + supportingText = + if (mismatch) { + { Text(stringRes(Res.string.account_backup_encrypted_password_mismatch)) } + } else { + null + }, + trailingIcon = + if (canEncrypt) { + { Icon(MaterialSymbols.Check, contentDescription = null, tint = MaterialTheme.colorScheme.primary) } + } else { + null + }, + keyboardOptions = + KeyboardOptions( + autoCorrectEnabled = false, + keyboardType = KeyboardType.Password, + imeAction = ImeAction.Done, + ), + keyboardActions = + KeyboardActions( + onDone = { + // Close the keyboard so the result and its buttons are visible. Not via + // clearFocus(): that hands focus to the embed tab's RemoteImeView, which + // keeps the keyboard up. + keyboardController?.hide() + encrypt() + }, + ), + visualTransformation = visualTransformation, + ) + + Spacer(Modifier.height(12.dp)) + + FilledTonalButton( + modifier = Modifier.fillMaxWidth(), + enabled = canEncrypt, + onClick = ::encrypt, + ) { + if (working) { + CircularProgressIndicator(modifier = Modifier.size(18.dp), strokeWidth = 2.dp) + Spacer(Modifier.width(8.dp)) + Text(stringRes(Res.string.account_backup_encrypting)) + } else { + ButtonContent(MaterialSymbols.Lock, stringRes(Res.string.account_backup_encrypt)) + } + } + } else { + Text( + text = encryptedValue, + style = MaterialTheme.typography.bodySmall.copy(fontFamily = FontFamily.Monospace), + modifier = + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .background(MaterialTheme.colorScheme.surface) + .padding(12.dp), + ) + + Spacer(Modifier.height(8.dp)) + + Text( + text = stringRes(Res.string.account_backup_encrypted_saved_hint), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + + Spacer(Modifier.height(12.dp)) + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + FilledTonalButton( + modifier = Modifier.weight(1f), + onClick = { + scope.launch { + clipboard.setText(encryptedValue) + Toast.makeText(context, loadStringRes(Res.string.secret_key_copied_to_clipboard), Toast.LENGTH_SHORT).show() + } + }, + ) { + ButtonContent(MaterialSymbols.ContentCopy, stringRes(Res.string.backup_keys_copy)) + } + FilledTonalButton( + modifier = Modifier.weight(1f), + onClick = { showQr = true }, + ) { + ButtonContent(MaterialSymbols.QrCode2, stringRes(Res.string.account_backup_qr_code)) + } + } + + TextButton( + modifier = Modifier.align(Alignment.CenterHorizontally), + onClick = { + encrypted = null + password = "" + repeated = "" + }, + ) { + Text(stringRes(Res.string.account_backup_encrypt_again)) + } + } + } + } + } + } + + encrypted?.let { + if (showQr) { + ShowKeyQRDialog(it, onClose = { showQr = false }) + } + } +} + +@Composable +private fun BackupTips() { + Column( + modifier = Modifier.padding(horizontal = 4.dp, vertical = 4.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + TipRow(MaterialSymbols.EditNote, stringRes(Res.string.account_backup_tip_storage)) + TipRow(MaterialSymbols.Warning, stringRes(Res.string.account_backup_tip_trust)) + TipRow(MaterialSymbols.Shield, stringRes(Res.string.account_backup_tip_developers)) + } +} + +@Composable +private fun CardTitle( + symbol: MaterialSymbol, + title: String, + modifier: Modifier = Modifier, +) { + Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { + Icon(symbol, contentDescription = null, tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(20.dp)) + Spacer(Modifier.width(8.dp)) + Text(title, style = MaterialTheme.typography.titleSmall, fontWeight = FontWeight.SemiBold) + } +} + +@Composable +private fun TipRow( + symbol: MaterialSymbol, + text: String, +) { + Row(verticalAlignment = Alignment.Top) { + Icon(symbol, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.size(20.dp)) + Spacer(Modifier.width(12.dp)) + Text(text, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + } +} + +@Composable +private fun ButtonContent( + symbol: MaterialSymbol, + label: String, +) { + Icon(symbol, contentDescription = null, modifier = Modifier.size(18.dp)) + Spacer(Modifier.width(8.dp)) + Text(label) +} + +/** + * Asks for the device credential (biometric or lock screen) once per visit, before + * the key is first revealed, copied or shown as a QR code. [lock] forgets the approval, + * e.g. when the app goes to the background. + */ +@Stable +private class KeyAccessGate { + var isUnlocked by mutableStateOf(false) + private set + + /** + * The action waiting on the keyguard fallback activity to return. Only a new request or + * that activity's result replaces it: the activity stops this screen (so ON_STOP must not + * clear it), and a wrong fingerprint before the lockout fallback is not a final failure. + */ + var pending: (() -> Unit)? = null + + var prompt: ((onApproved: () -> Unit) -> Unit)? = null + + fun withAccess(action: () -> Unit) { + if (isUnlocked) { + action() + } else { + prompt?.invoke { + isUnlocked = true + action() + } + } + } + + fun lock() { + isUnlocked = false + } +} + +@Composable +private fun rememberKeyAccessGate(accountViewModel: AccountViewModel): KeyAccessGate { val context = LocalContext.current val authLabels = rememberAuthPromptLabels() - val authLabelCopyKey = stringRes(Res.string.copy_my_secret_key) - val scope = rememberCoroutineScope() + val authTitle = stringRes(Res.string.backup_keys) + val gate = remember { KeyAccessGate() } val keyguardLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> + val action = gate.pending + gate.pending = null if (result.resultCode == Activity.RESULT_OK) { - copyNSec(context, scope, accountViewModel.account, clipboardManager) + action?.invoke() } } - Button( - modifier = Modifier.padding(horizontal = 3.dp), - onClick = { + SideEffect { + gate.prompt = { onApproved -> + gate.pending = onApproved authenticate( - title = authLabelCopyKey, + title = authTitle, context = context, labels = authLabels, keyguardLauncher = keyguardLauncher, - onApproved = { copyNSec(context, scope, accountViewModel.account, clipboardManager) }, + onApproved = { + gate.pending = null + onApproved() + }, onError = { title, message -> accountViewModel.toastManager.toast(title, message) }, ) - }, - shape = ButtonBorder, - colors = - ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.primary, - ), - contentPadding = ButtonPadding, - ) { - Icon( - tint = MaterialTheme.colorScheme.onPrimary, - symbol = MaterialSymbols.Key, - contentDescription = - stringRes(Res.string.copies_the_nsec_id_your_password_to_the_clipboard_for_backup), - modifier = Modifier.padding(end = 5.dp), - ) - Text( - stringRes(id = Res.string.copy_my_secret_key), - color = MaterialTheme.colorScheme.onPrimary, - ) - } -} - -@Composable -private fun EncryptNSecCopyButton( - accountViewModel: AccountViewModel, - password: MutableState, -) { - val clipboardManager = LocalClipboard.current - val context = LocalContext.current - val authLabels = rememberAuthPromptLabels() - val authLabelCopyKey = stringRes(Res.string.copy_my_secret_key) - val scope = rememberCoroutineScope() - - val keyguardLauncher = - rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> - if (result.resultCode == Activity.RESULT_OK) { - encryptCopyNSec(password, context, scope, accountViewModel, clipboardManager) - } - } - - Row { - Column { - OutlinedButton( - modifier = Modifier.padding(horizontal = 3.dp), - onClick = { - authenticate( - title = authLabelCopyKey, - context = context, - labels = authLabels, - keyguardLauncher = keyguardLauncher, - onApproved = { encryptCopyNSec(password, context, scope, accountViewModel, clipboardManager) }, - onError = { title, message -> accountViewModel.toastManager.toast(title, message) }, - ) - }, - shape = ButtonBorder, - contentPadding = ButtonPadding, - enabled = password.value.text.isNotBlank(), - ) { - Icon( - symbol = MaterialSymbols.Key, - contentDescription = - stringRes(Res.string.copies_the_nsec_id_your_password_to_the_clipboard_for_backup), - modifier = Modifier.padding(end = 5.dp), - ) - Text( - stringRes(id = Res.string.encrypt_and_copy_my_secret_key), - ) - } - } - - Column { - QrCodeButtonEncrypted(accountViewModel, password) } } + + return gate } fun Context.getFragmentActivity(): FragmentActivity? { @@ -411,156 +768,41 @@ fun Context.getFragmentActivity(): FragmentActivity? { private fun copyNSec( context: Context, scope: CoroutineScope, - account: Account, + nsec: String, clipboardManager: Clipboard, ) { - account.settings.keyPair.privKey?.let { - val nsec = it.toNsec() - scope.launch { - clipboardManager.setText(nsec) - Toast - .makeText( - context, - loadStringRes(Res.string.secret_key_copied_to_clipboard), - Toast.LENGTH_SHORT, - ).show() + // The auto-clear below must outlive this screen, so [scope] is not a composition scope. + scope.launch { + clipboardManager.setClipEntry(ClipEntry(sensitiveClip(nsec))) + Toast + .makeText( + context, + loadStringRes(Res.string.secret_key_copied_to_clipboard), + Toast.LENGTH_SHORT, + ).show() - // Best-effort auto-clear: after a delay, wipe the clipboard only if it - // still holds this exact nsec (don't clobber anything copied since). - // On Android 13+ the OS also shows its own sensitive-content UI. - delay(CLIPBOARD_CLEAR_DELAY_MS) - if (clipboardManager.getText() == nsec) { - clipboardManager.setClipEntry(ClipEntry(ClipData.newPlainText("", ""))) - } + // Best-effort auto-clear: after a delay, wipe the clipboard only if it + // still holds this exact nsec (don't clobber anything copied since). + delay(CLIPBOARD_CLEAR_DELAY_MS) + if (clipboardManager.getText() == nsec) { + clipboardManager.setClipEntry(ClipEntry(ClipData.newPlainText("", ""))) } } } -private fun encryptCopyNSec( - password: MutableState, - context: Context, - scope: CoroutineScope, - accountViewModel: AccountViewModel, - clipboardManager: Clipboard, -) { - if (password.value.text.isBlank()) { - scope.launch { - Toast - .makeText( - context, - loadStringRes(Res.string.password_is_required), - Toast.LENGTH_SHORT, - ).show() - } - } else { - accountViewModel.account.settings.keyPair.privKey?.let { - val key = runCatching { Nip49().encrypt(it.toHexKey(), password.value.text) }.getOrNull() - if (key != null) { - scope.launch { - clipboardManager.setText(key) - Toast - .makeText( - context, - loadStringRes(Res.string.secret_key_copied_to_clipboard), - Toast.LENGTH_SHORT, - ).show() - } - } else { - scope.launch { - Toast - .makeText( - context, - loadStringRes(Res.string.failed_to_encrypt_key), - Toast.LENGTH_SHORT, - ).show() - } - } - } +/** + * Marks the clip as sensitive so Android 13+ hides it in the copy confirmation overlay and + * clipboard previews. That overlay is a system window, outside this screen's FLAG_SECURE. + */ +private fun sensitiveClip(text: String): ClipData = + ClipData.newPlainText("", text).apply { + // ClipDescription.EXTRA_IS_SENSITIVE, spelled out: the constant is API 33, the key works earlier. + description.extras = PersistableBundle().apply { putBoolean("android.content.extra.IS_SENSITIVE", true) } } -} - -@Composable -private fun QrCodeButtonBase( - accountViewModel: AccountViewModel, - isEnabled: Boolean = true, - contentDescription: StringResource, - onDialogShow: () -> String?, -) { - val context = LocalContext.current - val authLabels = rememberAuthPromptLabels() - val authLabelCopyKey = stringRes(Res.string.copy_my_secret_key) - - // store the dialog open or close state - var dialogOpen by remember { mutableStateOf(false) } - - val keyguardLauncher = - rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> - if (result.resultCode == Activity.RESULT_OK) { - dialogOpen = true - } - } - - IconButton( - enabled = isEnabled, - onClick = { - authenticate( - title = authLabelCopyKey, - context = context, - labels = authLabels, - keyguardLauncher = keyguardLauncher, - onApproved = { dialogOpen = true }, - onError = { title, message -> accountViewModel.toastManager.toast(title, message) }, - ) - }, - ) { - Icon( - painter = painterRes(R.drawable.ic_qrcode, 4), - contentDescription = stringRes(id = contentDescription), - modifier = Modifier.size(24.dp), - tint = if (isEnabled) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.grayText, - ) - } - - if (dialogOpen) { - ShowKeyQRDialog( - onDialogShow(), - onClose = { dialogOpen = false }, - ) - } -} - -@Composable -private fun QrCodeButton(accountViewModel: AccountViewModel) { - QrCodeButtonBase( - accountViewModel = accountViewModel, - contentDescription = Res.string.show_private_key_qr_code, - onDialogShow = { - accountViewModel.account.settings.keyPair.privKey - ?.toNsec() - }, - ) -} - -@Composable -private fun QrCodeButtonEncrypted( - accountViewModel: AccountViewModel, - password: MutableState, -) { - QrCodeButtonBase( - accountViewModel = accountViewModel, - isEnabled = password.value.text.isNotBlank(), - contentDescription = Res.string.show_encrypted_private_key_qr_code, - onDialogShow = { - accountViewModel.account.settings.keyPair.privKey - ?.toHexKey() - ?.let { Nip49().encrypt(it, password.value.text) } - }, - ) -} @Composable private fun ShowKeyQRDialog( - qrCode: String?, + qrCode: String, onClose: () -> Unit, ) { Dialog( @@ -574,7 +816,6 @@ private fun ShowKeyQRDialog( .fillMaxSize() .padding(10.dp), ) { - // Back button at the top Row( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, @@ -582,7 +823,6 @@ private fun ShowKeyQRDialog( BackButton(onPress = onClose) } - // QR Code content Column( modifier = Modifier @@ -591,7 +831,7 @@ private fun ShowKeyQRDialog( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { - QrCodeDrawer(qrCode ?: "error") + QrCodeDrawer(qrCode) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/LoginViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/LoginViewModel.kt index b1062bd9c4..fd91a9fdec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/LoginViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/LoginViewModel.kt @@ -39,6 +39,7 @@ import com.vitorpamplona.amethyst.commons.resources.password_is_required import com.vitorpamplona.amethyst.commons.resources.sign_request_rejected_description import com.vitorpamplona.amethyst.commons.tor.TorSettingsFlow import com.vitorpamplona.amethyst.ui.screen.AccountSessionManager +import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription @Stable class LoginViewModel : ViewModel() { @@ -58,7 +59,7 @@ class LoginViewModel : ViewModel() { var password by mutableStateOf(TextFieldValue("")) val needsPassword by derivedStateOf { - key.text.startsWith("ncryptsec1") + Bech32Transcription.normalize(key.text).startsWith("ncryptsec1") } var isFirstLogin by mutableStateOf(false) diff --git a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/KeyCommands.kt b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/KeyCommands.kt index 5385284091..14c76a545d 100644 --- a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/KeyCommands.kt +++ b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/KeyCommands.kt @@ -25,6 +25,7 @@ import com.vitorpamplona.amethyst.cli.Identity import com.vitorpamplona.amethyst.cli.Output import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.core.toHexKey +import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes import com.vitorpamplona.quartz.nip19Bech32.toNpub import com.vitorpamplona.quartz.nip49PrivKeyEnc.Nip49 @@ -121,7 +122,7 @@ object KeyCommands { private fun decrypt(rest: Array): Int { val args = Args(rest) - val ncryptsec = args.positional(0, "ncryptsec").trim() + val ncryptsec = Bech32Transcription.normalize(args.positional(0, "ncryptsec")) if (!ncryptsec.startsWith("ncryptsec")) return Output.error("bad_args", "expected an ncryptsec1… string") // Read both spellings eagerly so passing both doesn't trip rejectUnknown(). val pwAlias = args.flag("pw") diff --git a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/LoginCommand.kt b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/LoginCommand.kt index 3f97d9c8ba..839041a49f 100644 --- a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/LoginCommand.kt +++ b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/LoginCommand.kt @@ -30,6 +30,7 @@ import com.vitorpamplona.quartz.nip05DnsIdentifiers.Nip05Client import com.vitorpamplona.quartz.nip05DnsIdentifiers.OkHttpNip05Fetcher import com.vitorpamplona.quartz.nip05DnsIdentifiers.resolveUserHexOrNull import com.vitorpamplona.quartz.nip06KeyDerivation.Nip06 +import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription import com.vitorpamplona.quartz.nip19Bech32.toNpub import com.vitorpamplona.quartz.nip46RemoteSigner.signer.NostrSignerRemote import com.vitorpamplona.quartz.nip49PrivKeyEnc.Nip49 @@ -90,7 +91,7 @@ object LoginCommand { args.rejectUnknown("password", "pw", "private") val identity = - resolveIdentity(key, args) + resolveIdentity(Bech32Transcription.normalize(key), args) ?: return Output.error( "bad_key", "could not parse '$key' as any supported identifier", diff --git a/commonsUI/src/commonMain/composeResources/values-ar-rSA/strings.xml b/commonsUI/src/commonMain/composeResources/values-ar-rSA/strings.xml index e9970306ff..eb8f051c0d 100644 --- a/commonsUI/src/commonMain/composeResources/values-ar-rSA/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ar-rSA/strings.xml @@ -227,7 +227,6 @@ Relays الموقع Lightning عنوان - نسخ معرف Nsec (كلمة المرور الخاصة بك) إلى الحافظة للنسخ الاحتياطي إرسال رسالة مباشرة القيام بتحرير metadata للمستخدم رفع الحظر @@ -282,9 +281,6 @@ ضع علامة على جميع الرسائل/الاشعارات المعروفة كمقروء تعيين الجديد كمقروء تعيين الكل كمقروء - ## النصائح الرئيسية للنسخ الاحتياطي والسلامة \n\n- يتم تأمين حسابك بمفتاح سري. المفتاح السري هو سلسلة عشوائية طويلة تبدأ بـ **nsec1**. أي شخص لديه مفتاحك السري يمكنه نشر المحتوى باستخدام هويتك. \n\n- لا تقم بوضع مفتاحك السري في أي موقع أو برنامج لا تثق به. \n- مطوري Amethyst لن يطلبوا منك **أبدا** المفتاح السري الخاص بك. \n- حافظ على نسخة احتياطية آمنة لمفتاحك السري لاسترداد الحساب. نوصي باستخدام برنامج لادارة كلمات المرور. - للحصول على أمان إضافي، يمكنك تشفير مفتاحك الخاص بكلمة مرور. يبدأ هذا المفتاح المشفر بـ **ncryptsec1** ولا يمكن استخدامه دون كلمة المرور الخاصة بك. \n\nإذا فقدت كلمة المرور، لن تتمكن من استرداد مفتاحك الخاص. - تشفير و نسخ المفتاح الخاص صورة شارة مكافئة ل %1$s "صورة منح الشارة لقد حصلت على شارة جائزة جديدة @@ -2039,7 +2035,6 @@ تم نسخ نص الملاحظة/المنشور إلى الحافظة تم النسخ إلى الحافظة تم نسخ عنوان @npub المؤلف إلى الحافظة - إنسخ مفتاحي السري نسخ إلى الحافظة تعذّر إنشاء LNUrl من عنوان Lightning "%1$s". تحقق من إعداد المستخدم تعذّر التحقق من الملف المنزّل بعد الرفع: %1$s @@ -2930,10 +2925,8 @@ رفع HLS مشاركة أو حفظ مقاطع قصيرة - إظهار رمز QR المفتاح الخاص المشفر تضمين الرسائل المباشرة والجماعية في تبويب الإشعارات. أوقف التشغيل للاحتفاظ بالرسائل في تبويب الرسائل فقط. إظهار الرسائل - إظهار رمز QR المفتاح الخاص تم رفض طلب التوقيع تأكد من أن تطبيق الموقِّع قد أذن بهذه المعاملة أعاد الموقِّع الخارجي بيانات غير متوقعة للطلب. قد يكون هناك خطأ في Amethyst أو في تطبيق الموقِّع. diff --git a/commonsUI/src/commonMain/composeResources/values-bn-rBD/strings.xml b/commonsUI/src/commonMain/composeResources/values-bn-rBD/strings.xml index b34056a786..a3394863e6 100644 --- a/commonsUI/src/commonMain/composeResources/values-bn-rBD/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-bn-rBD/strings.xml @@ -217,7 +217,6 @@ রিলেগুলি ওয়েবসাইট বিজলি-ঠিকানা - ব্যাকআপের জন্য আপনার Nsec আইডি (তথা পাসওয়ার্ড) ক্লিপবোর্ডে কপি করে একটি সরাসরি-বার্তা পাঠান ব্যবহারকারীর মেটাডেটা সম্পাদনা করে আনব্লক করুন @@ -271,9 +270,6 @@ পরিচিত সবগুলোকে পঠিত হিসেবে চিহ্নিত করুন নতুন সবগুলোকে পঠিত হিসেবে চিহ্নিত করুন সবগুলোকে পঠিত হিসেবে চিহ্নিত করুন - ## মূল ব্যাকআপ এবং নিরাপত্তা টিপস \n\n আপনার অ্যাকাউন্ট একটি গোপন কী দ্বারা সুরক্ষিত। মূলটি হল অক্ষরগুলির একটি দীর্ঘ ক্রম যা শুরু হয় **nsec1**. যে কেউ এই গোপন কী অ্যাক্সেস করতে পারে পোস্ট এবং আপনার পরিচয় পরিবর্তন করতে পারেন. \n\n- আপনি বিশ্বাস করেন না এমন কোনো ওয়েবসাইট বা সফ্টওয়্যারে আপনার গোপন কী **করবেন না**. \n- অ্যামেথিস্ট ডেভেলপাররা **কখনই** আপনার গোপন কী চাইবে না. \n- **করুন** অ্যাকাউন্ট পুনরুদ্ধারের জন্য আপনার গোপন কীটির একটি নিরাপদ ব্যাকআপ রাখুন৷. আমরা একটি পাসওয়ার্ড ম্যানেজার ব্যবহার করার পরামর্শ দিই।. - অতিরিক্ত নিরাপত্তার জন্য, আপনি একটি পাসওয়ার্ড দিয়ে আপনার কী এনক্রিপ্ট করতে পারেন. এই কী দিয়ে শুরু হয় **ncryptsec1** এবং আপনার পাসওয়ার্ড ছাড়া ব্যবহার করা যাবে না।. \n\n আপনি যদি আপনার পাসওয়ার্ড হারিয়ে ফেলেন, আপনি আপনার কী পুনরুদ্ধার করতে পারবেন না।. - এনক্রিপ্ট এবং আমার গোপন কী অনুলিপি %1$s -এর জন্য ব্যাজ পুরষ্কারের ছবি "ব্যাজ পুরস্কার চিত্র আপনি একটি নতুন ব্যাজ পুরষ্কার পেয়েছেন @@ -2005,7 +2001,6 @@ নোটের রচনাটি ক্লিপবোর্ডে কপি করা হয়েছে ক্লিপবোর্ডে কপি হয়েছে রচয়িতার @npub ক্লিপবোর্ডে কপি করুন - আমার ব্যক্তিগত চাবিটি কপি করুন ক্লিপবোর্ডে কপি করুন Lightning Address "%1$s" থেকে LNUrl তৈরি করা যায়নি। ব্যবহারকারীর সেটআপ পরীক্ষা করুন আপলোডের পরে ডাউনলোড করা ফাইল পরীক্ষা করা যায়নি: %1$s @@ -2811,10 +2806,8 @@ HLS আপলোড শেয়ার বা সেভ করুন শর্টস - এনক্রিপ্টেড প্রাইভেট কী QR কোড দেখান বিজ্ঞপ্তি ট্যাবে সরাসরি ও গ্রুপ বার্তা অন্তর্ভুক্ত করুন। বার্তাগুলো শুধুমাত্র বার্তা ট্যাবে রাখতে বন্ধ করুন। বার্তা দেখান - প্রাইভেট কী QR কোড দেখান সাইন অনুরোধ প্রত্যাখ্যাত নিশ্চিত করুন যে সাইনার অ্যাপ্লিকেশনটি এই লেনদেন অনুমোদন করেছে এক্সটার্নাল সাইনার অনুরোধের জন্য একটি অপরিচিত পেলোড ফেরত দিয়েছে। Amethyst বা সাইনারে একটি বাগ থাকতে পারে। diff --git a/commonsUI/src/commonMain/composeResources/values-cs/strings.xml b/commonsUI/src/commonMain/composeResources/values-cs/strings.xml index 06b182ff77..a59a25da1f 100644 --- a/commonsUI/src/commonMain/composeResources/values-cs/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-cs/strings.xml @@ -561,7 +561,6 @@ Přeposílání Webová stránka Lightning adresa - Zkopíruje Nsec ID (vaše heslo) do schránky pro zálohování Poslat přímou zprávu Upravit uživatelova metadata Odblokovat @@ -670,14 +669,11 @@ Označit všechny známé jako přečtené Označit všechny nové jako přečtené Označit všechny jako přečtené - ## Tipy pro zálohování klíčů a bezpečnost \n\nVaše konto je zabezpečeno tajným klíčem. Klíč je dlouhá posloupnost znaků začínající s **nsec1**. Kdo má přístup k tomuto tajnému klíči, může přispívat a měnit vaši identitu. \n\n- **Nedávejte** svůj tajný klíč na žádnou webovou stránku nebo do žádného softwaru, kterému nedůvěřujete. \n- Vývojáři Amethystu nikdy **nebudou** žádat o váš tajný klíč. \n- **Udržujte** bezpečnou zálohu vašeho tajného klíče pro obnovení účtu. Doporučujeme použití správce hesel. - Pro další zabezpečení můžete svůj klíč zašifrovat heslem. Tento klíč začíná s **ncryptsec1** a nelze ho použít bez vašeho hesla. \n\nPokud zapomenete heslo, nebudete moci obnovit svůj klíč. Zálohujte si klíče Váš tajný klíč je jediný způsob, jak se k tomuto účtu dostat. Pokud ho ztratíte, nelze ho už nikdy obnovit. Uložte si ho někam do bezpečí. Zálohovat nyní Uložil jsem si je Zavřít - Zašifrovat a zkopírovat můj tajný klíč Obrázek ocenění od %1$s Obrázek ocenění Obdrželi jste nové ocenění @@ -3653,7 +3649,6 @@ Text poznámky zkopírován do schránky Zkopírováno do schránky Uživatelovo ID (@npub) zkopírováno do schránky - Zkopírovat můj tajný klíč Kopírovat do schránky Nepodařilo se sestavit LNUrl z Lightning adresy "%1$s". Zkontrolujte nastavení uživatele Nelze zkontrolovat stažený soubor po nahrání: %1$s @@ -5256,10 +5251,8 @@ HLS nahrávání Sdílet nebo Uložit Krátká videa - Zobrazit šifrovaný QR kód soukromého klíče Zahrnout přímé a skupinové zprávy na kartě Oznámení. Vypněte, aby zprávy zůstaly pouze na kartě Zprávy. Zobrazit zprávy - Zobrazit QR kód privátního klíče Požadavek na podpis byl zamítnut Ujistěte se, že podepisující aplikace autorizovala tuto transakci Externí podepisovatel vrátil data, která jsou pro daný požadavek neobvyklá. Může se jednat o chybu v Amethystu nebo v podepisovateli. diff --git a/commonsUI/src/commonMain/composeResources/values-de-rDE/strings.xml b/commonsUI/src/commonMain/composeResources/values-de-rDE/strings.xml index 0d938c442c..df7de8f834 100644 --- a/commonsUI/src/commonMain/composeResources/values-de-rDE/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-de-rDE/strings.xml @@ -545,7 +545,6 @@ Relays Website Lightning-Adresse - Kopiert die Nsec-ID (Ihr Passwort) zur Sicherung in die Zwischenablage Sende eine Direktnachricht Bearbeitet die Benutzermetadaten Entsperren @@ -654,14 +653,11 @@ Alle Kontakte als gelesen markieren Alle Unbekannten als gelesen markieren Alle als gelesen markieren - ## Tipps zur Schlüsselsicherheit \n\nDein Konto ist durch einen privaten Schlüssel gesichert. Der Schlüssel ist eine lange Zeichenfolge, die mit **nsec1** beginnt. Jeder, der Zugriff auf diesen privaten Schlüssel hat, kann in deinem Namen posten und dein Profil ändern. \n\n- Lege deinen privaten Schlüssel **nicht** auf einer Website oder in einer Software ab, der du nicht vertraust. \n- Die Entwickler von Amethyst werden dich **niemals** nach deinem privaten Schlüssel fragen. \n- **Bewahre** eine sichere Kopie deines privaten Schlüssels zur Kontowiederherstellung auf. Wir empfehlen die Verwendung eines Passwort-Managers. - Für zusätzliche Sicherheit kannst du deinen Schlüssel mit einem Passwort verschlüsseln. Dieser Schlüssel beginnt mit **ncryptsec1** und kann ohne dein Passwort nicht verwendet werden. \n\nWenn du dein Passwort verlierst, kannst du deinen Schlüssel nicht wiederherstellen. Sichere deine Schlüssel Dein geheimer Schlüssel ist der einzige Weg zu diesem Konto. Wenn du ihn verlierst, kann er nie wiederhergestellt werden. Speichere ihn jetzt an einem sicheren Ort. Jetzt sichern Habe ich gespeichert Schließen - Meinen privaten Schlüssel verschlüsseln und kopieren Auszeichnungsbild für %1$s Auszeichnungsbild Du hast eine neue Auszeichnung erhalten @@ -3577,7 +3573,6 @@ Notiztext in die Zwischenablage kopiert In die Zwischenablage kopiert Autor-ID in die Zwischenablage kopiert - Meinen geheimen Schlüssel kopieren In Zwischenablage kopieren Konnte keine LNUrl aus der Lightning-Adresse "%1$s" zusammenstellen. Überprüfe die Konfiguration des Benutzers Die heruntergeladene Datei konnte nach dem Hochladen nicht überprüft werden: %1$s @@ -5042,10 +5037,8 @@ HLS-Upload Teilen oder Speichern Kurzvideos - QR-Code für verschlüsselten privaten Schlüssel anzeigen Direkt- und Gruppennachrichten im Benachrichtigungs-Tab anzeigen. Deaktivieren, um Nachrichten nur im Nachrichten-Tab zu behalten. Nachrichten anzeigen - Privaten QR-Code anzeigen Signaturanfrage abgelehnt Stell sicher, dass die Signer-App diese Transaktion autorisiert hat Externer Signer hat Daten zurückgegeben, die für die Anfrage ungewöhnlich sind. Es könnte ein Fehler in Amethyst oder im Signer vorliegen. diff --git a/commonsUI/src/commonMain/composeResources/values-de/strings.xml b/commonsUI/src/commonMain/composeResources/values-de/strings.xml index a1bc04624c..a062bd2b0d 100644 --- a/commonsUI/src/commonMain/composeResources/values-de/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-de/strings.xml @@ -204,7 +204,6 @@ Relais Webseite Lightning-Adresse - Kopiert die Nsec-ID (Ihr Passwort) zur Sicherung in die Zwischenablage Sende eine Direktnachricht Bearbeitet die Benutzermetadaten Entsperren @@ -259,9 +258,6 @@ Alle als bekannt markieren Alle als neu markieren Alle als gelesen markieren - ## Schlüsselsicherheits-Tipps \n\nIhr Konto ist durch einen geheimen Schlüssel gesichert. Der Schlüssel ist eine lange Zeichenfolge, die mit **nsec1** beginnt. Jeder, der Zugriff auf diesen geheimen Schlüssel hat, kann Ihre Identität posten und ändern. \n\n- Legen Sie Ihren geheimen Schlüssel **nicht** auf eine Website oder in eine Software, der Sie nicht vertrauen. \n- Die Entwickler von Amethyst werden Sie **niemals** nach Ihrem geheimen Schlüssel fragen. \n- **Bewahren Sie** eine sichere Sicherung Ihres geheimen Schlüssels zur Kontowiederherstellung auf. Wir empfehlen die Verwendung eines Passwort-Managers. - Für zusätzliche Sicherheit können Sie Ihren Schlüssel mit einem Passwort verschlüsseln. Dieser Schlüssel beginnt mit **ncryptsec1** und kann ohne Ihr Passwort nicht verwendet werden. \n\nWenn Sie Ihr Passwort verlieren, können Sie Ihren Schlüssel nicht wiederherstellen. - Verschlüsseln und kopieren Sie meinen geheimen Schlüssel Auszeichnungsbild für %1$s Auszeichnungsbild Sie haben eine neue Auszeichnung erhalten @@ -2047,7 +2043,6 @@ Notiztext in die Zwischenablage kopiert In die Zwischenablage kopiert Autor-ID in die Zwischenablage kopiert - Meinen geheimen Schlüssel kopieren In Zwischenablage kopieren Konnte keine LNUrl aus der Lightning-Adresse "%1$s" zusammenstellen. Überprüfen Sie die Konfiguration des Benutzers Die heruntergeladene Datei konnte nach dem Hochladen nicht überprüft werden: %1$s @@ -2896,10 +2891,8 @@ HLS-Upload Teilen oder Speichern Kurzvideos - QR-Code für verschlüsselten privaten Schlüssel anzeigen Direkt- und Gruppennachrichten im Benachrichtigungs-Tab anzeigen. Deaktivieren, um Nachrichten nur im Nachrichten-Tab zu behalten. Nachrichten anzeigen - Privaten QR-Code anzeigen Signaturanfrage abgelehnt Stellen Sie sicher, dass die Unterzeichner-Anwendung diese Transaktion autorisiert hat Externer Signierer hat Daten zurückgegeben, die für die Anfrage ungewöhnlich sind. Es könnte ein Fehler in Amethyst oder im Signierer vorliegen. diff --git a/commonsUI/src/commonMain/composeResources/values-el-rGR/strings.xml b/commonsUI/src/commonMain/composeResources/values-el-rGR/strings.xml index 2fe2f7373b..16c37e259b 100644 --- a/commonsUI/src/commonMain/composeResources/values-el-rGR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-el-rGR/strings.xml @@ -216,7 +216,6 @@ Διαμοιραστές Ιστοσελίδα Διεύθυνση Lightning - Αντιγράφει το "Μυστικό Κλειδί" σας (Nsec ID ή αλλιώς ο μυστικός κωδικός πρόσβασής σας) στο πρόχειρο για δημιουργία αντιγράφου ασφαλείας Αποστολή Άμεσου Μηνύματος Επεξεργασία των Μεταδεδομένων του Χρήστη Άρση Αποκλεισμού @@ -271,9 +270,6 @@ Σήμανση όλων των γνωστοποιήσεων ως αναγνωσμένων Σήμανση όλων ως αναγνωσμένων Σήμανση όλων ως αναγνωσμένα - ## Συμβουλές ασφαλείας και δημιουργίας αντιγράφων ασφαλείας κλειδιού \n\nΟ λογαριασμός σου ασφαλίζεται με ένα μυστικό κλειδί. Το κλειδί είναι μια μακρά ακολουθία χαρακτήρων που ξεκινά με **nsec1**. Όποιος έχει πρόσβαση σε αυτό το μυστικό κλειδί μπορεί να δημοσιεύει και να αλλάζει την ταυτότητά σου. \n\n- **Μην** βάζεις το μυστικό σου κλειδί σε κανέναν ιστότοπο ή λογισμικό που δεν εμπιστεύεσαι. \n- Οι προγραμματιστές του Amethyst **δεν** θα ζητήσουν ποτέ το μυστικό σου κλειδί. \n- **Διατήρησε** ένα ασφαλές αντίγραφο ασφαλείας του μυστικού σου κλειδιού για ανάκτηση λογαριασμού. Συνιστούμε τη χρήση διαχειριστή κωδικών πρόσβασης. - Για πρόσθετη ασφάλεια, μπορείς να κρυπτογραφήσεις το κλειδί σου με κωδικό πρόσβασης. Αυτό το κλειδί ξεκινά με **ncryptsec1** και δεν μπορεί να χρησιμοποιηθεί χωρίς τον κωδικό σου. \n\nΑν χάσεις τον κωδικό σου, δεν θα μπορείς να ανακτήσεις το κλειδί σου. - Κρυπτογράφηση και αντιγραφή του μυστικού μου κλειδιού Σήμα βράβευσης για %1$s "Εικόνα βραβείου παρασήμου Λάβατε ένα νέο Σήμα Βράβευσης @@ -1990,7 +1986,6 @@ Το κείμενο της δημοσίευσης αποθηκεύτηκε στο πρόχειρο Αντιγράφηκε στο πρόχειρο Το "Δημόσιο Κλειδί" του συντάκτη της δημοσίευσης αποθηκεύτηκε στο πρόχειρο - Αντιγραφή του "Μυστικού Κλειδιού" μου Αντιγραφή στο πρόχειρο Δεν ήταν δυνατή η δημιουργία του LNUrl από τη διεύθυνση Lightning "%1$s". Ελέγξτε ρυθμίσεις χρήστη Δεν ήταν δυνατός ο έλεγχος του ληφθέντος αρχείου μετά το ανέβασμα: %1$s @@ -2759,10 +2754,8 @@ Κοινοποίηση ως URL εικόνας Μεταφόρτωση HLS Κοινοποίηση ή αποθήκευση - Εμφάνιση QR code κρυπτογραφημένου ιδιωτικού κλειδιού Συμπερίληψη άμεσων και ομαδικών μηνυμάτων στην καρτέλα ειδοποιήσεων. Απενεργοποιήστε για να διατηρείτε τα μηνύματα μόνο στην καρτέλα μηνυμάτων. Εμφάνιση μηνυμάτων - Εμφάνιση QR code ιδιωτικού κλειδιού Αίτημα υπογραφής απορρίφθηκε Βεβαιωθείτε ότι η εφαρμογή υπογραφής έχει εξουσιοδοτήσει αυτή τη συναλλαγή Ο εξωτερικός signer επέστρεψε ένα payload που είναι ασυνήθιστο για το αίτημα. Ενδέχεται να υπάρχει σφάλμα στο Amethyst ή στον signer. diff --git a/commonsUI/src/commonMain/composeResources/values-eo-rUY/strings.xml b/commonsUI/src/commonMain/composeResources/values-eo-rUY/strings.xml index ce975e7024..41f7ad82ec 100644 --- a/commonsUI/src/commonMain/composeResources/values-eo-rUY/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-eo-rUY/strings.xml @@ -218,7 +218,6 @@ Plusendiloj Retejo Lightning-Adreso - Kopii la Nsec ID (vian pasvorton) al la tondujo por sekurkopio Sendi rektan mesaĝon Redakti metadatumojn de uzanto Malbloki @@ -273,9 +272,6 @@ Marki ĉiujn Konatajn legitaj Marki ĉiujn Novajn legitaj Marki ĉiujn legitajn - ## Konsiletoj pri Ŝlosila Sekurkopiao kaj Sekureco \n\nVia konto estas sekurigita per sekreta ŝlosilo. La ŝlosilo estas longa sinsekvo de signoj komencanta per **nsec1**. Ĉiu kiu havas aliron al ĉi tiu sekreta ŝlosilo povas afiŝi kaj ŝanĝi vian identecon. \n\n- **Ne** metu vian sekretan ŝlosilon en ajnan retejon aŭ programaron, kiun vi ne fidas. \n- Amethyst-programistoj **neniam** petos vian sekretan ŝlosilon. \n- **Faru** sekuran sekurkopion de via sekreta ŝlosilo por reakiro de konto. Ni rekomendas uzi pasvortan administrilon. - Por plia sekureco, vi povas ĉifri vian ŝlosilon per pasvorto. Ĉi tiu ŝlosilo komenciĝas per **ncryptsec1** kaj ne povas esti uzata sen via pasvorto. \n\nSe vi perdas vian pasvorton, vi ne povos reakiri vian ŝlosilon. - Ĉifri kaj kopii mian seketan ŝlosilon Ŝildeto-premia bildo por %1$s "Insigna premibildeto Vi ricevis novan ŝildeto-premion @@ -2014,7 +2010,6 @@ Kopiita tekston de noto al tondujo Kopiita al poŝujo Kopiita @npub de aŭtoro al tondujo - Kopii mian sekretan ŝlosilon Kopii al poŝujo Ne eblis kunmeti LNUrl el Lightning-Adreso "%1$s". Kontrolu la agordon de la uzanto Ne eblis kontroli la elŝutitan dosieron post alŝuto: %1$s @@ -2813,10 +2808,8 @@ HLS Alŝuto Kunhavigi aŭ Konservi Mallongaj videoj - Montri ĉifritan privatan ŝlosilon QR-kode Inkluzivi rektajn kaj grupajn mesaĝojn en la Sciiga langeto. Malŝaltu por konservi mesaĝojn nur en la Mesaĝa langeto. Montri Mesaĝojn - Montri privatan ŝlosilon QR-kode Subskrib-peto rifuzita Certigu ke la subskribista aplikaĵo aŭtoris ĉi tiun transakcion La ekstera subskribanto resendis utilan ŝarĝon kiu estas stranga por la peto. Povas ekzisti eraro en Amethyst aŭ en la Subskribanto. diff --git a/commonsUI/src/commonMain/composeResources/values-eo/strings.xml b/commonsUI/src/commonMain/composeResources/values-eo/strings.xml index ef18a4b455..3274fa4e7d 100644 --- a/commonsUI/src/commonMain/composeResources/values-eo/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-eo/strings.xml @@ -204,7 +204,6 @@ Plusendiloj Retejo Lightning-Adreso - Kopii la Nsec ID (vian pasvorton) al la tondujo por sekurkopio Sendi rektan mesaĝon Redakti metadatumojn de uzanto Malbloki @@ -259,9 +258,6 @@ Marki ĉiujn Konatajn legitaj Marki ĉiujn Novajn legitaj Marki ĉiujn legitajn - ## Konsiletoj pri Ŝlosila Sekurkopiao kaj Sekureco \n\nVia konto estas sekurigita per sekreta ŝlosilo. La ŝlosilo estas longa sinsekvo de signoj komencanta per **nsec1**. Ĉiu kiu havas aliron al ĉi tiu sekreta ŝlosilo povas afiŝi kaj ŝanĝi vian identecon. \n\n- **Ne** metu vian sekretan ŝlosilon en ajnan retejon aŭ programaron, kiun vi ne fidas. \n- Amethyst-programistoj **neniam** petos vian sekretan ŝlosilon. \n- **Faru** sekuran sekurkopion de via sekreta ŝlosilo por reakiro de konto. Ni rekomendas uzi pasvortan administrilon. - Por plia sekureco, vi povas ĉifri vian ŝlosilon per pasvorto. Ĉi tiu ŝlosilo komenciĝas per **ncryptsec1** kaj ne povas esti uzata sen via pasvorto. \n\nSe vi perdas vian pasvorton, vi ne povos reakiri vian ŝlosilon. - Ĉifri kaj kopii mian seketan ŝlosilon Ŝildeto-premia bildo por %1$s "Insigna premibildeto Vi ricevis novan ŝildeto-premion @@ -2038,7 +2034,6 @@ Kopiita tekston de noto al tondujo Kopiita al poŝujo Kopiita @npub de aŭtoro al tondujo - Kopii mian sekretan ŝlosilon Kopii al poŝujo Ne eblis kunmeti LNUrl el Lightning-Adreso "%1$s". Kontrolu la agordon de la uzanto Ne eblis kontroli la elŝutitan dosieron post alŝuto: %1$s @@ -2863,10 +2858,8 @@ HLS Alŝuto Kunhavigi aŭ Konservi Mallongaj videoj - Montri ĉifritan privatan ŝlosilon QR-kode Inkluzivi rektajn kaj grupajn mesaĝojn en la Sciiga langeto. Malŝaltu por konservi mesaĝojn nur en la Mesaĝa langeto. Montri Mesaĝojn - Montri privatan ŝlosilon QR-kode Subskrib-peto rifuzita Certigu ke la subskribista aplikaĵo aŭtoris ĉi tiun transakcion La ekstera subskribanto resendis utilan ŝarĝon kiu estas stranga por la peto. Povas ekzisti eraro en Amethyst aŭ en la Subskribanto. diff --git a/commonsUI/src/commonMain/composeResources/values-es-rES/strings.xml b/commonsUI/src/commonMain/composeResources/values-es-rES/strings.xml index 3035a49c08..22de7cb7f9 100644 --- a/commonsUI/src/commonMain/composeResources/values-es-rES/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-es-rES/strings.xml @@ -217,7 +217,6 @@ Retransmisores Sitio web Dirección Lightning - Copia el ID Nsec (tu contraseña) en el portapapeles para hacer una copia de seguridad Enviar un mensaje directo Edita los metadatos del usuario Desbloquear @@ -272,9 +271,6 @@ Marcar los conocidos como leídos Marcar los nuevos como leídos Marcar todos como leídos - ## Consejos sobre la protección y la copia de seguridad de las claves \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. - Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. \n\nSi pierdes la contraseña, no podrás recuperar tu clave. - Cifrar y copiar mi clave secreta Imagen del Badge para %1$s "Imagen de premio de insignia Has recibido un nuevo Badge @@ -2011,7 +2007,6 @@ Texto de nota copiado al portapapeles Copiado al portapapeles @npub del autor copiado al portapapeles - Copiar mi clave secreta Copiar al portapapeles No se pudo ensamblar la LNUrl desde la dirección de Lightning "%1$s". Comprueba la configuración del usuario. No se pudo comprobar el archivo descargado después de cargar: %1$s @@ -2826,10 +2821,8 @@ Subida HLS Compartir o guardar Cortos - Mostrar código QR de clave privada cifrada Incluye mensajes directos y de grupo en la pestaña de Notificaciones. Desactívalo para mantener los mensajes solo en la pestaña de Mensajes. Mostrar mensajes - Mostrar código QR de clave privada Solicitud de firma rechazada Asegúrate de que la aplicación firmante haya autorizado esta transacción. El firmante externo devolvió una carga útil que no concuerda con la solicitud. Es posible que haya un error, ya sea en Amethyst o en el firmante. diff --git a/commonsUI/src/commonMain/composeResources/values-es-rMX/strings.xml b/commonsUI/src/commonMain/composeResources/values-es-rMX/strings.xml index 791a4dc908..72e983759b 100644 --- a/commonsUI/src/commonMain/composeResources/values-es-rMX/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-es-rMX/strings.xml @@ -217,7 +217,6 @@ Relés Sitio web Dirección de Lightning - Copia el ID Nsec (tu contraseña) en el portapapeles para hacer una copia de seguridad Enviar un mensaje directo Edita los metadatos del usuario Desbloquear @@ -272,9 +271,6 @@ Marcar todos los conocidos como leídos Marcar todos los nuevos como leídos Marcar todos como leídos - ## Consejos sobre la protección y la copia de seguridad de las claves \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. - Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. \n\nSi pierdes la contraseña, no podrás recuperar tu clave. - Cifrar y copiar mi clave secreta Imagen de premio de insignia por %1$s "Imagen de premio de insignia Recibiste un nuevo premio de insignia @@ -2010,7 +2006,6 @@ Texto de la nota copiado al portapapeles Copiado al portapapeles @npub del autor copiado al portapapeles - Copiar mi clave secreta Copiar al portapapeles No se pudo ensamblar la LNUrl desde la dirección de Lightning "%1$s". Comprueba la configuración del usuario. No se pudo comprobar el archivo descargado después de subir: %1$s @@ -2819,10 +2814,8 @@ Subida HLS Compartir o guardar Cortos - Mostrar código QR de clave privada cifrada Incluye mensajes directos y de grupo en la pestaña de Notificaciones. Desactívalo para mantener los mensajes solo en la pestaña de Mensajes. Mostrar mensajes - Mostrar código QR de clave privada Solicitud de firma rechazada Asegúrate de que la aplicación firmante haya autorizado esta transacción. El firmante externo devolvió una carga útil que no concuerda con la solicitud. Es posible que haya un error, ya sea en Amethyst o en el firmante. diff --git a/commonsUI/src/commonMain/composeResources/values-es-rUS/strings.xml b/commonsUI/src/commonMain/composeResources/values-es-rUS/strings.xml index 23d497b889..324e61dcb2 100644 --- a/commonsUI/src/commonMain/composeResources/values-es-rUS/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-es-rUS/strings.xml @@ -217,7 +217,6 @@ Relés Sitio web Dirección de Lightning - Copia el ID Nsec (tu contraseña) en el portapapeles para hacer una copia de seguridad Enviar un mensaje directo Edita los metadatos del usuario Desbloquear @@ -272,9 +271,6 @@ Marcar todos los conocidos como leídos Marcar todos los nuevos como leídos Marcar todos como leídos - ## Consejos sobre la protección y la copia de seguridad de las claves \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. - Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. \n\nSi pierdes la contraseña, no podrás recuperar tu clave. - Cifrar y copiar mi clave secreta Imagen de premio de insignia por %1$s "Imagen de premio de insignia Recibiste un nuevo premio de insignia @@ -2010,7 +2006,6 @@ Texto de la nota copiado al portapapeles Copiado al portapapeles @npub del autor copiado al portapapeles - Copiar mi clave secreta Copiar al portapapeles No se pudo ensamblar la LNUrl desde la dirección de Lightning "%1$s". Comprueba la configuración del usuario. No se pudo comprobar el archivo descargado después de subir: %1$s @@ -2819,10 +2814,8 @@ Subida HLS Compartir o guardar Cortos - Mostrar código QR de clave privada cifrada Incluye mensajes directos y de grupo en la pestaña de Notificaciones. Desactívalo para mantener los mensajes solo en la pestaña de Mensajes. Mostrar mensajes - Mostrar código QR de clave privada Solicitud de firma rechazada Asegúrate de que la aplicación firmante haya autorizado esta transacción. El firmante externo devolvió una carga útil que no concuerda con la solicitud. Es posible que haya un error, ya sea en Amethyst o en el firmante. diff --git a/commonsUI/src/commonMain/composeResources/values-es/strings.xml b/commonsUI/src/commonMain/composeResources/values-es/strings.xml index 0f52873364..b50a02847d 100644 --- a/commonsUI/src/commonMain/composeResources/values-es/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-es/strings.xml @@ -204,7 +204,6 @@ Retransmisores Sitio web Dirección Lightning - Copia la ID de Nsec (su contraseña) en el portapapeles para hacer una copia de seguridad Enviar un mensaje directo Edita los metadatos del usuario Desbloquear @@ -259,7 +258,6 @@ Marcar los conocidos como leídos Marcar los nuevos como leídos Marcar todos como leídos - Cifrar y copiar mi clave secreta Imagen del Badge para %1$s "Imagen de premio de insignia Has recibido un nuevo Badge @@ -1800,8 +1798,6 @@ URL base de la API del explorador Pagar factura del DVM Pagar %1$s sats al DVM - ## Consejos sobre la protección y la copia de seguridad de las claves \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. - Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. \n\nSi pierdes la contraseña, no podrás recuperar tu clave. Usar URL directa nSite: %1$s nApplet: %1$s @@ -2038,7 +2034,6 @@ Texto de nota copiado al portapapeles Copiado al portapapeles @npub del autor copiado al portapapeles - Copiar mi clave secreta Copiar al portapapeles No se pudo ensamblar la LNUrl desde la dirección de Lightning "%1$s". Comprueba la configuración del usuario. No se pudo comprobar el archivo descargado después de cargar: %1$s @@ -2863,10 +2858,8 @@ Subida HLS Compartir o guardar Cortos - Mostrar código QR de clave privada cifrada Incluye mensajes directos y de grupo en la pestaña de Notificaciones. Desactívalo para mantener los mensajes solo en la pestaña de Mensajes. Mostrar mensajes - Mostrar código QR de clave privada Solicitud de firma rechazada Asegúrate de que la aplicación firmante haya autorizado esta transacción. El firmante externo devolvió una carga útil que no concuerda con la solicitud. Es posible que haya un error, ya sea en Amethyst o en el firmante. diff --git a/commonsUI/src/commonMain/composeResources/values-fa-rIR/strings.xml b/commonsUI/src/commonMain/composeResources/values-fa-rIR/strings.xml index 3ecb2f982d..3077ca6903 100644 --- a/commonsUI/src/commonMain/composeResources/values-fa-rIR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fa-rIR/strings.xml @@ -219,7 +219,6 @@ رله ها وبسایت آدرس لایتنینگ - شناسه کلید خصوصی (پسوردتان) را در کلیپبورد کپی می کند( ارسال پیام مستقیم متادیتای کاربر را ویرایش می کند از بلاک درآوردن @@ -274,9 +273,6 @@ همه شناس ها خوانده شده کن همه جدیدها را خوانده شده کن همه را خوانده شده کن - نکات ایمنی و ذخیره کلید حساب کاربری شما با یک کلید خصوصی محافظت می شود. این کلید دنباله ای بلند از کاراکترها است که با **nsec1** آغاز می گردد. هر کس به این کلید خصوصی دسترسی داشته باشد می تواند بجای شما یادداشت پست کرده یا هویت شما را تغییر دهد. هرگز کلید خصوصی خود را در هیچ وبسایت با نرم افزاری که به آن اطمینان ندارید **وارد نکنید**. سازندگان امتیست **هرگز** کلیدتان را از شما نمی خواهند. یک پشتیبان یدکی مخفی از کلید خود به منظور بازیابی **نگه دارید**. ما استفاده از نرم افزار مدیریت پسورد را توصیه می کنیم. - برای ایمنی بیشتر، می توانید کلید خود را با یک رمزعبور رمزنگاری کنید. این نوع کلید با **ncryptsec1** آغاز می شود و نمی تواند بدون رمز عبور شما استفاده شود. اگر پسوردتان را گم کنید، نخواهید توانست کلیدتان را بازیابی کنید. - رمزنگاری و کپی کلید من تصویر مدال پاداش برای %1$s تصویر جایزه نشان یک مدال پاداش دریافت کردید @@ -2015,7 +2011,6 @@ یادداشت در کلیپبورد کپی شد در کلیپ‌بورد کپی شد @npubنویسنده در کلیپبورد کپی شد - کلید خصوصیم را کپی کن کپی به کلیپ‌بورد LNUrl از آدرس لایتنینگ "%1$s" بدست نیامد. تنظیمات کاربر را بررسی کنید. فایل بارگیری شده پس از بارگذاری بررسی نشد: %1$s @@ -2820,10 +2815,8 @@ آپلود HLS اشتراک گذاری یا ذخیره‌سازی ویدیوهای کوتاه - نمایش کد QR کلید خصوصی رمزنگاری شده پیام‌های مستقیم و گروهی را در تب اعلان‌ها نمایش دهید. غیرفعال کنید تا پیام‌ها فقط در تب پیام‌ها باشند. نمایش پیام‌ها - نمایش کد QR کلید خصوصی درخواست امضا رد شد مطمئن شوید که اپ امضا کننده این تراکنش را تایید کرده است signer خارجی یک پاسخ عجیب برای درخواست بازگرداند. ممکن است باگی در Amethyst یا در signer وجود داشته باشد. diff --git a/commonsUI/src/commonMain/composeResources/values-fa/strings.xml b/commonsUI/src/commonMain/composeResources/values-fa/strings.xml index cf8347e236..d45ac6d794 100644 --- a/commonsUI/src/commonMain/composeResources/values-fa/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fa/strings.xml @@ -204,7 +204,6 @@ رله ها وبسایت آدرس لایتنینگ - شناسه کلید خصوصی (پسوردتان) را در کلیپبورد کپی می کند( ارسال پیام مستقیم متادیتای کاربر را ویرایش می کند از بلاک درآوردن @@ -259,9 +258,6 @@ همه شناس ها خوانده شده کن همه جدیدها را خوانده شده کن همه را خوانده شده کن - نکات ایمنی و ذخیره کلید حساب کاربری شما با یک کلید خصوصی محافظت می شود. این کلید دنباله ای بلند از کاراکترها است که با **nsec1** آغاز می گردد. هر کس به این کلید خصوصی دسترسی داشته باشد می تواند بجای شما یادداشت پست کرده یا هویت شما را تغییر دهد. هرگز کلید خصوصی خود را در هیچ وبسایت با نرم افزاری که به آن اطمینان ندارید **وارد نکنید**. سازندگان امتیست **هرگز** کلیدتان را از شما نمی خواهند. یک پشتیبان یدکی مخفی از کلید خود به منظور بازیابی **نگه دارید**. ما استفاده از نرم افزار مدیریت پسورد را توصیه می کنیم. - برای ایمنی بیشتر، می توانید کلید خود را با یک رمزعبور رمزنگاری کنید. این نوع کلید با **ncryptsec1** آغاز می شود و نمی تواند بدون رمز عبور شما استفاده شود. اگر پسوردتان را گم کنید، نخواهید توانست کلیدتان را بازیابی کنید. - رمزنگاری و کپی کلید من تصویر مدال پاداش برای %1$s تصویر جایزه نشان یک مدال پاداش دریافت کردید @@ -2038,7 +2034,6 @@ یادداشت در کلیپبورد کپی شد در کلیپ‌بورد کپی شد @npubنویسنده در کلیپبورد کپی شد - کلید خصوصیم را کپی کن کپی به کلیپ‌بورد LNUrl از آدرس لایتنینگ "%1$s" بدست نیامد. تنظیمات کاربر را بررسی کنید. فایل بارگیری شده پس از بارگذاری بررسی نشد: %1$s @@ -2863,10 +2858,8 @@ آپلود HLS اشتراک گذاری یا ذخیره‌سازی ویدیوهای کوتاه - نمایش کد QR کلید خصوصی رمزنگاری شده پیام‌های مستقیم و گروهی را در تب اعلان‌ها نمایش دهید. غیرفعال کنید تا پیام‌ها فقط در تب پیام‌ها باشند. نمایش پیام‌ها - نمایش کد QR کلید خصوصی درخواست امضا رد شد مطمئن شوید که اپ امضا کننده این تراکنش را تایید کرده است signer خارجی یک پاسخ عجیب برای درخواست بازگرداند. ممکن است باگی در Amethyst یا در signer وجود داشته باشد. diff --git a/commonsUI/src/commonMain/composeResources/values-fi-rFI/strings.xml b/commonsUI/src/commonMain/composeResources/values-fi-rFI/strings.xml index b9116115b5..f7927b5a97 100644 --- a/commonsUI/src/commonMain/composeResources/values-fi-rFI/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fi-rFI/strings.xml @@ -213,7 +213,6 @@ Releet Verkkosivusto Lightning-osoite - Kopioi Nsec-tunniste (salasanasi) leikepöydälle varmuuskopiointia varten Lähetä suora viesti Muokkaa käyttäjän metatietoja Poista esto @@ -268,9 +267,6 @@ Merkitse kaikki Tunnetut luetuiksi Merkitse kaikki Uudet luetuiksi Merkitse kaikki luetuiksi - ## Avainten varmuuskopiointi ja turvallisuusvinkit \n\nTilisi on suojattu salaisella avaimella. Avain on pitkä merkkijono, joka alkaa **nsec1**:llä. Kuka tahansa, jolla on pääsy tähän salaiseen avaimeen, voi julkaista ja muuttaa henkilöllisyyttäsi. \n\n- **Älä** anna salaista avaintasi mihinkään verkkosivustoon tai ohjelmistoon, johon et luota. \n- Amethystin kehittäjät eivät **koskaan** pyydä salaista avaintasi. \n- **Tee** turvallinen varmuuskopio salaisesta avaimestasi tilin palauttamista varten. Suosittelemme salasananhallintaohjelman käyttöä. - Lisäturvallisuuden vuoksi voit salata avaimesi salasanalla. Tämä avain alkaa **ncryptsec1**:llä eikä sitä voi käyttää ilman salasanaasi. \n\nJos kadotat salasanasi, et pysty palauttamaan avaintasi. - Salaa ja kopioi salainen avaimeni Merkki kohteelle %1$s "Merkkipalkinnon kuva Olet saanut uuden merkin @@ -1995,7 +1991,6 @@ Viestin teksti kopioitu leikepöydälle Kopioitu leikepöydälle Käyttäjän @npub kopioitu leikepöydälle - Kopioi salainen avain Kopioi leikepöydälle Ei voitu koota LNUrlia Lightning-osoitteesta "%1$s". Tarkista käyttäjän asetukset Ladatun tiedoston tarkistus epäonnistui latauksen jälkeen: %1$s @@ -2790,10 +2785,8 @@ HLS-lataus Jaa tai tallenna Lyhytvideot - Näytä salatun yksityisen avaimen QR-koodi Sisällytä suorat viestit ja ryhmäviestit Ilmoitukset-välilehdelle. Poista käytöstä, jos haluat pitää viestit vain Viestit-välilehdellä. Näytä viestit - Näytä yksityisen avaimen QR-koodi Allekirjoituspyyntö hylätty Varmista, että allekirjoittajasovellus on valtuuttanut tämän tapahtuman Ulkoinen allekirjoittaja palautti pyyntöön nähden odottamattoman tietopaketin. Kyseessä voi olla vika Amethystissä tai allekirjoittajassa. diff --git a/commonsUI/src/commonMain/composeResources/values-fr-rCA/strings.xml b/commonsUI/src/commonMain/composeResources/values-fr-rCA/strings.xml index e31bf3e41c..8feba34b61 100644 --- a/commonsUI/src/commonMain/composeResources/values-fr-rCA/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fr-rCA/strings.xml @@ -211,7 +211,6 @@ Relais Site Web Adresse Lightning - Copie l'ID Nsec (votre mot de passe) dans le presse-papiers pour le sauvegarder Envoyer un message direct Modifie les métadonnées de l'utilisateur Débloquer @@ -266,9 +265,6 @@ Marquer tous les Connus comme lu Marquer tous les Nouveaux comme lu Tout marquer comme lu - ## Sauvegarde des Clés et Conseils de Sécurité \n\nVotre compte est sécurisé par une clé secrète. La clé est une longue séquence de caractères commençant par **nsec1**. Toute personne ayant accès à cette clé secrète peut publier et modifier votre identité. \n\n- Ne mettez **pas** votre clé secrète sur un site web ou un logiciel auquel vous ne faites pas confiance. \n- Les développeurs d'Amethyst ne vous demanderont **jamais** votre clé secrète. \n- **Faites** une sauvegarde sécurisée de votre clé secrète pour la récupération de votre compte. Nous vous recommandons d'utiliser un gestionnaire de mots de passe. - Pour plus de sécurité, vous pouvez chiffrer votre clé avec un mot de passe. Cette clé commence par **ncryptsec1** et ne peut être utilisée sans votre mot de passe. \n\nSi vous perdez votre mot de passe, vous ne pourrez pas récupérer votre clé. - Chiffrer et copier ma clé secrète Image de badge pour %1$s Image du badge de récompense Vous avez reçu un nouveau Badge @@ -1949,7 +1945,6 @@ Copie du contenu de la note dans le presse-papiers Copié dans le presse-papiers Copie du @npub utilisateur dans le presse-papiers - Copier ma clé secrète Copier dans le presse-papiers Impossible d'assembler LNUrl à partir de l'adresse Lightning "%1$s". Vérifiez la configuration de l'utilisateur Impossible de vérifier le fichier téléchargé après le téléversement : %1$s @@ -2717,10 +2712,8 @@ Partager en tant qu'URL de l'image Mise en ligne HLS Partager ou Enregistrer - Afficher le QR code de la clé privée chiffrée Inclure les messages directs et de groupe dans l'onglet Notifications. Désactivez pour conserver les messages uniquement dans l'onglet Messages. Voir les messages - Afficher le QR code de la clé privée Requête de signature rejetée Assurez-vous que l'application signataire a autorisé cette transaction Le signataire externe a renvoyé des données qui sont étranges pour la requête. Il peut y avoir un bug sur Amethyst ou le signataire. diff --git a/commonsUI/src/commonMain/composeResources/values-fr-rFR/strings.xml b/commonsUI/src/commonMain/composeResources/values-fr-rFR/strings.xml index 15fe140875..7ffcdad0ac 100644 --- a/commonsUI/src/commonMain/composeResources/values-fr-rFR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fr-rFR/strings.xml @@ -213,7 +213,6 @@ Relais Site Web Adresse Lightning - Copie l'ID Nsec (votre mot de passe) dans le presse-papiers pour le sauvegarder Envoyer un message direct Modifie les métadonnées de l'utilisateur Débloquer @@ -268,9 +267,6 @@ Marquer tous les Connus comme lu Marquer tous les Nouveaux comme lu Tout marquer comme lu - ## Sauvegarde des Clés et Conseils de Sécurité \n\nVotre compte est sécurisé par une clé secrète. La clé est une longue séquence de caractères commençant par **nsec1**. Toute personne ayant accès à cette clé secrète peut publier et modifier votre identité. \n\n- Ne mettez **pas** votre clé secrète sur un site web ou un logiciel auquel vous ne faites pas confiance. \n- Les développeurs d'Amethyst ne vous demanderont **jamais** votre clé secrète. \n- **Faites** une sauvegarde sécurisée de votre clé secrète pour la récupération de votre compte. Nous vous recommandons d'utiliser un gestionnaire de mots de passe. - Pour plus de sécurité, vous pouvez chiffrer votre clé avec un mot de passe. Cette clé commence par **ncryptsec1** et ne peut être utilisée sans votre mot de passe. \n\nSi vous perdez votre mot de passe, vous ne pourrez pas récupérer votre clé. - Chiffrer et copier ma clé secrète Image de badge pour %1$s Image du badge de récompense Vous avez reçu un nouveau Badge @@ -2138,7 +2134,6 @@ Copie du contenu de la note dans le presse-papiers Copié dans le presse-papiers Copie du @npub utilisateur dans le presse-papiers - Copier ma clé secrète Copier dans le presse-papiers Impossible d'assembler LNUrl à partir de l'adresse Lightning "%1$s". Vérifiez la configuration de l'utilisateur Impossible de vérifier le fichier téléchargé après le téléversement : %1$s @@ -3003,10 +2998,8 @@ Mise en ligne HLS Partager ou Enregistrer Shorts - Afficher le QR code de la clé privée chiffrée Inclure les messages directs et de groupe dans l'onglet Notifications. Désactivez pour conserver les messages uniquement dans l'onglet Messages. Voir les messages - Afficher le QR code de la clé privée Requête de signature rejetée Assurez-vous que l'application signataire a autorisé cette transaction Le signataire externe a renvoyé des données qui sont étranges pour la requête. Il peut y avoir un bug sur Amethyst ou le signataire. diff --git a/commonsUI/src/commonMain/composeResources/values-fr/strings.xml b/commonsUI/src/commonMain/composeResources/values-fr/strings.xml index 41b7112fcb..183135accd 100644 --- a/commonsUI/src/commonMain/composeResources/values-fr/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fr/strings.xml @@ -204,7 +204,6 @@ Relais Site Web Adresse Lightning - Copie l'ID Nsec (votre mot de passe) dans le presse-papiers pour le sauvegarder Envoyer un message direct Modifie les métadonnées de l'utilisateur Débloquer @@ -259,9 +258,6 @@ Marquer tous les Connus comme lu Marquer tous les Nouveaux comme lu Tout marquer comme lu - ## Sauvegarde des Clés et Conseils de Sécurité \n\nVotre compte est sécurisé par une clé secrète. La clé est une longue séquence de caractères commençant par **nsec1**. Toute personne ayant accès à cette clé secrète peut publier et modifier votre identité. \n\n- Ne mettez **pas** votre clé secrète sur un site web ou un logiciel auquel vous ne faites pas confiance. \n- Les développeurs d'Amethyst ne vous demanderont **jamais** votre clé secrète. \n- **Faites** une sauvegarde sécurisée de votre clé secrète pour la récupération de votre compte. Nous vous recommandons d'utiliser un gestionnaire de mots de passe. - Pour plus de sécurité, vous pouvez chiffrer votre clé avec un mot de passe. Cette clé commence par **ncryptsec1** et ne peut être utilisée sans votre mot de passe. \n\nSi vous perdez votre mot de passe, vous ne pourrez pas récupérer votre clé. - Chiffrer et copier ma clé secrète Image de badge pour %1$s Image du badge de récompense Vous avez reçu un nouveau Badge @@ -2038,7 +2034,6 @@ Copie du contenu de la note dans le presse-papiers Copié dans le presse-papiers Copie du @npub utilisateur dans le presse-papiers - Copier ma clé secrète Copier dans le presse-papiers Impossible d'assembler LNUrl à partir de l'adresse Lightning "%1$s". Vérifiez la configuration de l'utilisateur Impossible de vérifier le fichier téléchargé après le téléversement : %1$s @@ -2863,10 +2858,8 @@ Mise en ligne HLS Partager ou Enregistrer Shorts - Afficher le QR code de la clé privée chiffrée Inclure les messages directs et de groupe dans l'onglet Notifications. Désactivez pour conserver les messages uniquement dans l'onglet Messages. Voir les messages - Afficher le QR code de la clé privée Requête de signature rejetée Assurez-vous que l'application signataire a autorisé cette transaction Le signataire externe a renvoyé des données qui sont étranges pour la requête. Il peut y avoir un bug sur Amethyst ou le signataire. diff --git a/commonsUI/src/commonMain/composeResources/values-hi-rIN/strings.xml b/commonsUI/src/commonMain/composeResources/values-hi-rIN/strings.xml index 2bd0dcf453..ad244458af 100644 --- a/commonsUI/src/commonMain/composeResources/values-hi-rIN/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-hi-rIN/strings.xml @@ -545,7 +545,6 @@ पुनःप्रसारक जालस्थान लैटनिंग पता - एनसेक॰ सूचक (आपका गुप्त पारणशब्द) की अनुकृति करता है टाँकाफलक में सुरक्षित रखने के लिए सीधा संदेश भेजें उपयोगकर्ता के उपतथ्य का सम्पादन करता है बाधा हटाएँ @@ -654,14 +653,11 @@ सब ज्ञात को पढ लिया चिह्नित करें सब नये को पढ लिया चिह्नित करें सब को पढ लिया चिह्नित करें - ## कुंचिका सुरक्षार्थ अनुकृति तथा सुरक्षा सुझाव \n\nआपकी लेखा एक गुप्त कुंचिका से सुरक्षित किया गया है। कुंचिका अक्षरों की एक लम्बी श्रृंखला है जो **nsec1** से आरम्भ होता है। जिस किसी के पास यह कुंचिका है वह पत्र प्रकाशित कर सकेगा तथा आपका परिचय परिवर्तित कर सकेगा। \n\n- आपकी गुप्त कुंचिका किसी भी जालस्थान अथवा क्रमक में **ना** डालें जिसपर आपका विश्वास ना हो। \n- अमेथिस्ट क्रमलेख विकासकर्ता आपकी गुप्त कुंचिका **कभी नहीं** पूछेंगे। \n- आपकी गुप्त कुंचिका की एक सुरक्षित अनुकृति **अवश्य** रखें अपनी लेखा पुनः प्राप्त करने के लिए। पारणशब्ध प्रबंधन क्रमक की पुनः प्रशंसा करते हैं। - अधिक सुरक्षा के लिए आप अपनी कुंचिका का रहस्यीकरण कर सकते हैं एक पारणशब्द के साथ। यह कुंचिका आरम्भ होगी **ncryptsec1** से तथा पारणशब्द के बिना प्रयोग साध्य नहीं। \n\n यदि आप अपना पारणशब्द खो देते हैं, तो आप अपनी कुंचिका को पुनः प्राप्त नहीं कर सकते। अपने कुंचिकाओं को सुरक्षित रखें आपकी गुप्त कुंचिका एकमात्र विधि है इस लेखा का अभिगमन करने के लिए। यदि आप इसे खो देते हैं तो इसे कभी भी पुनःप्राप्त नहीं कर सकते। इसे कहीं सुरक्षित रखें अभी इस समय। अभी इसी समय सुरक्षित अनुकृति बनाएँ उनको मैंने सुरक्षित कर लिया हटाएँ - मेरी गुप्त कुंचिका का रहस्यीकरण तथा अनुकृति करें पदक पुरस्कार चित्र %1$s के लिए "पदक पुरस्कार चित्र आपको नया पदक पुरस्कार प्राप्त हुआ @@ -3577,7 +3573,6 @@ टीका लेख की अनुकृति की गई टाँकाफलक में टाँकाफलक में अनुकृत लेखक के @npub की अनुकृति की गई टाँकाफलक में - मेरी गुप्त कुंचिका की अनुकृति करें टाँकाफलक में अनुकृति करें लै॰जालपता नहीं बना पाए लै॰पता "%1$s" से। उपयोगकर्ता की स्थापना की जाँच करें आरोहण पश्चात अवरोहित अभिलेख की जाँच नहीं हो सकी : %1$s @@ -5040,10 +5035,8 @@ एचएलएस॰ आरोहण बाँटें अथवा अभिलेखन करें लघु चलचित्र - रहस्यीकृत निजी कुंचिका क्यूआर॰ चित्र अक्षरराशि दिखाएँ सूचनाएँ पृष्ठ पर सीधे तथा समूह सन्देशों को समाविष्ट करें। निष्क्रिय करें यदि सन्देशों को केवल सन्देश पृष्ठ में रखना चाहते हों तो। सन्देशों को दिखाएँ - निजी कुंचिका क्यूआर॰ चित्र अक्षरराशि दिखाएँ हस्ताक्षर अनुरोध अस्वीकृत सुनिश्चित करें हस्ताक्षर क्रमक ने इस व्यापार को अनुमति दिया बाहरी हस्ताक्षरकर्ता द्वारा दिया गया उत्तर विचित्र है अनुरोध के लिए। अमेथिस्ट अथवा हस्ताक्षरकर्ता में कुछ दोष हो सकता है। diff --git a/commonsUI/src/commonMain/composeResources/values-hu-rHU/strings.xml b/commonsUI/src/commonMain/composeResources/values-hu-rHU/strings.xml index 396bea328a..c33e43e167 100644 --- a/commonsUI/src/commonMain/composeResources/values-hu-rHU/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-hu-rHU/strings.xml @@ -545,7 +545,6 @@ Átjátszó Weboldal Lightning-cím - Az Nsec azonosítót (az Ön „jelszavát”) a vágólapra másolja biztonsági mentés céljából Közvetlen üzenet küldése Felhasználó metaadatainak szerkesztése Letiltás megszüntetése @@ -654,14 +653,11 @@ Az összes ismert megjelölése olvasottként Az összes új üzenet megjelölése olvasottként Összes megjelölése olvasottként - ## Kulcs- és biztonsági mentési tippek \n\nFiókját egy titkos kulcs védi. A kulcs egy hosszú véletlenszerű karakterlánc, amely **nsec1**-vel kezdődik. Bárki, aki az Ön titkos kulcsához hozzáfér, az Ön személyazonosságának használatával bármilyen tartalmat közzétehet. \n\n- **Ne** helyezze el a titkos kulcsát olyan webhelyen vagy szoftverben, amelyben nem bízik. \n- Az Amethyst fejlesztői az Ön titkos kulcsát **soha** nem fogják Öntől elkérni. \n- A fiókja helyrehozása érdekében, a titkos kulcsáról **mindig** készítsen biztonsági másolatot. Javasoljuk egy jelszókezelő használatát. - A nagyobb biztonság érdekében titkosítsa egy jelszóval. A jelszóval védett kulcs **ncryptsec1**-vel kezdődik, és a jelszava nélkül nem használható. \n\nHa elveszíti a jelszavát, nem tudja helyrehozni a kulcsát. Biztonsági mentés készítése a kulcsokról A titkos kulcs megadása az egyetlen módja a fiók elérésének. Ha elveszíti, akkor soha nem tudja helyrehozni. Mentse el biztonságos helyre most. Biztonsági mentés most Elmentettem a kulcsokat Eltüntetés - Saját titkos kulcs titkosítása és másolása Kitűző %1$s számára Kitűző képe Ön egy új kitűzőt kapott @@ -3577,7 +3573,6 @@ Bejegyzés szövege a vágólapra másolva Vágólapra másolva A szerző @npub-ja a vágólapra másolva - Saját titkos kulcs másolása Másolás a vágólapra Nem sikerült az LN-webcímet a(z) „%1$s” Lightning-címről összeállítani. Ellenőrizze a felhasználó beállításait Nem lehetett ellenőrizni a letöltött fájlt a feltöltés után: %1$s @@ -5040,10 +5035,8 @@ HLS-feltöltés Megosztás vagy mentés Rövidek - Jelszóval védett privát kulcs megjelenítése QR-kódként Közvetlen és csoportos üzenetek megjelenítése az Értesítések lapon. Kapcsolja ki, ha az üzeneteket csak az Üzenetek lapon szeretné látni. Üzenetek megjelenítése - Privát kulcs megjelenítése QR-kódként Aláírási kérés elutasítva Győződjön meg arról, hogy ezt a tranzakciót az aláíró-alkalmazás hitelesítette-e A külső aláíró a kéréstől eltérő, szokatlan választ küldött. Lehet, hogy hiba lépett fel az Amethystben vagy az aláíró alkalmazásban. diff --git a/commonsUI/src/commonMain/composeResources/values-in-rID/strings.xml b/commonsUI/src/commonMain/composeResources/values-in-rID/strings.xml index 9ff7d96b62..ce34156cf5 100644 --- a/commonsUI/src/commonMain/composeResources/values-in-rID/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-in-rID/strings.xml @@ -211,7 +211,6 @@ Relai Situs web Alamat Lightning - Salin ID Nsec (kata sandi Anda) ke papan klip untuk cadangan Kirim Pesan Langsung Ubah metadata pengguna Buka blokir @@ -266,9 +265,6 @@ Tandai semua yang dikenal sebagai telah dibaca Tandai semua yang baru sebagai telah dibaca Tandai semua sebagai telah dibaca - ## Tips Cadangan Kunci dan Keamanan \n\nAkun Anda diamankan dengan kunci rahasia. Kunci ini adalah rangkaian karakter panjang yang diawali dengan **nsec1**. Siapa pun yang memiliki akses ke kunci rahasia ini dapat memposting dan mengubah identitas Anda. \n\n- **Jangan** memasukkan kunci rahasia Anda ke situs web atau perangkat lunak yang tidak Anda percaya. \n- Pengembang Amethyst **tidak akan pernah** meminta kunci rahasia Anda. \n- **Lakukan** pencadangan kunci rahasia Anda secara aman untuk pemulihan akun. Kami merekomendasikan penggunaan pengelola kata sandi. - Untuk keamanan tambahan, Anda dapat mengenkripsi kunci dengan kata sandi. Kunci ini diawali dengan **ncryptsec1** dan tidak dapat digunakan tanpa kata sandi Anda. \n\nJika Anda kehilangan kata sandi, Anda tidak akan dapat memulihkan kunci Anda. - Enkripsi dan salin kunci rahasia saya Gambar penghargaan lencana untuk %1$s "Gambar penghargaan lencana Anda menerima penghargaan lencana baru @@ -1972,7 +1968,6 @@ Teks disalin ke papan klip Disalin ke clipboard @npub pemilik telah disalin ke papan klip - Salin kunci rahasia saya Salin ke clipboard Tidak dapat merakit LNUrl dari Alamat Lightning "%1$s". Periksa pengaturan pengguna Tidak dapat memeriksa file yang diunduh setelah diunggah: %1$s @@ -2721,10 +2716,8 @@ Bagikan sebagai URL Gambar Unggah HLS Bagikan atau Simpan - Tampilkan kode QR kunci privat terenkripsi Sertakan pesan langsung dan grup pada tab Notifikasi. Matikan untuk menyimpan pesan hanya di tab Pesan. Tampilkan Pesan - Tampilkan kode QR kunci privat Permintaan tanda tangan ditolak Pastikan aplikasi penandatangan telah mengizinkan transaksi ini Penanda tangan eksternal mengembalikan payload yang tidak sesuai dengan permintaan. Mungkin ada bug di Amethyst atau di penanda tangan. diff --git a/commonsUI/src/commonMain/composeResources/values-in/strings.xml b/commonsUI/src/commonMain/composeResources/values-in/strings.xml index 2fe9f6457e..55ec897974 100644 --- a/commonsUI/src/commonMain/composeResources/values-in/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-in/strings.xml @@ -202,7 +202,6 @@ Relai Situs Web Alamat Lightning - Salin Nsec ID (kata sandi anda) ke papan klip sebagai cadangan Kirim Pesan Langsung Ubah Metadata Pengguna Batalkan blokir @@ -257,9 +256,6 @@ Tandai semua yg dikenal telah dibaca Tandai pesan baru telah dibaca Tandai semua telah dibaca - ## Tips Cadangan Kunci dan Keamanan \n\nAkun Anda diamankan dengan kunci rahasia. Kunci ini adalah rangkaian karakter panjang yang diawali dengan **nsec1**. Siapa pun yang memiliki akses ke kunci rahasia ini dapat memposting dan mengubah identitas Anda. \n\n- **Jangan** memasukkan kunci rahasia Anda ke situs web atau perangkat lunak yang tidak Anda percaya. \n- Pengembang Amethyst **tidak akan pernah** meminta kunci rahasia Anda. \n- **Lakukan** pencadangan kunci rahasia Anda secara aman untuk pemulihan akun. Kami merekomendasikan penggunaan pengelola kata sandi. - Untuk keamanan tambahan, Anda dapat mengenkripsi kunci dengan kata sandi. Kunci ini diawali dengan **ncryptsec1** dan tidak dapat digunakan tanpa kata sandi Anda. \n\nJika Anda kehilangan kata sandi, Anda tidak akan dapat memulihkan kunci Anda. - Enkripsi dan salin kunci rahasia saya Gambar penghargaan lencana untuk %1$s "Gambar penghargaan lencana Anda Menerima Penghargaan Lencana baru @@ -2028,7 +2024,6 @@ Teks catatan disalin ke papan klip Disalin ke clipboard @npub Penulis disalin ke papan klip - Salin kunci rahasia saya Salin ke clipboard Tidak dapat merakit LNUrl dari Alamat Lightning "%1$s". Periksa pengaturan pengguna Tidak dapat memeriksa file yang diunduh setelah diunggah: %1$s @@ -2827,10 +2822,8 @@ Unggah HLS Bagikan atau Simpan Shorts - Tampilkan kode QR kunci privat terenkripsi Sertakan pesan langsung dan grup pada tab Notifikasi. Matikan untuk menyimpan pesan hanya di tab Pesan. Tampilkan Pesan - Tampilkan kode QR kunci privat Permintaan tanda tangan ditolak Pastikan aplikasi penandatangan telah mengizinkan transaksi ini Penanda tangan eksternal mengembalikan payload yang tidak sesuai dengan permintaan. Mungkin ada bug di Amethyst atau di penanda tangan. diff --git a/commonsUI/src/commonMain/composeResources/values-it-rIT/strings.xml b/commonsUI/src/commonMain/composeResources/values-it-rIT/strings.xml index e097e17c7f..46a70f4033 100644 --- a/commonsUI/src/commonMain/composeResources/values-it-rIT/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-it-rIT/strings.xml @@ -212,7 +212,6 @@ Relè Sito web Indirizzo Lightning - Copia l'ID Nsec (la password) negli appunti per il backup Invia un messaggio diretto Modifica i metadati dell'utente Sblocca @@ -266,9 +265,6 @@ Segna tutti i conosciuti come letti Segna tutti i nuovi come letti Segna tutti come letti - ## Suggerimenti per il backup e la sicurezza della chiave \n\nIl tuo account è protetto da una chiave segreta. La chiave è una lunga sequenza di caratteri che inizia con **nsec1**. Chiunque abbia accesso a questa chiave segreta può pubblicare e modificare la tua identità. \n\n- **Non** inserire la tua chiave segreta in nessun sito web o software di cui non ti fidi. \n- Gli sviluppatori di Amethyst non chiederanno **mai** la tua chiave segreta. \n- **Conserva** un backup sicuro della tua chiave segreta per il recupero dell'account. Si consiglia l'uso di un gestore di password. - Per maggiore sicurezza, puoi cifrare la tua chiave con una password. Questa chiave inizia con **ncryptsec1** e non può essere utilizzata senza la tua password. \n\nSe perdi la password, non potrai recuperare la tua chiave. - Cifra e copia la mia chiave segreta Immagine premio badge per %1$s "Immagine del premio badge Hai ricevuto un nuovo premio Badge @@ -1969,7 +1965,6 @@ Testo della nota copiato negli appunti Copiato negli appunti @npub dell'autore copiata negli appunti - Copia la mia chiave segreta Copia negli appunti Impossibile assemblare LNUrl dall'indirizzo Lightning "%1$s". Controlla la configurazione dell'utente Impossibile verificare il file scaricato dopo il caricamento: %1$s @@ -2754,10 +2749,8 @@ Condividi come URL immagine Caricamento HLS Condividi o salva - Mostra QR code della chiave privata cifrata Includi messaggi diretti e di gruppo nella scheda Notifiche. Disattiva per tenere i messaggi solo nella scheda Messaggi. Mostra messaggi - Mostra QR code della chiave privata Richiesta di firma rifiutata Assicurati che l'applicazione signer abbia autorizzato questa transazione Il firmatario esterno ha restituito un payload inatteso per la richiesta. Potrebbe esserci un bug in Amethyst o nell'app firmatario. diff --git a/commonsUI/src/commonMain/composeResources/values-ja-rJP/strings.xml b/commonsUI/src/commonMain/composeResources/values-ja-rJP/strings.xml index 61af0a4940..d05cf2e3ba 100644 --- a/commonsUI/src/commonMain/composeResources/values-ja-rJP/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ja-rJP/strings.xml @@ -216,7 +216,6 @@ リレー ウェブサイト Lightningアドレス - バックアップ用に nsec ID (パスワード) をクリップボードにコピー ダイレクトメッセージを送信 ユーザのメタデータを編集 ブロック解除 @@ -271,9 +270,6 @@ すべての「知り合い」を既読にする すべての「新規リクエスト」を既読にする すべて既読にする - ## 鍵のバックアップとセキュリティのヒント \n\nアカウントは秘密鍵によって保護されています。この鍵は **nsec1** で始まる長い文字列です。この秘密鍵にアクセスできる人は誰でも、あなたの名前でポストしたり、プロフィールを変更したりできます。 \n\n- 信頼していないウェブサイトやアプリに秘密鍵を **入力しないでください**。 \n- Amethyst の開発者が秘密鍵を **求めることは絶対にありません**。 \n- アカウントの復元のために、秘密鍵の安全なバックアップを **必ず** 保管してください。パスワードマネージャーの使用をお勧めします。 - さらにセキュリティを高めるために、鍵をパスワードで暗号化することができます。この鍵は **ncryptsec1** で始まり、パスワードなしでは使用できません。 \n\nパスワードを忘れると、鍵を復元できなくなります。 - 秘密鍵を暗号化してコピー %1$sのバッジ授与画像 バッジ授与の画像 新しいバッジが授与されました @@ -1999,7 +1995,6 @@ テキストがクリップボードにコピーされました クリップボードにコピーしました @npubをクリップボードにコピーしました - 秘密鍵をコピー クリップボードにコピー Lightning アドレス「%1$s」から LNUrl を組み立てられませんでした。ユーザーの設定を確認してください アップロード後にダウンロードしたファイルを確認できませんでした:%1$s @@ -2774,10 +2769,8 @@ HLS アップロード 共有または保存 ショート - 暗号化された秘密鍵の QR コードを表示 通知タブにダイレクト・グループメッセージを含めます。オフにするとメッセージはメッセージタブのみに表示されます。 メッセージを表示 - 秘密鍵の QR コードを表示 署名リクエストが拒否されました 署名アプリがこのトランザクションを承認していることを確認してください 外部署名アプリがリクエストに対して予期しないペイロードを返しました。Amethyst または署名アプリにバグがある可能性があります。 diff --git a/commonsUI/src/commonMain/composeResources/values-ja/strings.xml b/commonsUI/src/commonMain/composeResources/values-ja/strings.xml index 8e2365c27e..e2b24e5fac 100644 --- a/commonsUI/src/commonMain/composeResources/values-ja/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ja/strings.xml @@ -202,7 +202,6 @@ リレー ウェブサイト Lightningアドレス - バックアップ用に nsec ID (パスワード) をクリップボードにコピー ダイレクトメッセージを送信 ユーザのメタデータを編集 ブロック解除 @@ -257,9 +256,6 @@ すべての「知り合い」を既読にする すべての「新規リクエスト」を既読にする すべて既読にする - ## 鍵のバックアップとセキュリティのヒント \n\nアカウントは秘密鍵によって保護されています。この鍵は **nsec1** で始まる長い文字列です。この秘密鍵にアクセスできる人は誰でも、あなたの名前でポストしたり、プロフィールを変更したりできます。 \n\n- 信頼していないウェブサイトやアプリに秘密鍵を **入力しないでください**。 \n- Amethyst の開発者が秘密鍵を **求めることは絶対にありません**。 \n- アカウントの復元のために、秘密鍵の安全なバックアップを **必ず** 保管してください。パスワードマネージャーの使用をお勧めします。 - さらにセキュリティを高めるために、鍵をパスワードで暗号化することができます。この鍵は **ncryptsec1** で始まり、パスワードなしでは使用できません。 \n\nパスワードを忘れると、鍵を復元できなくなります。 - 秘密鍵を暗号化してコピー %1$sのバッジ授与画像 バッジ授与の画像 新しいバッジが授与されました @@ -2028,7 +2024,6 @@ テキストがクリップボードにコピーされました クリップボードにコピーしました @npubをクリップボードにコピーしました - 秘密鍵をコピー クリップボードにコピー Lightning アドレス「%1$s」から LNUrl を組み立てられませんでした。ユーザーの設定を確認してください アップロード後にダウンロードしたファイルを確認できませんでした:%1$s @@ -2827,10 +2822,8 @@ HLS アップロード 共有または保存 ショート - 暗号化された秘密鍵の QR コードを表示 通知タブにダイレクト・グループメッセージを含めます。オフにするとメッセージはメッセージタブのみに表示されます。 メッセージを表示 - 秘密鍵の QR コードを表示 署名リクエストが拒否されました 署名アプリがこのトランザクションを承認していることを確認してください 外部署名アプリがリクエストに対して予期しないペイロードを返しました。Amethyst または署名アプリにバグがある可能性があります。 diff --git a/commonsUI/src/commonMain/composeResources/values-ko-rKR/strings.xml b/commonsUI/src/commonMain/composeResources/values-ko-rKR/strings.xml index 68998b3497..b5f94f364a 100644 --- a/commonsUI/src/commonMain/composeResources/values-ko-rKR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ko-rKR/strings.xml @@ -211,7 +211,6 @@ relay 웹사이트 Lightning 주소 - Nsec ID(비밀번호)를 백업을 위해 클립보드에 복사합니다 다이렉트 메시지 보내기 사용자 메타데이터 편집 차단 해제 @@ -266,9 +265,6 @@ 알려진 항목 모두 읽음 표시 새 항목 모두 읽음 표시 모두 읽음 표시 - ## 키 백업 및 보안 팁 \n\n계정은 비밀 키로 보호됩니다. 키는 **nsec1**로 시작하는 긴 문자열입니다. 이 비밀 키에 접근할 수 있는 누구든 게시물 작성 및 신원 변경이 가능합니다. \n\n- 신뢰하지 않는 웹사이트나 소프트웨어에 비밀 키를 **입력하지** 마세요. \n- Amethyst 개발자는 **절대** 비밀 키를 요청하지 않습니다. \n- 계정 복구를 위해 비밀 키를 안전하게 백업해 **두세요**. 비밀번호 관리자 사용을 권장합니다. - 추가 보안을 위해 비밀번호로 키를 암호화할 수 있습니다. 이 키는 **ncryptsec1**로 시작하며 비밀번호 없이는 사용할 수 없습니다. \n\n비밀번호를 분실하면 키를 복구할 수 없습니다. - 내 비밀 키 암호화 및 복사 %1$s의 배지 수상 이미지 "배지 수상 이미지 새 배지를 수여받았습니다 @@ -1988,7 +1984,6 @@ 노트 텍스트가 클립보드에 복사되었습니다 클립보드에 복사됨 작성자의 @npub가 클립보드에 복사되었습니다 - 내 비밀 키 복사 클립보드에 복사 Lightning 주소 "%1$s"에서 LNUrl을 구성할 수 없습니다. 사용자 설정을 확인하세요 업로드 후 다운로드된 파일을 확인할 수 없습니다: %1$s @@ -2759,10 +2754,8 @@ 이미지 URL로 공유 HLS 업로드 공유 또는 저장 - 암호화된 개인 키 QR 코드 표시 알림 탭에 다이렉트 및 그룹 메시지를 포함합니다. 메시지를 메시지 탭에만 표시하려면 끄세요. 메시지 표시 - 개인 키 QR 코드 표시 서명 요청이 거부됨 서명 앱이 이 트랜잭션을 승인했는지 확인하세요 외부 서명 앱이 요청과 맞지 않는 응답을 반환했습니다. Amethyst 또는 서명 앱에 버그가 있을 수 있습니다. diff --git a/commonsUI/src/commonMain/composeResources/values-lv-rLV/strings.xml b/commonsUI/src/commonMain/composeResources/values-lv-rLV/strings.xml index 0c9953b12e..159c676759 100644 --- a/commonsUI/src/commonMain/composeResources/values-lv-rLV/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-lv-rLV/strings.xml @@ -220,7 +220,6 @@ Relay Vietne Lightning adrese - Kopē Nsec ID (jūsu paroli) starpliktuvē dublēšanai Sūtīt tiešo ziņojumu Rediģē lietotāja metadatus Atbloķēt @@ -277,11 +276,8 @@ Atzīmēt visu zināmo kā lasītu Atzīmēt visu jauno kā lasītu Atzīmēt visu kā lasītu - ## Atslēgas dublēšanas un drošības padomi \n\nJūsu konts ir aizsargāts ar slepeno atslēgu. Atslēga ir gara rakstzīmju secība, kas sākas ar **nsec1**. Ikviens, kam ir piekļuve šai slepenai atslēgai, var publicēt un mainīt jūsu identitāti. \n\n- **Neievietojiet** savu slepeno atslēgu nevienā tīmekļa vietnē vai programmatūrā, kurai neuzticaties. \n- Amethyst izstrādātāji **nekad** neprasīs jūsu slepeno atslēgu. \n- **Glabājiet** drošu slepenas atslēgas dublējumu konta atjaunošanai. Mēs iesakām izmantot paroļu pārvaldnieku. - Papildu drošībai variet šifrēt atslēgu ar paroli. Šī atslēga sāksies ar **ncryptsec1** virkni un to nevarēs izmantot bez šīs paroles. \n\nJa jūs aizmirsīsiet paroli, vairs nevarēsiet atgūt savu atslēgu. Jūsu slepenā atslēga ir vienīgais veids, kā piekļūt šim kontam. Ja to pazaudēsiet, tad nekad nevarēsiet atgūt piekļuvi kontam. Saglabājiet atslēgu drošā vietā tagad. Esiet tās saglabājuši - Šifrēt un kopēt manu slepeno atslēgu Žetona piešķiršanas attēls par %1$s "Žetona piešķiršanas attēls Jūs saņēmāt jaunu žetonu @@ -2020,7 +2016,6 @@ Piezīmes teksts nokopēts starpliktuvē Nokopēts starpliktuvē Autora @npub nokopēts starpliktuvē - Kopēt manu slepeno atslēgu Kopēt starpliktuvē Nevarēja izveidot LNUrl no Lightning adreses "%1$s". Pārbaudiet lietotāja iestatījumus Nevarēja pārbaudīt lejupielādēto failu pēc augšupielādes: %1$s @@ -2842,10 +2837,8 @@ HLS augšupielāde Kopīgot vai saglabāt Šorti - Rādīt šifrētās privātās atslēgas QR kodu Iekļaut tiešās un grupas ziņas paziņojumu cilnē. Izslēdziet, lai ziņas tiktu rādītas tikai ziņojumu cilnē. Rādīt ziņas - Rādīt privātās atslēgas QR kodu Parakstīšanas pieprasījums noraidīts Pārliecinieties, ka parakstītāja lietotne ir autorizējusi šo darījumu Ārējais parakstītājs atgrieza neparastu atbildi uz pieprasījumu. Iespējams, ir kļūda Amethyst vai parakstītājā. diff --git a/commonsUI/src/commonMain/composeResources/values-nl-rBE/strings.xml b/commonsUI/src/commonMain/composeResources/values-nl-rBE/strings.xml index db64544d90..b47be71e33 100644 --- a/commonsUI/src/commonMain/composeResources/values-nl-rBE/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-nl-rBE/strings.xml @@ -204,7 +204,6 @@ Relays Website Lightning-adres - Kopieert je privésleutel (nsec) naar het klembord voor back-up Stuur privébericht Bewerkt gebruikers-metadata Deblokkeren @@ -259,7 +258,6 @@ Alle bekende markeren als gelezen Alle nieuwe markeren als gelezen Alles markeren als gelezen - Versleutel en kopieer mijn privésleutel Badge-awardafbeelding voor %1$s Badge-awardafbeelding Je hebt een nieuwe badge-award ontvangen @@ -1800,8 +1798,6 @@ Explorer API-basis-URL Factuur betalen van de DVM %1$s sats betalen aan de DVM - ## Sleutelback-up en veiligheidstips\n\nJe account wordt beveiligd door een privésleutel (begint met **nsec1**). Iedereen met deze sleutel kan namens jou posten.\n\n- Voer je privésleutel **nooit** in op een website of app die je niet volledig vertrouwt.\n- Amethyst-ontwikkelaars zullen **nooit** om je privésleutel vragen.\n- Maak een veilige back-up van je privésleutel (bijvoorbeeld in een wachtwoordmanager). - Voor extra veiligheid kun je je sleutel versleutelen met een wachtwoord. Deze versleutelde sleutel begint met **ncryptsec1** en kan alleen met je wachtwoord worden gebruikt.\n\nAls je het wachtwoord vergeet, kun je de sleutel niet meer herstellen. Directe URL gebruiken Statische website: %1$s Root-site @@ -2038,7 +2034,6 @@ Note-tekst gekopieerd naar klembord Gekopieerd naar klembord Gebruikers-ID (@npub…) gekopieerd naar klembord - Mijn privésleutel kopiëren Kopiëren naar klembord Kon LNURL niet samenstellen vanuit Lightning-adres "%1$s". Controleer de instellingen van de gebruiker. Kon gedownload bestand niet controleren na upload: %1$s @@ -2863,10 +2858,8 @@ HLS-upload Delen of opslaan Shorts - Toon versleutelde QR-code van privésleutel Directe berichten en groepsberichten opnemen in het tabblad Meldingen. Uitschakelen om berichten alleen in het tabblad Berichten te houden. Berichten tonen - Toon QR-code van privésleutel Ondertekenverzoek afgewezen Zorg dat de signer-app dit verzoek heeft goedgekeurd. Externe signer heeft een onjuiste payload geretourneerd voor dit verzoek. Er kan een bug zitten in Amethyst of in de signer. diff --git a/commonsUI/src/commonMain/composeResources/values-nl-rNL/strings.xml b/commonsUI/src/commonMain/composeResources/values-nl-rNL/strings.xml index a47c701a37..cc49452a22 100644 --- a/commonsUI/src/commonMain/composeResources/values-nl-rNL/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-nl-rNL/strings.xml @@ -338,7 +338,6 @@ %1$s rapportages Relays Lightning-adres - Kopieert je privésleutel (nsec) naar het klembord voor back-up Stuur privébericht Bewerkt gebruikers-metadata Deblokkeren @@ -444,14 +443,11 @@ Alle bekende markeren als gelezen Alle nieuwe markeren als gelezen Alles markeren als gelezen - ## Sleutelback-up en veiligheidstips\n\nJe account wordt beveiligd door een privésleutel (begint met **nsec1**). Iedereen met deze sleutel kan namens jou posten.\n\n- Voer je privésleutel **nooit** in op een website of app die je niet volledig vertrouwt.\n- Amethyst-ontwikkelaars zullen **nooit** om je privésleutel vragen.\n- Maak een veilige back-up van je privésleutel (bijvoorbeeld in een wachtwoordmanager). - Voor extra veiligheid kun je je sleutel versleutelen met een wachtwoord. Deze versleutelde sleutel begint met **ncryptsec1** en kan alleen met je wachtwoord worden gebruikt.\n\nAls je het wachtwoord vergeet, kun je de sleutel niet meer herstellen. Maak een back-up van je sleutels Je geheime sleutel is de enige manier om bij dit account te komen. Raak je hem kwijt, dan is hij nooit meer te herstellen. Sla hem nu op een veilige plek op. Nu back-uppen Ik heb ze opgeslagen Sluiten - Versleutel en kopieer mijn privésleutel Badge-awardafbeelding voor %1$s Badge-awardafbeelding Je hebt een nieuwe badge-award ontvangen @@ -3081,7 +3077,6 @@ Note-tekst gekopieerd naar klembord Gekopieerd naar klembord Gebruikers-ID (@npub…) gekopieerd naar klembord - Mijn privésleutel kopiëren Kopiëren naar klembord Kon LNURL niet samenstellen vanuit Lightning-adres "%1$s". Controleer de instellingen van de gebruiker. Kon gedownload bestand niet controleren na upload: %1$s @@ -4473,10 +4468,8 @@ HLS-upload Delen of opslaan Shorts - Toon versleutelde QR-code van privésleutel Directe berichten en groepsberichten opnemen in het tabblad Meldingen. Uitschakelen om berichten alleen in het tabblad Berichten te houden. Berichten tonen - Toon QR-code van privésleutel Ondertekenverzoek afgewezen Zorg dat de signer-app dit verzoek heeft goedgekeurd. Externe signer heeft een onjuiste payload geretourneerd voor dit verzoek. Er kan een bug zitten in Amethyst of in de signer. diff --git a/commonsUI/src/commonMain/composeResources/values-nl/strings.xml b/commonsUI/src/commonMain/composeResources/values-nl/strings.xml index 5ddca3ba0e..062bc8ef1b 100644 --- a/commonsUI/src/commonMain/composeResources/values-nl/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-nl/strings.xml @@ -204,7 +204,6 @@ Relays Website Lightning Adress - Kopieert het NSEC ID (uw wachtwoord) naar klembord voor back-up. Stuur een privébericht Bewerkt de metadata van de gebruiker Deblokkeren @@ -259,9 +258,6 @@ Bekende markeren als gelezen Nieuwe markeren als gelezen Alles markeren als gelezen - ## Sleutel back-up en veiligheidstips \n\nUw account is beveiligd met een privésleutel. De sleutel is een lange, willekeurige reeks die begint met **nsec1**. Iedereen die toegang heeft tot uw privésleutel kan inhoud publiceren met uw identiteit. \n\n- Voer uw privésleutel **nooit** in een website of software die u niet vertrouwt. \n- Amethyst ontwikkelaars zullen u **nooit** om uw privésleutel vragen. \n- **Bewaar** een veilige back-up van uw privésleutel voor accountherstel. Wij raden u aan een wachtwoordmanager te gebruiken. - Voor meer veiligheid kan je je sleutel versleutelen met een wachtwoord. Deze sleutel begint met **ncryptsec1** en kan niet worden gebruikt zonder uw wachtwoord. \n\nAls je je wachtwoord verliest, je kan je sleutel niet herstellen. - Versleutel en kopieer mijn geheime sleutel Badge award afbeelding voor %1$s Badge-awardafbeelding Je hebt een nieuwe Badge award ontvangen @@ -2038,7 +2034,6 @@ Note tekst gekopieerd naar klembord Gekopieerd naar klembord @npub auteur gekopieerd naar klembord - Kopieer mijn privésleutel Kopiëren naar klembord Kon LNUrl niet samenbrengen van Lightning Adress "%1$s". Controleer de instellingen van de gebruiker Kan het gedownloade bestand niet controleren na upload: %1$s @@ -2863,10 +2858,8 @@ HLS-upload Delen of opslaan Shorts - Toon versleutelde QR-code van privésleutel Directe berichten en groepsberichten opnemen in het tabblad Meldingen. Uitschakelen om berichten alleen in het tabblad Berichten te houden. Berichten tonen - Toon QR-code van privésleutel Ondertekenverzoek afgewezen Zorg ervoor dat de teken-app deze transactie heeft geautoriseerd Externe signer heeft een onjuiste payload geretourneerd voor dit verzoek. Er kan een bug zitten in Amethyst of in de signer. diff --git a/commonsUI/src/commonMain/composeResources/values-pl-rPL/strings.xml b/commonsUI/src/commonMain/composeResources/values-pl-rPL/strings.xml index 906a63b569..8b1f5cd7f1 100644 --- a/commonsUI/src/commonMain/composeResources/values-pl-rPL/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-pl-rPL/strings.xml @@ -561,7 +561,6 @@ Transmitery Strona www Lightning Adres - Kopiuje Nsec ID (hasło) do schowka w celu wykonania kopii zapasowej Wyślij bezpośrednią wiadomość Edytowanie metadanych użytkowników Odblokuj @@ -670,14 +669,11 @@ Zaznacz wszystkie popularne jako przeczytane Zaznacz wszystkie nowe jako przeczytane Zaznacz wszystkie jako przeczytane - ## Porady dotyczące kopii zapasowej i bezpieczeństwa \n\nTwoje konto jest zabezpieczone tajnym kluczem. Kluczem jest długa sekwencja znaków, zaczynająca się od **nsec1**. Każdy, kto ma dostęp do tego tajnego klucza może publikować i zmieniać Twoją tożsamość. \n\n- **nie** umiejszczaj swojego tajnego klucza na żadnej stronie internetowej lub oprogramowaniu, któremu nie ufasz. \n- Deweloperzy Ametyst **nigdy** nie będą prosić o Twój tajny klucz. \n- **Zrób ** bezpieczną kopię zapasową swojego tajnego klucza do ewentualnego odzyskania konta. Zalecamy użycie menedżera haseł. - Dla dodatkowego bezpieczeństwa możesz zaszyfrować swój klucz hasłem. Ten klucz zaczyna się od **ncryptsec1** i nie może być użyty bez hasła. \n\nJeśli zgubisz hasło, nie będziesz w stanie odzyskać swojego klucza. Kopia zapasowa kluczy Twój tajny klucz jest jedynym sposobem na dostęp do tego konta. Jeśli go zgubisz, nigdy nie będzie można go odzyskać. Zapisz go w bezpiecznym miejscu. Utwórz kopię zapasową Zapisałem(am) Ignoruj - Zaszyfruj i skopiuj mój tajny klucz Wizerunek odznaki dla %1$s Wizerunek odznaki Otrzymałeś nową odznakę @@ -3653,7 +3649,6 @@ Skopiowano tekst wpisu do schowka Skopiowano do schowka Skopiowano @npub autora do schowka - Kopiuj mój tajny klucz Kopiuj do schowka Nie można stworzyć LNUrl z Adresu "%1$s". Sprawdź konfigurację użytkownika Nie można sprawdzić pobranego pliku po wgraniu: %1$s @@ -5256,10 +5251,8 @@ Wgraj HLS Udostępnij lub zapisz Filmiki - Pokaż zaszyfrowany kod QR klucza prywatnego W zakładce „Powiadomienia” znajdują się zarówno wiadomości bezpośrednie, jak i grupowe. Wyłącz tę opcję, aby wiadomości były wyświetlane wyłącznie w zakładce „Wiadomości”. Pokaż wiadomości - Pokaż kod QR klucza prywatnego Prośba o zalogowanie została odrzucona Upewnij się, że aplikacja logującego autoryzuje tę operację Sygnatariusz zewnętrzny zwrócił dane, które są niezgodne z żądaniem. Być może wystąpił błąd w Amethyst lub w samym sygnatariuszu. diff --git a/commonsUI/src/commonMain/composeResources/values-pt-rBR/strings.xml b/commonsUI/src/commonMain/composeResources/values-pt-rBR/strings.xml index a469cfbf88..7fa393e1b3 100644 --- a/commonsUI/src/commonMain/composeResources/values-pt-rBR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-pt-rBR/strings.xml @@ -545,7 +545,6 @@ Relés Site Endereço Lightning - Copiar a chave Nsec (sua senha) para backup Enviar uma mensagem direta Muda os dados do usuário Desbloquear @@ -654,14 +653,11 @@ Marcar todos conhecidos como lidos Marcar todas novas solicitações como lidas Marcar todas como lidas - ## Dicas de Backup de Chave e Segurança \n\nSua conta é protegida por uma chave secreta. A chave é uma sequência longa de caracteres que começa com **nsec1**. Qualquer pessoa que tenha acesso a esta chave secreta pode postar e alterar sua identidade. \n\n- **Não** coloque sua chave secreta em nenhum site ou software que você não confie. \n- Os desenvolvedores da Amethyst **nunca** pedirão sua chave secreta. \n- **Mantenha** uma cópia de segurança segura de sua chave secreta para recuperação da conta. Recomendamos o uso de um gerenciador de senhas. - Para segurança adicional, você pode criptografar sua chave com uma senha. Esta chave começa com **ncryptsec1** e não pode ser usada sem sua senha. \n\nSe você perder sua senha, não será possível recuperar sua chave. Faça backup das suas chaves Sua chave secreta é a única forma de acessar esta conta. Se você perdê-la, ela nunca poderá ser recuperada. Guarde-a em um lugar seguro agora. Fazer backup agora Já salvei Dispensar - Criptografar e copiar minha chave secreta Imagem da medalha para %1$s Imagem do prêmio Você recebeu uma nova medalha @@ -3577,7 +3573,6 @@ Texto copiado Copiado para a área de transferência Copiado @npub do autor - Copiar minha chave secreta Copiar para a Área de Transferência Não foi possível montar o LNUrl a partir do Endereço Lightning "%1$s". Verifique a configuração do usuário Não foi possível verificar o arquivo baixado após o upload: %1$s @@ -5040,10 +5035,8 @@ Upload HLS Compartilhar ou Salvar Curtas - Mostrar o código QR da chave privada criptografado Inclui mensagens diretas e de grupo na aba Notificações. Desative para manter as mensagens apenas na aba Mensagens. Mostrar mensagens - Mostrar código QR de chave privada Solicitação de assinatura rejeitada Certifique-se de que a aplicação assinante autorizou esta transação O assinador externo retornou dados estranhos para a solicitação. Pode haver um bug no Amethyst ou no assinador. diff --git a/commonsUI/src/commonMain/composeResources/values-pt-rPT/strings.xml b/commonsUI/src/commonMain/composeResources/values-pt-rPT/strings.xml index 6df337c8f7..5225a9ebf9 100644 --- a/commonsUI/src/commonMain/composeResources/values-pt-rPT/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-pt-rPT/strings.xml @@ -216,7 +216,6 @@ Relés Site Endereço Lightning - Copiar a chave Nsec (sua senha) para backup Enviar uma mensagem direta Muda os dados do usuário Desbloquear @@ -271,9 +270,6 @@ Marcar todos conhecidos como lidos Marcar todas novas solicitações como lidas Marcar todas como lidas - ## Dicas de Backup de Chave e Segurança \n\nSua conta é protegida por uma chave secreta. A chave é uma sequência longa de caracteres que começa com **nsec1**. Qualquer pessoa que tenha acesso a esta chave secreta pode postar e alterar sua identidade. \n\n- **Não** coloque sua chave secreta em nenhum site ou software que você não confie. \n- Os desenvolvedores da Amethyst **nunca** pedirão sua chave secreta. \n- **Mantenha** uma cópia de segurança segura de sua chave secreta para recuperação da conta. Recomendamos o uso de um gerenciador de senhas. - Para segurança adicional, você pode criptografar sua chave com uma senha. Esta chave começa com **ncryptsec1** e não pode ser usada sem sua senha. \n\nSe você perder sua senha, não será possível recuperar sua chave. - Criptografar e copiar minha chave secreta Imagem da medalha para %1$s Imagem do prêmio Você recebeu uma nova medalha @@ -1988,7 +1984,6 @@ Texto copiado Copiado para a área de transferência Copiado @npub do autor - Copiar minha chave secreta Copiar para a Área de Transferência Não foi possível montar o LNUrl a partir do Endereço Lightning "%1$s". Verifique a configuração do usuário Não foi possível verificar o arquivo baixado após o upload: %1$s @@ -2775,10 +2770,8 @@ Upload HLS Compartilhar ou Salvar Curtas - Mostrar o código QR da chave privada criptografado Inclui mensagens diretas e de grupo na aba Notificações. Desative para manter as mensagens apenas na aba Mensagens. Mostrar mensagens - Mostrar código QR de chave privada Solicitação de assinatura rejeitada Certifique-se de que a aplicação assinante autorizou esta transação O assinador externo retornou dados estranhos para a solicitação. Pode haver um bug no Amethyst ou no assinador. diff --git a/commonsUI/src/commonMain/composeResources/values-ru-rRU/strings.xml b/commonsUI/src/commonMain/composeResources/values-ru-rRU/strings.xml index 2d9214c475..85e7e02487 100644 --- a/commonsUI/src/commonMain/composeResources/values-ru-rRU/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ru-rRU/strings.xml @@ -219,7 +219,6 @@ Релеев Сайт Lightning адрес - Копирует Nsec ID (ваш пароль) для резервного копирования Отправить сообщение Редактирует метаданные пользователя Разблокировать @@ -274,9 +273,6 @@ Отметить все известные прочитанными Отметить все новые прочитанными Отметить всё прочитанным - ## Советы по резервному копированию и безопасности ключей \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей. - Для дополнительной безопасности вы можете зашифровать ваш ключ с помощью пароля. Этот ключ начинается с **ncryptsec1** и не может быть использован без пароля. \n\nЕсли вы потеряете свой пароль, вы не сможете восстановить ваш ключ. - Зашифровать и копировать мой секретный ключ Картинка значка-награды %1$s Изображение награды за значок Вы получили в награду новый значок @@ -2029,7 +2025,6 @@ Копировать текст Скопировано в буфер обмена ID (npub) автора скопирован - Скопировать мой приватный ключ Копировать в буфер обмена Не удалось собрать LNUrl из Lightning Address «%1$s». Проверьте настройки пользователя Не удалось проверить загруженный файл после выгрузки: %1$s @@ -2858,10 +2853,8 @@ Поделиться URL изображения Загрузка HLS Поделиться или сохранить - Показать зашифрованный QR-код приватного ключа Включить личные и групповые сообщения во вкладку «Уведомления». Отключите, чтобы сообщения отображались только во вкладке «Сообщения». Показывать сообщения - Показать QR-код приватного ключа Запрос на подпись отклонён Убедитесь, что приложение подписи авторизовало эту транзакцию Внешний подписант вернул неожиданный ответ на запрос. Возможно, ошибка в Amethyst или в приложении подписи. diff --git a/commonsUI/src/commonMain/composeResources/values-ru-rUA/strings.xml b/commonsUI/src/commonMain/composeResources/values-ru-rUA/strings.xml index 4656ddd56e..a9cb955bbe 100644 --- a/commonsUI/src/commonMain/composeResources/values-ru-rUA/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ru-rUA/strings.xml @@ -212,7 +212,6 @@ Жалобы %1$s жалоб Веб-сайт - Копирует Nsec ID (ваш пароль) в буфер обмена для резервного копирования Отправить личное сообщение Редактирует метаданные пользователя Разблокировать @@ -267,9 +266,6 @@ Отметить все известные как прочитанные Отметить все новые как прочитанные Отметить все как прочитанные - ## Советы по резервному копированию и безопасности ключей \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей. - Для дополнительной безопасности вы можете зашифровать ваш ключ паролем. Этот ключ начинается с **ncryptsec1** и не может быть использован без вашего пароля. \n\nЕсли вы потеряете пароль, вы не сможете восстановить ключ. - Зашифровать и скопировать мой секретный ключ Изображение награды для %1$s Изображение награды за значок Вы получили новую награду @@ -2015,7 +2011,6 @@ Текст записи скопирован в буфер обмена Скопировано в буфер обмена @npub автора скопирован в буфер обмена - Скопировать мой секретный ключ Скопировать в буфер обмена Не удалось собрать LNUrl из Lightning Address «%1$s». Проверьте настройки пользователя Не удалось проверить загруженный файл после выгрузки: %1$s @@ -2840,10 +2835,8 @@ Поделиться URL изображения Загрузка HLS Поделиться или сохранить - Показать QR-код зашифрованного приватного ключа Включить личные и групповые сообщения во вкладку «Уведомления». Отключите, чтобы сообщения отображались только во вкладке «Сообщения». Показывать сообщения - Показать QR-код приватного ключа Запрос на подпись отклонён Убедитесь, что приложение подписи авторизовало эту транзакцию Внешний подписант вернул неожиданный ответ на запрос. Возможно, ошибка в Amethyst или в приложении подписи. diff --git a/commonsUI/src/commonMain/composeResources/values-ru/strings.xml b/commonsUI/src/commonMain/composeResources/values-ru/strings.xml index 9ceaec1f2a..be13796940 100644 --- a/commonsUI/src/commonMain/composeResources/values-ru/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ru/strings.xml @@ -208,7 +208,6 @@ Релеев Сайт Lightning адрес - Копирует Nsec ID (ваш пароль) для резервного копирования Отправить сообщение Редактирует метаданные пользователя Разблокировать @@ -263,9 +262,6 @@ Отметить все известные прочитанными Отметить все новые прочитанными Отметить всё прочитанным - ## Советы по резервному копированию и безопасности ключей \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей. - Для дополнительной безопасности вы можете зашифровать ваш ключ паролем. Этот ключ начинается с **ncryptsec1** и не может быть использован без вашего пароля. \n\nЕсли вы потеряете пароль, вы не сможете восстановить ваш ключ. - Зашифровать и скопировать секретный ключ Картинка значка-награды %1$s Изображение награды за значок Вы получили в награду новый значок @@ -2058,7 +2054,6 @@ Копировать текст Скопировано в буфер обмена ID (npub) автора скопирован - Скопировать мой приватный ключ Копировать в буфер обмена Не удалось собрать LNUrl из Lightning Address «%1$s». Проверьте настройки пользователя Не удалось проверить загруженный файл после выгрузки: %1$s @@ -2935,10 +2930,8 @@ Загрузка HLS Поделиться или сохранить Shorts - Показать QR-код зашифрованного приватного ключа Включить личные и групповые сообщения во вкладку «Уведомления». Отключите, чтобы сообщения отображались только во вкладке «Сообщения». Показывать сообщения - Показать QR-код приватного ключа Запрос на подпись отклонён Убедитесь, что приложение подписи авторизовало эту транзакцию Внешний подписант вернул неожиданный ответ на запрос. Возможно, ошибка в Amethyst или в приложении подписи. diff --git a/commonsUI/src/commonMain/composeResources/values-sl-rSI/strings.xml b/commonsUI/src/commonMain/composeResources/values-sl-rSI/strings.xml index 94bd73c074..9f7b4ef715 100644 --- a/commonsUI/src/commonMain/composeResources/values-sl-rSI/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-sl-rSI/strings.xml @@ -363,7 +363,6 @@ Releji Spletna stran Lightning naslov - Kopira Nsec ID (tvoje geslo) v odložišče za varnostno kopiranje Pošlji direktno sporočilo Uredi uporabnikove metapodatke Deblokiraj @@ -472,14 +471,11 @@ Označi vse znane kot prebrane Označi vse nove kot prebrane Označi vse kot prebrane - ## Varnostna kopija ključev in varnostni nasveti \n\nVaš račun je zaščiten z privatnim ključem. Ta ključ ima dolgo sekvenco znakov kateri se začnejo z **nsec1**. Kdorkoli ima dostop, do tega privatnega ključa, lahko pošiljajo zapiske in spremenijo vašo digitalno identiteto. \n\n- Nikoli in **Nikdar** ne vpisuj svojega privatnega ključa v spletne strani in aplikacije katerim ne zaupaš. \n- Amethyst ustvarjalci vas ne bojo **nikoli** vprašali po vašem privatnem ključu. \n- Ustvari **varnostno kopijo** svojega privatnega ključa, za obnovitev računa. Priporoča se uporaba upravljalnika gesel. - Za dodatno varnost, lahko šifriraš svoj ključ z dodatnim geslom. Ta ključ se začne z **ncryptsec1** in ne more bit uporabljen brez dodatnega gesla. \n\nČe izgubiš geslo, obnova ključa ni več mogoča. Varno shrani ključe Vaš zasebni ključ je edini način za dostop do tega računa. Če ga izgubite, ga ne boste mogli več obnoviti. Shranite ga na varno mesto. Varno shrani zdaj shranjeno Opusti - Šifriraj in kopiraj moj privatni ključ Slika nagradne značke za %1$s "Slika nagradne značke Prejel/a si novo nagradno značko @@ -3316,7 +3312,6 @@ Tekst zapiska kopiran v odložišče Kopirano v odložišče Avtorjev @npub kopiran v odložišče - Kopiraj moj privatni ključ Kopiraj v odložišče Ni bilo mogoče sestaviti LNUrl iz "lightning" naslova '%1$s'. Preverite uporabnikove nastavitve Ni bilo mogoče preveriti prenesene datoteke po nalaganju: %1$s @@ -4844,10 +4839,8 @@ Naloži HLS Deli ali shrani Kratki posnetki - Pokaži QR kodo šifriranega zasebnega ključa V zavihek Obvestila vključite neposredna in skupinska sporočila. Izklopite, če želite sporočila ohraniti samo v zavihku Sporočila. Prikaži sporočilo - Pokaži QR kodo zasebnega ključa Zahteva za vpis zavrnjena Prepričajte se, da je aplikacija za podpisovanje odobrila to transakcijo Zunanji podpisnik je vrnil neobičajen odgovor. Morda gre za napako v aplikaciji Amethyst ali v podpisniku. diff --git a/commonsUI/src/commonMain/composeResources/values-sr-rSP/strings.xml b/commonsUI/src/commonMain/composeResources/values-sr-rSP/strings.xml index 79291d0563..c7b1d4b59c 100644 --- a/commonsUI/src/commonMain/composeResources/values-sr-rSP/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-sr-rSP/strings.xml @@ -216,7 +216,6 @@ Relay-ovi Veb stranica Lightning adresa - Kopira Nsec ID (vaša lozinka) u međuspremnik radi rezervne kopije Pošalji direktnu poruku Izmeni metapodatke korisnika Odblokiraj @@ -271,9 +270,6 @@ Označi sve poznate kao pročitano Označi sve novo kao pročitano Označi sve kao pročitano - ## Saveti za bekap ključa i bezbednost \n\nVaš nalog je zaštićen tajnim ključem. Ključ je dugačak niz znakova koji počinje sa **nsec1**. Svako ko ima pristup ovom tajnom ključu može da objavljuje i menja vaš identitet. \n\n- **Ne** unosite vaš tajni ključ ni na jedan veb-sajt ili softver kojemu ne verujete. \n- Amethyst programeri **nikada** neće tražiti vaš tajni ključ. \n- **Čuvajte** bezbednu kopiju vašeg tajnog ključa radi oporavka naloga. Preporučujemo korišćenje menadžera lozinki. - Za dodatnu bezbednost, možete šifrovati vaš ključ lozinkom. Ovaj ključ počinje sa **ncryptsec1** i ne može se koristiti bez vaše lozinke. \n\nAko izgubite lozinku, nećete moći da obnovite ključ. - Šifruj i kopiraj moj tajni ključ Slika značke za %1$s "Slika značke Dobili ste novu značku @@ -1997,7 +1993,6 @@ Tekst beleške kopiran u clipboard Kopirano u privremenu memoriju @npub autora kopiran u clipboard - Kopiraj moj tajni ključ Kopiraj u privremenu memoriju Nije moguće sastaviti LNUrl iz Lightning adrese "%1$s". Proverite podešavanja korisnika Preuzeta datoteka se ne može proveriti nakon otpremanja: %1$s @@ -2820,10 +2815,8 @@ HLS otpremanje Podeli ili sačuvaj Kratki snimci - Prikaži QR kod šifrovanog privatnog ključa Uključi direktne i grupne poruke na kartici Obaveštenja. Isključite da poruke budu samo na kartici Poruke. Prikaži poruke - Prikaži QR kod privatnog ključa Zahtev za potpisivanje odbijen Proverite da li je aplikacija za potpisivanje odobrila ovu transakciju Spoljni potpisnik je vratio podatke koji su neočekivani za zahtev. Možda postoji greška u Amethyst-u ili aplikaciji za potpisivanje. diff --git a/commonsUI/src/commonMain/composeResources/values-sv-rSE/strings.xml b/commonsUI/src/commonMain/composeResources/values-sv-rSE/strings.xml index c63d123853..05544e3d76 100644 --- a/commonsUI/src/commonMain/composeResources/values-sv-rSE/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-sv-rSE/strings.xml @@ -545,7 +545,6 @@ Reläer Websida Lightning Adress - Kopierar Nsec ID (ditt lösenord) till urklipp för säkerhetskopiering Skicka ett direkt meddelande Redigerar användarens metadata Sluta blockera @@ -654,14 +653,11 @@ Markera alla kända som lästa Markera alla nya som lästa Markera allt som läst - ## Nyckelsäkerhetsråd \n\nDitt konto är säkrat med en hemlig nyckel. Nyckeln är en lång följd av tecken som börjar med **nsec1**. Den som har tillgång till denna hemliga nyckel kan posta och ändra din identitet. \n\n- **Lägg inte** din hemliga nyckel på någon webbplats eller i någon mjukvara som du inte litar på. \n- Utvecklarna av Amethyst kommer **aldrig** att be om din hemliga nyckel. \n- **Spara** en säkerhetskopia av din hemliga nyckel för återställning av kontot. Vi rekommenderar att du använder en lösenordshanterare. - För extra säkerhet kan du kryptera din nyckel med ett lösenord. Denna nyckel börjar med **ncryptsec1** och kan inte användas utan ditt lösenord. \n\nOm du tappar bort ditt lösenord kommer du inte att kunna återställa din nyckel. Säkerhetskopiera dina nycklar Din hemliga nyckel är enda sättet att komma åt det här kontot. Om du förlorar den kan den aldrig återskapas. Spara den på ett säkert ställe nu. Säkerhetskopiera nu Jag har sparat dem Avfärda - Kryptera och kopiera min hemliga nyckel Tilldelad Badge för %1$s Bild på utmärkelse Du har blivit tilldelad en ny Badge @@ -3577,7 +3573,6 @@ Kopierade anteckningstext till urklipp Kopierat till urklipp Kopierade författarens @npub till urklipp - Kopiera min hemliga nyckel Kopiera till Urklipp Kunde inte montera LNUrl från Lightning Address "%1$s". Kontrollera användarens konfiguration Kunde inte kontrollera nedladdad fil efter uppladdning: %1$s @@ -5040,10 +5035,8 @@ HLS-uppladdning Dela eller Spara Kortfilmer - Visa QR-kod för krypterad privat nyckel Inkludera direktmeddelanden och gruppmeddelanden på fliken Aviseringar. Stäng av för att hålla meddelanden enbart på fliken Meddelanden. Visa meddelanden - Visa QR-kod för privat nyckel Signeringsförfrågan avvisad Kontrollera att signeringsprogrammet har godkänt denna transaktion Extern signatär returnerade data som är ovanliga för begäran. Det kan finnas en bugg i antingen Amethyst eller signatären. diff --git a/commonsUI/src/commonMain/composeResources/values-sw/strings.xml b/commonsUI/src/commonMain/composeResources/values-sw/strings.xml index a5f776dbef..286d845f7c 100644 --- a/commonsUI/src/commonMain/composeResources/values-sw/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-sw/strings.xml @@ -213,7 +213,6 @@ %1$s Ripoti Tovuti Anwani ya Umeme - Hunakili Kitambulisho cha Nsec (nywila yako) kwenye ubao wa kunakili kwa ajili ya nakala rudufu Tuma Ujumbe wa Moja kwa Moja Huhariri Metadata ya Mtumiaji Fungua @@ -268,9 +267,6 @@ Funga kama Zimejulikana Funga kama Mpya Funga kama Zimejulikana - ## Vidokezo vya Nakala Rudufu ya Ufunguo na Usalama \n\nAkaunti yako inalindwa na ufunguo wa siri. Ufunguo ni mfululizo mrefu wa herufi unaoanza na **nsec1**. Mtu yeyote anayepata ufunguo huu wa siri anaweza kuchapisha na kubadilisha utambulisho wako. \n\n- **Usiweke** ufunguo wako wa siri katika tovuti yoyote au programu unayoitembelewa. \n- Watengenezaji wa Amethyst **hawatawahi** kuomba ufunguo wako wa siri. \n- **Hifadhi** nakala salama ya ufunguo wako wa siri kwa ajili ya kurejesha akaunti. Tunapendekeza kutumia kidhibiti cha nenosiri. - Kwa usalama zaidi, unaweza kusimba ufunguo wako kwa nenosiri. Ufunguo huu unaanza na **ncryptsec1** na hauwezi kutumika bila nenosiri lako. \n\nUkipoteza nenosiri lako, hutaweza kurejesha ufunguo wako. - Simba na nakili ufunguo wangu wa siri Picha ya tuzo ya alama kwa %1$s "Picha ya tuzo ya beji Umepokea Tuzo Mpya ya Alama @@ -1999,7 +1995,6 @@ Maudhui ya dokezo yamenakiliwa kwenye ubao wa kunakili Imenakiliwa kwenye ubao wa kunakili Imesakinishwa @npub ya mwandishi kwa ubao wa kunakili - Nakili Ufunguo Wangu wa Siri Nakili kwenye ubao wa kunakili Haikuweza kuunda LNUrl kutoka kwa Anwani ya Lightning "%1$s". Angalia mpangilio wa mtumiaji Haikuweza kukagua faili lililопakuliwa baada ya kupakia: %1$s @@ -2795,10 +2790,8 @@ Pakia HLS Shiriki au Hifadhi Mafupi - Onyesha msimbo wa QR wa ufunguo wa siri uliofichwa Jumuisha ujumbe wa moja kwa moja na wa kikundi kwenye kichupo cha Arifa. Zima ili kuweka ujumbe kwenye kichupo cha Ujumbe pekee. Onyesha Ujumbe - Onyesha msimbo wa QR wa ufunguo wa siri Ombi la kusaini limekataliwa Hakikisha programu ya kusaini imeidhinisha muamala huu Msimamizi wa nje alirejesha data ya ajabu kwa ombi hili. Huenda kuna hitilafu katika Amethyst au Msimamizi. diff --git a/commonsUI/src/commonMain/composeResources/values-ta-rIN/strings.xml b/commonsUI/src/commonMain/composeResources/values-ta-rIN/strings.xml index 4b61e32475..1118006456 100644 --- a/commonsUI/src/commonMain/composeResources/values-ta-rIN/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ta-rIN/strings.xml @@ -217,7 +217,6 @@ ரிலேகள் இணையதளம் லைட்னிங் முகவரி - Nsec IDயை (உங்கள் கடவுச்சொல்) காப்புப்பிரதிக்காக கிளிப்போர்டுக்கு நகலெடுக்கிறது நேரடிச் செய்தியை அனுப்பு பயனரின் தகவலை திருத்துகிறது தடையை நீக்கு @@ -272,9 +271,6 @@ தெரிந்தவற்றைப் படித்ததாகக் குறி புதியனவற்றைப் படித்ததாகக் குறி அனைத்தையும் படித்ததாகக் குறி - ## திறவுகோல் காப்புப்பிரதி மற்றும் பாதுகாப்பு குறிப்புகள் \n\nஉங்கள் கணக்கு ஒரு இரகசிய திறவுகோலால் பாதுகாக்கப்படுகிறது. இந்த திறவுகோல் **nsec1** என்று தொடங்கும் நீண்ட எழுத்துத் தொடராகும். இந்த இரகசிய திறவுகோலை யாராவது பெற்றால் அவர்கள் உங்கள் அடையாளத்தை பயன்படுத்தி இடுகையிடலாம் மற்றும் மாற்றலாம். \n\n- உங்கள் இரகசிய திறவுகோலை நீங்கள் நம்பாத எந்த வலைத்தளத்திலும் அல்லது மென்பொருளிலும் வைக்க **வேண்டாம்**. \n- Amethyst டெவலப்பர்கள் உங்கள் இரகசிய திறவுகோலை **ஒருபோதும்** கேட்கமாட்டார்கள். \n- கணக்கு மீட்டெடுப்புக்காக உங்கள் இரகசிய திறவுகோலை பாதுகாப்பாக காப்புப்பிரதி எடுங்கள். கடவுச்சொல் மேலாளரை பயன்படுத்த பரிந்துரைக்கிறோம். - கூடுதல் பாதுகாப்புக்காக, உங்கள் திறவுகோலை கடவுச்சொல்லால் குறியாக்கலாம். இந்த திறவுகோல் **ncryptsec1** என்று தொடங்கும் மற்றும் உங்கள் கடவுச்சொல்லின்றி பயன்படுத்த முடியாது. \n\nகடவுச்சொல்லை மறந்தால், உங்கள் திறவுகோலை மீட்டெடுக்க முடியாது. - என் இரகசிய விசையை மறைகுறியாக்கி நகல் எடுக்கவும் %1$s க்கான பேட்ஜ் விருது படம் "பேட்ஜ் விருது படம் நீங்கள் ஒரு புதிய பேட்ஜ் விருதைப் பெற்றீர்கள் @@ -1999,7 +1995,6 @@ குறிப்பு கிளிப்போர்டுக்கு நகலெடுக்கப் பட்டது கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது கிளிப்போர்டுக்கு எழுத்தாளரின் @npub நகலெடுக்கப் பட்டது - எனது ரகசிய சாவியை நகலெடுக்கவும் கிளிப்போர்டுக்கு நகலெடு Lightning முகவரி "%1$s" இலிருந்து LNUrl ஐ உருவாக்க முடியவில்லை. பயனரின் அமைப்பை சரிபார்க்கவும் பதிவேற்றத்திற்குப் பிறகு பதிவிறக்கிய கோப்பை சரிபார்க்க முடியவில்லை: %1$s @@ -2784,10 +2779,8 @@ HLS பதிவேற்றம் பகிர் அல்லது சேமி குறுவீடியோக்கள் - மறைகுறியாக்கப்பட்ட தனிப்பட்ட விசை QR குறியீட்டை காட்டு அறிவிப்பு தாவலில் நேரடி மற்றும் குழு செய்திகளை சேர்க்கவும். செய்திகளை செய்திகள் தாவலில் மட்டும் வைக்க அணைக்கவும். செய்திகளை காட்டு - தனிப்பட்ட விசை QR குறியீட்டை காட்டு கையொப்பமிடல் கோரிக்கை நிராகரிக்கப்பட்டது கையொப்பமிடல் செயலி இந்த பரிவர்த்தனையை அங்கீகரித்திருக்கிறதா என சரிபார்க்கவும் வெளிப்புற கையெழுத்திட்டவர் கோரிக்கைக்கு அசாதாரணமான தரவை திரும்ப அனுப்பியது. Amethyst அல்லது கையெழுத்திட்டவரில் ஒரு பிழை இருக்கலாம். diff --git a/commonsUI/src/commonMain/composeResources/values-ta/strings.xml b/commonsUI/src/commonMain/composeResources/values-ta/strings.xml index 210f73485f..0c9046b656 100644 --- a/commonsUI/src/commonMain/composeResources/values-ta/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ta/strings.xml @@ -204,7 +204,6 @@ ரிலேகள் இணையதளம் லைட்னிங் முகவரி - Nsec IDயை (உங்கள் கடவுச்சொல்) காப்புப்பிரதிக்காக கிளிப்போர்டுக்கு நகலெடுக்கிறது நேரடிச் செய்தியை அனுப்பு பயனரின் தகவலை திருத்துகிறது தடையை நீக்கு @@ -259,9 +258,6 @@ தெரிந்தவற்றைப் படித்ததாகக் குறி புதியனவற்றைப் படித்ததாகக் குறி அனைத்தையும் படித்ததாகக் குறி - ## திறவுகோல் காப்புப்பிரதி மற்றும் பாதுகாப்பு குறிப்புகள் \n\nஉங்கள் கணக்கு ஒரு இரகசிய திறவுகோலால் பாதுகாக்கப்படுகிறது. இந்த திறவுகோல் **nsec1** என்று தொடங்கும் நீண்ட எழுத்துத் தொடராகும். இந்த இரகசிய திறவுகோலை யாராவது பெற்றால் அவர்கள் உங்கள் அடையாளத்தை பயன்படுத்தி இடுகையிடலாம் மற்றும் மாற்றலாம். \n\n- உங்கள் இரகசிய திறவுகோலை நீங்கள் நம்பாத எந்த வலைத்தளத்திலும் அல்லது மென்பொருளிலும் வைக்க **வேண்டாம்**. \n- Amethyst டெவலப்பர்கள் உங்கள் இரகசிய திறவுகோலை **ஒருபோதும்** கேட்கமாட்டார்கள். \n- கணக்கு மீட்டெடுப்புக்காக உங்கள் இரகசிய திறவுகோலை பாதுகாப்பாக காப்புப்பிரதி எடுங்கள். கடவுச்சொல் மேலாளரை பயன்படுத்த பரிந்துரைக்கிறோம். - கூடுதல் பாதுகாப்புக்காக, உங்கள் திறவுகோலை கடவுச்சொல்லால் குறியாக்கலாம். இந்த திறவுகோல் **ncryptsec1** என்று தொடங்கும் மற்றும் உங்கள் கடவுச்சொல்லின்றி பயன்படுத்த முடியாது. \n\nகடவுச்சொல்லை மறந்தால், உங்கள் திறவுகோலை மீட்டெடுக்க முடியாது. - என் இரகசிய விசையை மறைகுறியாக்கி நகல் எடுக்கவும் %1$s க்கான பேட்ஜ் விருது படம் "பேட்ஜ் விருது படம் நீங்கள் ஒரு புதிய பேட்ஜ் விருதைப் பெற்றீர்கள் @@ -2038,7 +2034,6 @@ குறிப்பு கிளிப்போர்டுக்கு நகலெடுக்கப் பட்டது கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது கிளிப்போர்டுக்கு எழுத்தாளரின் @npub நகலெடுக்கப் பட்டது - எனது ரகசிய சாவியை நகலெடுக்கவும் கிளிப்போர்டுக்கு நகலெடு Lightning முகவரி "%1$s" இலிருந்து LNUrl ஐ உருவாக்க முடியவில்லை. பயனரின் அமைப்பை சரிபார்க்கவும் பதிவேற்றத்திற்குப் பிறகு பதிவிறக்கிய கோப்பை சரிபார்க்க முடியவில்லை: %1$s @@ -2863,10 +2858,8 @@ HLS பதிவேற்றம் பகிர் அல்லது சேமி குறுவீடியோக்கள் - மறைகுறியாக்கப்பட்ட தனிப்பட்ட விசை QR குறியீட்டை காட்டு அறிவிப்பு தாவலில் நேரடி மற்றும் குழு செய்திகளை சேர்க்கவும். செய்திகளை செய்திகள் தாவலில் மட்டும் வைக்க அணைக்கவும். செய்திகளை காட்டு - தனிப்பட்ட விசை QR குறியீட்டை காட்டு கையொப்பமிடல் கோரிக்கை நிராகரிக்கப்பட்டது கையொப்பமிடல் செயலி இந்த பரிவர்த்தனையை அங்கீகரித்திருக்கிறதா என சரிபார்க்கவும் வெளிப்புற கையெழுத்திட்டவர் கோரிக்கைக்கு அசாதாரணமான தரவை திரும்ப அனுப்பியது. Amethyst அல்லது கையெழுத்திட்டவரில் ஒரு பிழை இருக்கலாம். diff --git a/commonsUI/src/commonMain/composeResources/values-th-rTH/strings.xml b/commonsUI/src/commonMain/composeResources/values-th-rTH/strings.xml index fccf86948f..cf2b33f695 100644 --- a/commonsUI/src/commonMain/composeResources/values-th-rTH/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-th-rTH/strings.xml @@ -215,7 +215,6 @@ รีเลย์ เว็บไซต์ ไม่ได้ตั้งค่า Lightning Address - คัดลอก Nsec ID (รหัสผ่านของคุณ) ลงคลิปบอร์ดเพื่อสำรองข้อมูล ส่งข้อความส่วนตัว แก้ไข the User's Metadata เลิกบล๊อก @@ -269,9 +268,6 @@ ทำเครื่องหมายอ่านแล้วในแชทที่รู้จักทั้งหมด ทำเครื่องหมายว่าอ่านแล้วทั้งหมดสำหรับข้อความใหม่ ทพเครื่องหมายว่าอ่านแล้วทั้งหมด - ## เคล็ดลับการสำรองข้อมูลและความปลอดภัยที่สำคัญ \n\nบัญชีของคุณได้รับการรักษาความปลอดภัยด้วยคีย์ลับ คีย์เป็นรหัสชุดตัวอักษรยาวขึ้นต้นด้วย **nsec1** ใครก็ตามที่สามารถเข้าถึงรหัสชุดนี้ได้ จะสามารถโพสต์และเปลี่ยนแปลงข้อมูลประจำตัวของคุณได้ \n\n- **ห้าม** ใส่รหัสชุดนี้ในเว็บไซต์หรือซอฟต์แวร์ที่คุณไม่ไว้ใจ \n- ทีมพัฒนา Amethyst **จะไม่มีวัน** ขอรหัสชุดนี้ของคุณ \n- **ควร** สำรองข้อมูลรหัสชุดนี้ไว้เพื่อกู้คืนบัญชีของคุณ เราแนะนำให้ใช้โปรแกรมจัดการรหัสผ่าน - สำหรับการรักษาความปลอดภัยเพิ่มเติม คุณสามารถเข้ารหัสคีย์ของคุณด้วยรหัสผ่าน คีย์นี้ขึ้นต้นด้วย **ncryptsec1** และไม่สามารถใช้งานได้หากไม่มีรหัสผ่านของคุณ \n\n**แต่** หากคุณสูญหายรหัสผ่าน คุณจะไม่สามารถกู้คืนคีย์ของคุณได้ - เข้ารหัสและคัดลอกคีย์ความปลอดภัยของฉัน ภาพเหรียญตราสําหรับ %1$s "รูปภาพรางวัลป้าย คุณได้รับเหรียญตราใหม่ @@ -1972,7 +1968,6 @@ คัดลอกข่้อความในโน้ตลงคลิปบอร์ด คัดลอกไปยังคลิปบอร์ดแล้ว คัดลอก @npub ของผู้เขียนลงคลิปบอร์ด - คัดลอก secret key ของฉัน คัดลอก ไม่สามารถสร้าง LNUrl จากที่อยู่ Lightning ได้ "%1$s" โปรดตรวจสอบการตั้งค่า ไม่สามารถตรวจสอบไฟล์ที่ดาวน์โหลดหลังจากอัปโหลด: %1$s @@ -2624,10 +2619,8 @@ แชร์เป็น URL รูปภาพ อัปโหลด HLS แชร์ หรือเก็บไว้ - แสดง QR code คีย์ส่วนตัวแบบเข้ารหัส รวมข้อความส่วนตัวและกลุ่มในแท็บการแจ้งเตือน ปิดเพื่อเก็บข้อความไว้เฉพาะในแท็บข้อความ แสดงข้อความ - แสดง QR code คีย์ส่วนตัว คำขอลงชื่อถูกปฏิเสธ โปรดตรวจสอบให้แน่ใจว่าแอพเข้ารหัส หรือ Signer ได้อนุญาติทำรายการนี้ ผู้ลงนามภายนอกส่งคืนข้อมูลที่ผิดปกติสำหรับคำขอนี้ อาจมีข้อผิดพลาดใน Amethyst หรือแอปผู้ลงนาม diff --git a/commonsUI/src/commonMain/composeResources/values-th/strings.xml b/commonsUI/src/commonMain/composeResources/values-th/strings.xml index a4d606f00b..869f2c34ae 100644 --- a/commonsUI/src/commonMain/composeResources/values-th/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-th/strings.xml @@ -202,7 +202,6 @@ รีเลย์ เว็บไซต์ ไม่ได้ตั้งค่า Lightning Address - คัดลอก Nsec ID (รหัสผ่านของคุณ) ลงคลิปบอร์ดเพื่อสำรองข้อมูล ส่งข้อความส่วนตัว แก้ไข the User's Metadata เลิกบล๊อก @@ -257,9 +256,6 @@ ทำเครื่องหมายอ่านแล้วในแชทที่รู้จักทั้งหมด ทำเครื่องหมายว่าอ่านแล้วทั้งหมดสำหรับข้อความใหม่ ทพเครื่องหมายว่าอ่านแล้วทั้งหมด - ## เคล็ดลับการสำรองข้อมูลและความปลอดภัยที่สำคัญ \n\nบัญชีของคุณได้รับการรักษาความปลอดภัยด้วยคีย์ลับ คีย์เป็นรหัสชุดตัวอักษรยาวขึ้นต้นด้วย **nsec1** ใครก็ตามที่สามารถเข้าถึงรหัสชุดนี้ได้ จะสามารถโพสต์และเปลี่ยนแปลงข้อมูลประจำตัวของคุณได้ \n\n- **ห้าม** ใส่รหัสชุดนี้ในเว็บไซต์หรือซอฟต์แวร์ที่คุณไม่ไว้ใจ \n- ทีมพัฒนา Amethyst **จะไม่มีวัน** ขอรหัสชุดนี้ของคุณ \n- **ควร** สำรองข้อมูลรหัสชุดนี้ไว้เพื่อกู้คืนบัญชีของคุณ เราแนะนำให้ใช้โปรแกรมจัดการรหัสผ่าน - สำหรับการรักษาความปลอดภัยเพิ่มเติม คุณสามารถเข้ารหัสคีย์ของคุณด้วยรหัสผ่าน คีย์นี้ขึ้นต้นด้วย **ncryptsec1** และไม่สามารถใช้งานได้หากไม่มีรหัสผ่านของคุณ \n\n**แต่** หากคุณสูญหายรหัสผ่าน คุณจะไม่สามารถกู้คืนคีย์ของคุณได้ - เข้ารหัสและคัดลอกคีย์ความปลอดภัยของฉัน ภาพเหรียญตราสําหรับ %1$s "รูปภาพรางวัลป้าย คุณได้รับเหรียญตราใหม่ @@ -2028,7 +2024,6 @@ คัดลอกข่้อความในโน้ตลงคลิปบอร์ด คัดลอกไปยังคลิปบอร์ดแล้ว คัดลอก @npub ของผู้เขียนลงคลิปบอร์ด - คัดลอก secret key ของฉัน คัดลอก ไม่สามารถสร้าง LNUrl จากที่อยู่ Lightning ได้ "%1$s" โปรดตรวจสอบการตั้งค่า ไม่สามารถตรวจสอบไฟล์ที่ดาวน์โหลดหลังจากอัปโหลด: %1$s @@ -2827,10 +2822,8 @@ อัปโหลด HLS แชร์ หรือเก็บไว้ Shorts - แสดง QR code คีย์ส่วนตัวแบบเข้ารหัส รวมข้อความส่วนตัวและกลุ่มในแท็บการแจ้งเตือน ปิดเพื่อเก็บข้อความไว้เฉพาะในแท็บข้อความ แสดงข้อความ - แสดง QR code คีย์ส่วนตัว คำขอลงชื่อถูกปฏิเสธ โปรดตรวจสอบให้แน่ใจว่าแอพเข้ารหัส หรือ Signer ได้อนุญาติทำรายการนี้ ผู้ลงนามภายนอกส่งคืนข้อมูลที่ผิดปกติสำหรับคำขอนี้ อาจมีข้อผิดพลาดใน Amethyst หรือแอปผู้ลงนาม diff --git a/commonsUI/src/commonMain/composeResources/values-tr-rTR/strings.xml b/commonsUI/src/commonMain/composeResources/values-tr-rTR/strings.xml index f73a393d7d..885e0cedad 100644 --- a/commonsUI/src/commonMain/composeResources/values-tr-rTR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-tr-rTR/strings.xml @@ -217,7 +217,6 @@ Relaylar Web Sitesi Lİghtning Adresi - Yedekleme için Nsec ID'yi (sizin şifreniz) panoya kopyalar Direkt Mesaj Gönder Kullanıcının Üstverisini Düzenler Engelleme @@ -272,9 +271,6 @@ Tüm bilinenleri okundu olarak işaretle Tüm yenileri okundu olarak işaretle Tümünü okundu olarak işaretle - ## Anahtar Yedekleme ve Güvenlik İpuçları \n\nHesabınız bir gizli anahtarla korunmaktadır. Anahtar, **nsec1** ile başlayan uzun bir karakter dizisidir. Bu gizli anahtara erişimi olan herkes kimliğiniz adına gönderi yapabilir ve kimliğinizi değiştirebilir. \n\n- Gizli anahtarınızı güvenmediğiniz herhangi bir web sitesine veya yazılıma **koymayın**. \n- Amethyst geliştiricileri gizli anahtarınızı **asla** istemez. \n- Hesap kurtarma için gizli anahtarınızın güvenli bir yedeğini **alın**. Bir parola yöneticisi kullanmanızı öneririz. - Ek güvenlik için anahtarınızı bir parola ile şifreleyebilirsiniz. Bu anahtar **ncryptsec1** ile başlar ve parolanız olmadan kullanılamaz. \n\nParolanızı kaybederseniz anahtarınızı kurtaramazsınız. - Gizli anahtarımı şifrele ve kopyala %1$s için rozet ödülü görseli "Rozet ödülü görseli Yeni bir Rozet Ödülü aldınız @@ -2007,7 +2003,6 @@ Not metni panoya kopyalandı Panoya kopyalandı Yazarın @npub'ı panoya kopyalandı - Gizli anahtarımı kopyala Panoya kopyala "%1$s" Lightning Adresinden LNUrl oluşturulamadı. Kullanıcının kurulumunu kontrol edin Yükleme sonrası indirilen dosya kontrol edilemedi: %1$s @@ -2789,10 +2784,8 @@ HLS Yükle Paylaş veya Kaydet Kısa videolar - Şifreli özel anahtar QR kodunu göster Bildirim sekmesine doğrudan ve grup mesajlarını dahil et. Mesajları yalnızca Mesajlar sekmesinde tutmak için kapatın. Mesajları Göster - Özel anahtar QR kodunu göster İmza isteği reddedildi İmzalayıcı uygulamanın bu işlemi yetkilendirdiğinden emin olun Harici imzalayıcı, istek için beklenmedik bir yük döndürdü. Amethyst veya İmzalayıcıda bir hata olabilir. diff --git a/commonsUI/src/commonMain/composeResources/values-tr/strings.xml b/commonsUI/src/commonMain/composeResources/values-tr/strings.xml index 7716fa9b4b..234cc91ca6 100644 --- a/commonsUI/src/commonMain/composeResources/values-tr/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-tr/strings.xml @@ -204,7 +204,6 @@ Relaylar Web Sitesi Lİghtning Adresi - Yedekleme için Nsec ID'yi (sizin şifreniz) panoya kopyalar Direkt Mesaj Gönder Kullanıcının Üstverisini Düzenler Engelleme @@ -259,9 +258,6 @@ Tüm bilinenleri okundu olarak işaretle Tüm yenileri okundu olarak işaretle Tümünü okundu olarak işaretle - ## Anahtar Yedekleme ve Güvenlik İpuçları \n\nHesabınız bir gizli anahtarla korunmaktadır. Anahtar, **nsec1** ile başlayan uzun bir karakter dizisidir. Bu gizli anahtara erişimi olan herkes kimliğiniz adına gönderi yapabilir ve kimliğinizi değiştirebilir. \n\n- Gizli anahtarınızı güvenmediğiniz herhangi bir web sitesine veya yazılıma **koymayın**. \n- Amethyst geliştiricileri gizli anahtarınızı **asla** istemez. \n- Hesap kurtarma için gizli anahtarınızın güvenli bir yedeğini **alın**. Bir parola yöneticisi kullanmanızı öneririz. - Ek güvenlik için anahtarınızı bir parola ile şifreleyebilirsiniz. Bu anahtar **ncryptsec1** ile başlar ve parolanız olmadan kullanılamaz. \n\nParolanızı kaybederseniz anahtarınızı kurtaramazsınız. - Gizli anahtarımı şifrele ve kopyala %1$s için rozet ödülü görseli "Rozet ödülü görseli Yeni bir Rozet Ödülü aldınız @@ -2038,7 +2034,6 @@ Not metni panoya kopyalandı Panoya kopyalandı Yazarın @npub'ı panoya kopyalandı - Gizli anahtarımı kopyala Panoya kopyala "%1$s" Lightning Adresinden LNUrl oluşturulamadı. Kullanıcının kurulumunu kontrol edin Yükleme sonrası indirilen dosya kontrol edilemedi: %1$s @@ -2863,10 +2858,8 @@ HLS Yükle Paylaş veya Kaydet Kısa videolar - Şifreli özel anahtar QR kodunu göster Bildirim sekmesine doğrudan ve grup mesajlarını dahil et. Mesajları yalnızca Mesajlar sekmesinde tutmak için kapatın. Mesajları Göster - Özel anahtar QR kodunu göster İmza isteği reddedildi İmzalayıcı uygulamanın bu işlemi yetkilendirdiğinden emin olun Harici imzalayıcı, istek için beklenmedik bir yük döndürdü. Amethyst veya İmzalayıcıda bir hata olabilir. diff --git a/commonsUI/src/commonMain/composeResources/values-uk-rUA/strings.xml b/commonsUI/src/commonMain/composeResources/values-uk-rUA/strings.xml index 334b4cb8fd..cdb6fd0b15 100644 --- a/commonsUI/src/commonMain/composeResources/values-uk-rUA/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-uk-rUA/strings.xml @@ -218,7 +218,6 @@ Релеїв Сайт Lightning адреса - Копіює Nsec ID (ваш пароль) для резервного копіювання Відправити повідомлення Редагує метадані користувача Розблокувати @@ -273,9 +272,6 @@ Позначити всі відомі прочитаними Позначити всі нові прочитаними Позначити все прочитаним - ## Поради щодо резервного копіювання та безпеки ключа \n\nВаш обліковий запис захищений секретним ключем. Ключ — це довга послідовність символів, що починається з **nsec1**. Будь-хто, хто має доступ до цього секретного ключа, може публікувати та змінювати вашу особу. \n\n- **Не** вводьте свій секретний ключ на жодному сайті чи в програмі, якій ви не довіряєте. \n- Розробники Amethyst **ніколи** не запитуватимуть ваш секретний ключ. \n- **Зробіть** надійне резервне копіювання секретного ключа для відновлення облікового запису. Рекомендуємо використовувати менеджер паролів. - Для додаткової безпеки ви можете зашифрувати ключ паролем. Цей ключ починається з **ncryptsec1** і не може бути використаний без вашого пароля. \n\nЯкщо ви забудете пароль, ви не зможете відновити ключ. - Зашифрувати та скопіювати мій секретний ключ Картинка значка-нагороди %1$s "Зображення нагороди значком Ви отримали в нагороду новий значок @@ -2020,7 +2016,6 @@ Скопіювати текст Скопійовано до буфера обміну ID (npub) автора скопійовано - Скопіювати мій приватний ключ Скопіювати в буфер Не вдалося скласти LNUrl з Lightning адреси «%1$s». Перевірте налаштування користувача Не вдалося перевірити завантажений файл після вивантаження: %1$s @@ -2845,10 +2840,8 @@ Поділитися як зображення Поділитися як URL зображення Поділитися або зберегти - Показати QR-код зашифрованого приватного ключа Включати особисті та групові повідомлення на вкладку «Сповіщення». Вимкніть, щоб залишити повідомлення лише на вкладці «Повідомлення». Показувати повідомлення - Показати QR-код приватного ключа Запит на підписання відхилено Переконайтеся, що застосунок-підписант авторизував цю транзакцію Зовнішній підписувач повернув дані, що не відповідають запиту. Можливо, є помилка в Amethyst або підписувачі. diff --git a/commonsUI/src/commonMain/composeResources/values-uk/strings.xml b/commonsUI/src/commonMain/composeResources/values-uk/strings.xml index bc7b9935b3..7910decae3 100644 --- a/commonsUI/src/commonMain/composeResources/values-uk/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-uk/strings.xml @@ -208,7 +208,6 @@ Релеїв Сайт Lightning адреса - Копіює Nsec ID (ваш пароль) для резервного копіювання Відправити повідомлення Редагує метадані користувача Розблокувати @@ -263,9 +262,6 @@ Позначити всі відомі прочитаними Позначити всі нові прочитаними Позначити все прочитаним - ## Поради щодо резервного копіювання та безпеки ключа \n\nВаш обліковий запис захищений секретним ключем. Ключ — це довга послідовність символів, що починається з **nsec1**. Будь-хто, хто має доступ до цього секретного ключа, може публікувати та змінювати вашу особу. \n\n- **Не** вводьте свій секретний ключ на жодному сайті чи в програмі, якій ви не довіряєте. \n- Розробники Amethyst **ніколи** не запитуватимуть ваш секретний ключ. \n- **Зробіть** надійне резервне копіювання секретного ключа для відновлення облікового запису. Рекомендуємо використовувати менеджер паролів. - Для додаткової безпеки ви можете зашифрувати ключ паролем. Цей ключ починається з **ncryptsec1** і не може бути використаний без вашого пароля. \n\nЯкщо ви забудете пароль, ви не зможете відновити ключ. - Зашифрувати та скопіювати мій секретний ключ Картинка значка-нагороди %1$s "Зображення нагороди значком Ви отримали в нагороду новий значок @@ -2058,7 +2054,6 @@ Скопіювати текст Скопійовано до буфера обміну ID (npub) автора скопійовано - Скопіювати мій приватний ключ Скопіювати в буфер Не вдалося скласти LNUrl з Lightning адреси «%1$s». Перевірте налаштування користувача Не вдалося перевірити завантажений файл після вивантаження: %1$s @@ -2935,10 +2930,8 @@ HLS Upload Поділитися або зберегти Shorts - Показати QR-код зашифрованого приватного ключа Включати особисті та групові повідомлення на вкладку «Сповіщення». Вимкніть, щоб залишити повідомлення лише на вкладці «Повідомлення». Показувати повідомлення - Показати QR-код приватного ключа Запит на підписання відхилено Переконайтеся, що застосунок-підписант авторизував цю транзакцію Зовнішній підписувач повернув дані, що не відповідають запиту. Можливо, є помилка в Amethyst або підписувачі. diff --git a/commonsUI/src/commonMain/composeResources/values-uz-rUZ/strings.xml b/commonsUI/src/commonMain/composeResources/values-uz-rUZ/strings.xml index 1584c9d77e..349da89d24 100644 --- a/commonsUI/src/commonMain/composeResources/values-uz-rUZ/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-uz-rUZ/strings.xml @@ -218,7 +218,6 @@ Relay lar Veb-sayt Lightning manzili - Nsec ID (parolingiz) nusxasini zaxiralash uchun buferga nusxalaydi To'g'ridan-to'g'ri xabar yuborish Foydalanuvchi metama'lumotlarini tahrirlaydi Blokdan chiqarish @@ -273,9 +272,6 @@ Barcha ma'lumlarni o'qilgan deb belgilash Barcha yangilarni o'qilgan deb belgilash Barchasini o'qilgan deb belgilash - ## Kalit zaxiralash va xavfsizlik maslahatlari \n\nHisobingiz maxfiy kalit bilan himoyalangan. Kalit **nsec1** bilan boshlanadigan uzun belgilar ketma-ketligidir. Ushbu maxfiy kalitga kirish huquqiga ega bo'lgan har kim sizning nomingizdan post qo'yishi va identifikatoringizni o'zgartirishi mumkin. \n\n- Maxfiy kalitingizni ishonmagan veb-sayt yoki dasturga **kiritmang**. \n- Amethyst ishlab chiquvchilari maxfiy kalitingizni hech **qachon** so'ramaydi. \n- Hisob tiklash uchun maxfiy kalitingizning xavfsiz zaxira nusxasini saqlang. Parol menejeridan foydalanishni tavsiya qilamiz. - Qo'shimcha xavfsizlik uchun kalitingizni parol bilan shifrlashingiz mumkin. Bu kalit **ncryptsec1** bilan boshlanadi va parolsiz ishlatib bo'lmaydi. \n\nParolingizni unutsangiz, kalitingizni tiklay olmaysiz. - Maxfiy kalitni shifrlash va nusxalash %1$s uchun nishon mukofoti rasmi "Nishon mukofoti rasmi Siz yangi nishon mukofoti oldingiz @@ -1995,7 +1991,6 @@ Eslatma matni buferga nusxalandi Buferga nusxalandi Muallifning @npub manzili buferga nusxalandi - Mening maxfiy kalitimni nusxalash Buferga nusxalash Lightning manzilidan LNUrl yig'ib bo'lmadi "%1$s". Foydalanuvchi sozlamasini tekshiring Yuklashdan keyin yuklab olingan faylni tekshirib bo'lmadi: %1$s @@ -2798,10 +2793,8 @@ HLS yuklash Ulashish yoki saqlash Shortslar - Shifrlangan shaxsiy kalit QR kodini ko'rsatish Bildirishnoma yorlig'iga to'g'ridan-to'g'ri va guruh xabarlarini kiriting. Xabarlarni faqat Xabarlar yorlig'ida saqlash uchun o'chiring. Xabarlarni Ko'rsatish - Shaxsiy kalit QR kodini ko'rsatish Imzo so'rovi rad etildi Imzolash ilovasi ushbu tranzaksiyaga ruxsat berganligini tekshiring Tashqi imzolash dasturi so'rov uchun g'alati javob qaytardi. Amethyst yoki imzolash dasturida xato bo'lishi mumkin. diff --git a/commonsUI/src/commonMain/composeResources/values-vi-rVN/strings.xml b/commonsUI/src/commonMain/composeResources/values-vi-rVN/strings.xml index 9a29f36685..41d1564cbe 100644 --- a/commonsUI/src/commonMain/composeResources/values-vi-rVN/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-vi-rVN/strings.xml @@ -212,7 +212,6 @@ Relay Trang web Địa chỉ Lightning - Sao chép Nsec ID (mật khẩu của bạn) vào clipboard để sao lưu Gửi tin nhắn trực tiếp Chỉnh sửa siêu dữ liệu người dùng Bỏ chặn @@ -267,9 +266,6 @@ Đánh dấu tất cả đã biết là đã đọc Đánh dấu tất cả mới là đã đọc Đánh dấu tất cả là đã đọc - ## Mẹo sao lưu khóa và bảo mật \n\nTài khoản của bạn được bảo mật bằng một khóa bí mật. Khóa là một chuỗi ký tự dài bắt đầu bằng **nsec1**. Bất kỳ ai có quyền truy cập vào khóa bí mật này đều có thể đăng bài và thay đổi danh tính của bạn. \n\n- **Không** đưa khóa bí mật của bạn vào bất kỳ trang web hoặc phần mềm nào mà bạn không tin tưởng. \n- Các nhà phát triển Amethyst sẽ **không bao giờ** yêu cầu khóa bí mật của bạn. \n- **Hãy** giữ bản sao lưu an toàn của khóa bí mật để khôi phục tài khoản. Chúng tôi khuyến nghị sử dụng trình quản lý mật khẩu. - Để bảo mật thêm, bạn có thể mã hóa khóa của mình bằng mật khẩu. Khóa này bắt đầu bằng **ncryptsec1** và không thể sử dụng nếu không có mật khẩu của bạn. \n\nNếu bạn mất mật khẩu, bạn sẽ không thể khôi phục khóa của mình. - Mã hóa và sao chép khóa bí mật của tôi Hình ảnh huy hiệu được trao cho %1$s "Hình ảnh huy hiệu được trao Bạn đã nhận được huy hiệu mới @@ -1983,7 +1979,6 @@ Đã sao chép nội dung ghi chú vào clipboard Đã sao chép vào clipboard Đã sao chép @npub của tác giả vào clipboard - Sao chép khóa bí mật của tôi Sao chép vào clipboard Không thể tạo LNUrl từ Địa chỉ Lightning "%1$s". Hãy kiểm tra cài đặt của người dùng Không thể kiểm tra tệp đã tải xuống sau khi tải lên: %1$s @@ -2746,10 +2741,8 @@ Chia sẻ dưới dạng URL hình ảnh Tải lên HLS Chia sẻ hoặc Lưu - Hiển thị mã QR khóa riêng tư đã mã hóa Bao gồm tin nhắn trực tiếp và nhóm trên tab Thông báo. Tắt để chỉ giữ tin nhắn trong tab Tin nhắn. Hiển thị tin nhắn - Hiển thị mã QR khóa riêng tư Yêu cầu ký bị từ chối Hãy đảm bảo ứng dụng ký đã cho phép giao dịch này Trình ký bên ngoài trả về dữ liệu không hợp lệ cho yêu cầu. Có thể có lỗi trong Amethyst hoặc trong trình ký. diff --git a/commonsUI/src/commonMain/composeResources/values-zh-rCN/strings.xml b/commonsUI/src/commonMain/composeResources/values-zh-rCN/strings.xml index 993bad59a6..068f70ecd9 100644 --- a/commonsUI/src/commonMain/composeResources/values-zh-rCN/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-zh-rCN/strings.xml @@ -303,7 +303,6 @@ 中继 网站 闪电地址 - 复制 Nsec ID(您的私人密钥)到剪贴板以备备份 发送直接消息 编辑用户元数据 不隐藏 @@ -389,9 +388,6 @@ 将所有已知内容标记为已读 将所有新内容标记为已读 将所有内容标记为已读 - ## 备份与安全提示 \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 \n- Amethyst 开发人员**永远不会**要求你提供私钥。 \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 - 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 \n\n如果你丢失密码, 你将无法恢复你的密钥。 - 加密并复制我的密钥。 颁发给 %1$s 的徽章图片 "徽章图片 你收到了新的徽章奖励 @@ -2623,7 +2619,6 @@ 文本已复制到剪贴板 已复制到剪贴板 已复制作者公钥 ID 到剪贴板 - 复制我的私人密钥 复制到剪贴板 无法从闪电地址集合LNURL"%1$s"。请检查用户设置 无法检查经过上传后再下载的文件:%1$s @@ -3754,10 +3749,8 @@ HLS 上传 分享或保存 短视频 - 显示加密私钥二维码 在通知选项卡上包含私信和群消息。如关闭只在消息选项卡中保留消息。 显示消息 - 显示私钥二维码 签名请求已被拒绝 请确保签名应用程序已授权此交易 外部签名器对该请求返回了不正常的载荷。这可能是 Amethyst 或签名器上的错误。 diff --git a/commonsUI/src/commonMain/composeResources/values-zh-rHK/strings.xml b/commonsUI/src/commonMain/composeResources/values-zh-rHK/strings.xml index af8d37327a..09ac836145 100644 --- a/commonsUI/src/commonMain/composeResources/values-zh-rHK/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-zh-rHK/strings.xml @@ -221,7 +221,6 @@ 中繼 網站 閃電地址 - 複製 Nsec ID(您的私人密鑰)到剪貼板以備備份 發送直接消息 編輯用户元數據 不隱藏 @@ -276,9 +275,6 @@ 將所有已知內容標記為已讀 將所有新內容標記為已讀 將所有內容標記為已讀 - ## 备份与安全提示 \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 \n- Amethyst 开发人员**永远不会**要求你提供私钥。 \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 - 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 \n\n如果你丢失密码, 你将无法恢复你的密钥。 - 加密并复制我的密钥。 頒發給 %1$s 的徽章圖片 "徽章图片 您收到了新的徽章獎勵 @@ -2020,7 +2016,6 @@ 文本已複製到剪貼板 已复制到剪贴板 複製作者的 @npub 到剪貼板 - 複製我的私人密鑰 复制到剪贴板 无法从闪电地址集合LNURL"%1$s"。请检查用户设置 无法检查经过上传后再下载的文件:%1$s @@ -2807,10 +2802,8 @@ HLS 上传 分享或保存 短视频 - 显示加密私钥二维码 在通知选项卡上包含私信和群消息。如关闭只在消息选项卡中保留消息。 显示消息 - 显示私钥二维码 签名请求已被拒绝 请确保签名应用程序已授权此交易 外部签名器对该请求返回了不正常的载荷。这可能是 Amethyst 或签名器上的错误。 diff --git a/commonsUI/src/commonMain/composeResources/values-zh-rSG/strings.xml b/commonsUI/src/commonMain/composeResources/values-zh-rSG/strings.xml index 5d8c0b7ca4..d3164d768c 100644 --- a/commonsUI/src/commonMain/composeResources/values-zh-rSG/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-zh-rSG/strings.xml @@ -221,7 +221,6 @@ 中继 网站 闪电地址 - 复制 Nsec ID(您的私人密钥)到剪贴板以备备份 发送直接消息 编辑用户元数据 不隐藏 @@ -276,9 +275,6 @@ 将所有已知内容标记为已读 将所有新内容标记为已读 将所有内容标记为已读 - ## 备份与安全提示 \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 \n- Amethyst 开发人员**永远不会**要求你提供私钥。 \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 - 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 \n\n如果你丢失密码, 你将无法恢复你的密钥。 - 加密并复制我的密钥。 颁发给 %1$s 的徽章图片 "徽章图片 你收到了新的徽章奖励 @@ -2020,7 +2016,6 @@ 文本已复制到剪贴板 已复制到剪贴板 已复制作者公钥 ID 到剪贴板 - 复制我的私人密钥 复制到剪贴板 无法从闪电地址集合LNURL"%1$s"。请检查用户设置 无法检查经过上传后再下载的文件:%1$s @@ -2807,10 +2802,8 @@ HLS 上传 分享或保存 短视频 - 显示加密私钥二维码 在通知选项卡上包含私信和群消息。如关闭只在消息选项卡中保留消息。 显示消息 - 显示私钥二维码 签名请求已被拒绝 请确保签名应用程序已授权此交易 外部签名器对该请求返回了不正常的载荷。这可能是 Amethyst 或签名器上的错误。 diff --git a/commonsUI/src/commonMain/composeResources/values-zh-rTW/strings.xml b/commonsUI/src/commonMain/composeResources/values-zh-rTW/strings.xml index 8f327fa1bf..cdc0f88ed8 100644 --- a/commonsUI/src/commonMain/composeResources/values-zh-rTW/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-zh-rTW/strings.xml @@ -216,7 +216,6 @@ 中繼 網站 閃電地址 - 複製 NSec (私人密鑰)到剪貼板以備備份 發送直接消息 編輯用户元數據 不隱藏 @@ -271,9 +270,6 @@ 將所有已知內容標記為已讀 將所有新內容標記為已讀 將所有內容標記為已讀 - ## 備份與安全提示 \n\n你的帳戶由一個私鑰保護。私鑰是以 **nsec1** 開頭的隨機字符串。任何擁有你的私鑰的人都可以使用你的身份發佈內容。 \n\n- **不要**將你的私鑰添加到任何你不信任的網站或軟件,亦不要在網上公開。 \n- Amethyst 開發人員**永遠不會**要求你提供私鑰。 \n- **請**保留你的私鑰的安全備份,以備帳戶恢復。我們建議使用密碼管理器。 - 爲了額外的安全性,你可以用密碼加密你的密鑰。此密鑰以 **ncryptsec1** 開頭,沒有密碼就不能使用。 \n\n如果你丟失密碼,你將無法恢復你的密鑰。 - 加密並複製我的密鑰 頒發給 %1$s 的徽章圖片 "徽章獎勵圖片 您收到了新的徽章獎勵 @@ -2005,7 +2001,6 @@ 文本已複製到剪貼板 已複製到剪貼簿 複製作者的 @npub 到剪貼板 - 複製我的私人密鑰 複製至剪貼簿 無法從閃電地址集合 LNURL “%1$s”。請檢查用戶設置 上傳後無法檢查已下載的檔案:%1$s @@ -2779,10 +2774,8 @@ HLS 上傳 分享或保存 短片 - 顯示加密私鑰 QR 碼 在通知分頁中包含私訊及群組訊息。關閉後,訊息將只出現在訊息分頁中。 顯示訊息 - 顯示私鑰 QR 碼 簽名請求已被拒絕 請確保簽名應用程式已授權此交易 外部簽署器回傳了與請求不符的酬載。Amethyst 或簽署器可能存在錯誤。 diff --git a/commonsUI/src/commonMain/composeResources/values-zh/strings.xml b/commonsUI/src/commonMain/composeResources/values-zh/strings.xml index 17be4c460b..76a3e30f4c 100644 --- a/commonsUI/src/commonMain/composeResources/values-zh/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-zh/strings.xml @@ -202,7 +202,6 @@ 中继 网站 闪电地址 - 复制 Nsec ID(您的私人密钥)到剪贴板以备备份 发送直接消息 编辑用户元数据 不隐藏 @@ -257,7 +256,6 @@ 将所有已知内容标记为已读 将所有新内容标记为已读 将所有内容标记为已读 - 加密并复制我的密钥。 颁发给 %1$s 的徽章图片 "徽章图片 您收到了新的徽章奖励 @@ -1799,8 +1797,6 @@ Explorer API 基础URL 支付来自DVM的发票 支付 %1$s sats 到 DVM - ## 备份与安全提示 \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 \n- Amethyst 开发人员**永远不会**要求你提供私钥。 \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 - 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 \n\n如果你丢失密码, 你将无法恢复你的密钥。 使用直接链接 静态网站: %1$s nApple: %1$s @@ -2037,7 +2033,6 @@ 文本已复制到剪贴板 已复制到剪贴板 复制作者的 @npub 到剪贴板 - 复制我的私人密钥 复制到剪贴板 无法从闪电地址集合LNURL"%1$s"。请检查用户设置 无法检查经过上传后再下载的文件:%1$s @@ -2860,10 +2855,8 @@ HLS 上传 分享或保存 短视频 - 显示加密私钥二维码 在通知选项卡上包含私信和群消息。如关闭只在消息选项卡中保留消息。 显示消息 - 显示私钥二维码 签名请求已被拒绝 请确保签名应用程序已授权此交易 外部签名器对该请求返回了不正常的载荷。这可能是 Amethyst 或签名器上的错误。 diff --git a/commonsUI/src/commonMain/composeResources/values/strings.xml b/commonsUI/src/commonMain/composeResources/values/strings.xml index 3782cc7eb2..873fdebe0b 100644 --- a/commonsUI/src/commonMain/composeResources/values/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values/strings.xml @@ -558,7 +558,6 @@ Relays Website Lightning Address - Copies the Nsec ID (your password) to the clipboard for backup Send a Direct Message Edits the User's Metadata Unblock @@ -668,14 +667,29 @@ Mark all Known as read Mark all New as read Mark all as read - ## Key Backup and Safety Tips \n\nYour account is secured by a secret key. The key is a long sequence of characters starting with **nsec1**. Anyone who has access to this secret key can post and change your identity. \n\n- Do **not** put your secret key in any website or software you do not trust. \n- Amethyst developers will **never** ask for your secret key. \n- **Do** keep a secure backup of your secret key for account recovery. We recommend using a password manager. - For additional security, you can encrypt your key with a password. This key starts with **ncryptsec1** and cannot be used without your password. \n\nIf you lose your password, you will not be able to recover your key. + Your secret key is your account + Anyone who has it can post as you. If you lose it, nobody can recover it, not even Amethyst. + Tap to reveal + Write it down in this order. Upper or lower case both work. + QR code + Password-protected copy + Password + An ncryptsec1… that only works with your password. + At least %1$d characters + Repeat password + Passwords don't match + Encrypt key + Encrypting… + Safe to keep in a password manager or cloud notes: it can't be opened without the password, and a forgotten password can't be recovered. + Use a different password + Keep the paper somewhere only you can find it, or save the key in a password manager. + Never paste your key into websites or apps you don't trust. + Amethyst developers will never ask for your key. Back up your keys Your secret key is the only way to access this account. If you lose it, it can never be recovered. Save it somewhere safe now. Back up now I saved them Dismiss - Encrypt and copy my secret key Badge award image for %1$s "Badge award image You Received a new Badge Award @@ -3617,7 +3631,6 @@ Copied note text to clipboard Copied to clipboard Copied author’s @npub to clipboard - Copy my secret key Copy to clipboard Could not assemble LNUrl from Lightning Address "%1$s". Check the user's setup Could not check downloaded file after upload: %1$s @@ -5105,10 +5118,8 @@ HLS Upload Share or Save Shorts - Show encrypted private key QR code Include direct and group messages on the Notification tab. Turn off to keep messages only in the Messages tab. Show Messages - Show private key QR code Sign request rejected Make sure the signer application has authorized this transaction External signer returned a payload that is strange for the request. There might be a bug on either Amethyst or the Signer. diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/KeyTranscriptionGrid.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/KeyTranscriptionGrid.kt new file mode 100644 index 0000000000..c0f95f4db0 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/KeyTranscriptionGrid.kt @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.text.TextAutoSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription + +private const val MASK_CHAR = '•' + +/** + * Shows a bech32 key (usually an nsec) as numbered rows of 5-4-4-4-4 character + * groups (see [Bech32Transcription]) so it can be copied onto paper by hand. + * + * Monospace keeps the groups aligned as columns across rows, and each row is + * auto-sized to stay on one line on narrow screens and large font scales. + * [masked] keeps the exact same layout with every character replaced by a dot, + * so revealing the key doesn't shift the screen. + */ +@Composable +fun KeyTranscriptionGrid( + bech32: String, + modifier: Modifier = Modifier, + masked: Boolean = false, + uppercase: Boolean = true, + color: Color = MaterialTheme.colorScheme.onSurface, + lineNumberColor: Color = MaterialTheme.colorScheme.onSurfaceVariant, +) { + val rows = + remember(bech32, masked, uppercase) { + val source = if (uppercase) bech32.uppercase() else bech32 + Bech32Transcription.groups(source).map { groups -> + groups.joinToString(" ") { group -> + if (masked) MASK_CHAR.toString().repeat(group.length) else group + } + } + } + + val keyStyle = + MaterialTheme.typography.titleLarge.copy( + fontFamily = FontFamily.Monospace, + fontWeight = FontWeight.Medium, + letterSpacing = 1.sp, + ) + + Column( + modifier = modifier, + verticalArrangement = Arrangement.spacedBy(10.dp), + ) { + rows.forEachIndexed { index, row -> + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = (index + 1).toString(), + style = MaterialTheme.typography.labelMedium, + color = lineNumberColor, + modifier = Modifier.width(20.dp), + ) + Text( + text = row, + style = keyStyle, + color = color, + maxLines = 1, + softWrap = false, + overflow = TextOverflow.Clip, + autoSize = TextAutoSize.StepBased(minFontSize = 10.sp, maxFontSize = keyStyle.fontSize), + ) + } + } + } +} diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManager.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManager.kt index 02b582fc95..4c2b520189 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManager.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManager.kt @@ -45,6 +45,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.sockets.okhttp.BasicOkHttpWebSoc import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions +import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription import com.vitorpamplona.quartz.nip19Bech32.decodePrivateKeyAsHexOrNull import com.vitorpamplona.quartz.nip19Bech32.decodePublicKeyAsHexOrNull import com.vitorpamplona.quartz.nip19Bech32.toNpub @@ -700,7 +701,8 @@ class AccountManager internal constructor( } fun loginWithKey(keyInput: String): Result { - val trimmedInput = keyInput.trim() + // Also accepts keys copied by hand: UPPERCASE, split into dash/space-separated groups. + val trimmedInput = Bech32Transcription.normalize(keyInput) val privKeyHex = decodePrivateKeyAsHexOrNull(trimmedInput) if (privKeyHex != null) { diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/auth/NewKeyOnboardingScreen.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/auth/NewKeyOnboardingScreen.kt index ea0d611615..5475ced1ee 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/auth/NewKeyOnboardingScreen.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/auth/NewKeyOnboardingScreen.kt @@ -66,6 +66,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.account_backup_password_min_length import com.vitorpamplona.amethyst.commons.resources.action_copy import com.vitorpamplona.amethyst.commons.resources.backup_keys_copied import com.vitorpamplona.amethyst.commons.resources.backup_keys_copy_plain_warning @@ -409,12 +410,13 @@ private fun EncryptedCopySection(nsec: String) { label = { Text(stringResource(Res.string.new_key_encrypt_password_label)) }, singleLine = true, isError = error, - supportingText = + supportingText = { if (error) { - { Text(stringResource(Res.string.backup_keys_encrypt_failed)) } + Text(stringResource(Res.string.backup_keys_encrypt_failed)) } else { - null - }, + Text(stringResource(Res.string.account_backup_password_min_length, Nip49.MIN_PASSWORD_LENGTH)) + } + }, visualTransformation = if (showChars) VisualTransformation.None else PasswordVisualTransformation(), trailingIcon = { @@ -450,7 +452,7 @@ private fun EncryptedCopySection(nsec: String) { } } }, - enabled = password.isNotBlank() && !working, + enabled = Nip49.isLongEnough(password) && !working, colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.secondaryContainer, diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/keyBackup/BackupKeysCard.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/keyBackup/BackupKeysCard.kt index 13e8e650b0..a81b62423f 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/keyBackup/BackupKeysCard.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/keyBackup/BackupKeysCard.kt @@ -63,6 +63,7 @@ import com.vitorpamplona.amethyst.commons.privacylock.LockScope import com.vitorpamplona.amethyst.commons.privacylock.LockState import com.vitorpamplona.amethyst.commons.privacylock.lockStateFor import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.account_backup_password_min_length import com.vitorpamplona.amethyst.commons.resources.backup_keys_copied import com.vitorpamplona.amethyst.commons.resources.backup_keys_copy import com.vitorpamplona.amethyst.commons.resources.backup_keys_copy_encrypted @@ -83,6 +84,7 @@ import com.vitorpamplona.amethyst.commons.resources.backup_keys_show_qr import com.vitorpamplona.amethyst.commons.resources.backup_keys_title import com.vitorpamplona.amethyst.commons.resources.backup_keys_unlock_subtitle import com.vitorpamplona.amethyst.commons.resources.backup_keys_unlock_title +import com.vitorpamplona.amethyst.commons.ui.components.KeyTranscriptionGrid import com.vitorpamplona.amethyst.desktop.account.AccountState import com.vitorpamplona.amethyst.desktop.security.DesktopLockScreen import com.vitorpamplona.amethyst.desktop.ui.auth.QrCodeCanvas @@ -314,7 +316,16 @@ private fun RevealedSecret( nsec: String, onHide: () -> Unit, ) { - MonospaceKeyValue(value = nsec, isSensitive = true) + KeyTranscriptionGrid( + bech32 = nsec, + modifier = + Modifier + .fillMaxWidth() + .background( + color = MaterialTheme.colorScheme.surface, + shape = RoundedCornerShape(4.dp), + ).padding(horizontal = 12.dp, vertical = 16.dp), + ) Spacer(Modifier.height(8.dp)) Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { @@ -363,12 +374,13 @@ private fun EncryptedCopy(nsec: String) { label = { Text(stringResource(Res.string.backup_keys_encrypt_password_label)) }, singleLine = true, isError = error, - supportingText = + supportingText = { if (error) { - { Text(stringResource(Res.string.backup_keys_encrypt_failed)) } + Text(stringResource(Res.string.backup_keys_encrypt_failed)) } else { - null - }, + Text(stringResource(Res.string.account_backup_password_min_length, Nip49.MIN_PASSWORD_LENGTH)) + } + }, visualTransformation = if (showChars) VisualTransformation.None else PasswordVisualTransformation(), trailingIcon = { @@ -406,7 +418,7 @@ private fun EncryptedCopy(nsec: String) { } } }, - enabled = password.isNotBlank() && !working, + enabled = Nip49.isLongEnough(password) && !working, ) { Icon( symbol = MaterialSymbols.ContentCopy, @@ -431,19 +443,11 @@ private fun EncryptedCopy(nsec: String) { } @Composable -private fun MonospaceKeyValue( - value: String, - isSensitive: Boolean = false, -) { +private fun MonospaceKeyValue(value: String) { Text( value, style = MaterialTheme.typography.bodySmall.copy(fontFamily = FontFamily.Monospace), - color = - if (isSensitive) { - MaterialTheme.colorScheme.error - } else { - MaterialTheme.colorScheme.onSurfaceVariant - }, + color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier .fillMaxWidth() diff --git a/desktopApp/src/jvmTest/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManagerKeyLoginTest.kt b/desktopApp/src/jvmTest/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManagerKeyLoginTest.kt index 6059f961fe..9cdb2b604d 100644 --- a/desktopApp/src/jvmTest/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManagerKeyLoginTest.kt +++ b/desktopApp/src/jvmTest/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManagerKeyLoginTest.kt @@ -24,6 +24,7 @@ import com.vitorpamplona.amethyst.commons.keystorage.SecureKeyStorage import com.vitorpamplona.amethyst.commons.model.account.SignerType import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal +import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription import com.vitorpamplona.quartz.nip19Bech32.toNpub import com.vitorpamplona.quartz.nip19Bech32.toNsec import io.mockk.coEvery @@ -84,6 +85,19 @@ class AccountManagerKeyLoginTest { assertEquals(SignerType.Internal, state.signerType) } + @Test + fun loginWithHandCopiedNsecReturnsLoggedIn() { + val keyPair = KeyPair() + val nsec = keyPair.privKey!!.toNsec() + // As written down from the backup screen: uppercase, in dash-separated groups, one row per line. + val handCopied = + Bech32Transcription.groups(nsec.uppercase()).joinToString("\n") { it.joinToString("-") } + + val state = manager.loginWithKey(handCopied).getOrThrow() + assertFalse(state.isReadOnly) + assertEquals(nsec, state.nsec) + } + @Test fun loginWithNpubReturnsReadOnly() { val keyPair = KeyPair() diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/Bech32Transcription.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/Bech32Transcription.kt new file mode 100644 index 0000000000..ba64067994 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/Bech32Transcription.kt @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip19Bech32 + +/** + * Helpers for copying a bech32 key (usually an `nsec1…`) by hand — onto paper, a + * steel plate, or into another device's keyboard — and for reading it back. + * + * A 32-byte key encodes to 63 chars (`nsec1` + 52 data + 6 checksum), which splits + * evenly into [ROWS_PER_KEY] rows of [ROW_PATTERN] (5-4-4-4-4 = 21): + * + * ``` + * nsec1 ptuh w9cg 9ays zgxs + * nr6zm 5akh s9ju w2r9 eujr + * ha0r5 q6fz wghj hsl4 vqtl + * ``` + * + * Bech32 is case-insensitive as long as the whole string uses one case, so the + * transcription may be shown in UPPERCASE: the alphabet has no `b`, `i` or `o`, + * and `1` only appears as the separator, which removes most handwriting mix-ups. + */ +object Bech32Transcription { + /** Group sizes of one row. The leading 5 keeps the `nsec1` prefix in one group. */ + val ROW_PATTERN = intArrayOf(5, 4, 4, 4, 4) + + const val ROWS_PER_KEY = 3 + + /** + * Splits [bech32] into rows of groups following [ROW_PATTERN]. The last row may be + * shorter when the input isn't a multiple of the row length. + */ + fun groups(bech32: String): List> { + val rows = mutableListOf>() + var i = 0 + while (i < bech32.length) { + val row = mutableListOf() + for (size in ROW_PATTERN) { + if (i >= bech32.length) break + val end = minOf(i + size, bech32.length) + row.add(bech32.substring(i, end)) + i = end + } + rows.add(row) + } + return rows + } + + /** + * Undoes a hand transcription: if [input], once whitespace and `-` separators are + * removed, starts with a NIP-19 / NIP-49 prefix (any case), returns it compacted and + * lowercased so the bech32 decoder and prefix checks accept it. Anything else is + * returned trimmed but otherwise untouched (hex keys, mnemonics, NIP-05 addresses). + * + * Neither whitespace nor `-` is in the bech32 alphabet, so dropping them can't turn + * one valid key into another. + */ + fun normalize(input: String): String { + val trimmed = input.trim() + val compact = trimmed.filterNot { it.isWhitespace() || it == '-' } + val lower = compact.lowercase() + return if (TRANSCRIBABLE_PREFIXES.any { lower.startsWith(it) }) lower else trimmed + } + + private val TRANSCRIBABLE_PREFIXES = arrayOf("nsec1", "npub1", "ncryptsec1", "nprofile1") +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49.kt index 1e82206ad5..d704d2a940 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49.kt @@ -31,6 +31,31 @@ import com.vitorpamplona.quartz.utils.UnicodeNormalizer import kotlin.math.pow class Nip49 { + companion object { + /** + * Shortest password Amethyst accepts when *creating* an ncryptsec. NIP-49 sets no + * minimum, and decrypting must accept any password other clients allowed, so this + * is a creation-time policy only. + * + * An ncryptsec can be attacked offline with no rate limit, at one scrypt(2^16) + * per guess. 12 characters keeps even a random-looking password out of reach of + * large GPU farms, while staying typeable on a phone at login. + */ + const val MIN_PASSWORD_LENGTH = 12 + + /** scrypt cost used when creating: 2^16 rounds, 64 MiB. Safe on low-end phones. */ + const val DEFAULT_LOG_N = 16 + + /** + * Length as scrypt sees it: code points of the NFKC-normalized password, so + * an emoji (a UTF-16 surrogate pair) counts once and compatibility forms + * count as what they normalize to. + */ + fun passwordLength(password: String): Int = UnicodeNormalizer().normalizeNFKC(password).count { !it.isLowSurrogate() } + + fun isLongEnough(password: String): Boolean = passwordLength(password) >= MIN_PASSWORD_LENGTH + } + fun decrypt( nCryptSec: String, password: String, @@ -42,30 +67,43 @@ class Nip49 { ): String { check(encryptedInfo != null) { "Couldn't decode key" } check(encryptedInfo.version == EncryptedInfo.V) { "invalid version" } + // 32-byte key + 16-byte tag. A shorter payload can still carry a valid tag and + // would otherwise come back as a zero-padded "key". + check(encryptedInfo.encryptedKey.size == 48) { "invalid encrypted key length" } val normalizedPassword = UnicodeNormalizer().normalizeNFKC(password).encodeToByteArray() val n = 2.0.pow(encryptedInfo.logn.toDouble()).toInt() - val key = SCrypt.scrypt(normalizedPassword, encryptedInfo.salt, n, 8, 1, 32) + val key = deriveKey(normalizedPassword, encryptedInfo.salt, n, encryptedInfo.logn.toInt()) val m = ByteArray(32) - LibSodiumInstance.cryptoAeadXChaCha20Poly1305IetfDecrypt( - m, - key, - encryptedInfo.encryptedKey, - byteArrayOf(encryptedInfo.keySecurity), - encryptedInfo.nonce, - key, - ) + try { + // The Poly1305 tag is what tells a wrong password apart. Inspecting the output + // instead (e.g. "any byte > 0") rejects valid keys whose bytes are all >= 0x80. + val authenticated = + LibSodiumInstance.cryptoAeadXChaCha20Poly1305IetfDecrypt( + m, + key, + encryptedInfo.encryptedKey, + byteArrayOf(encryptedInfo.keySecurity), + encryptedInfo.nonce, + key, + ) - check(m.any { it > 0 }) { "Incorrect password" } + check(authenticated) { "Incorrect password" } - return m.toHexKey() + return m.toHexKey() + } finally { + // NIP-49: the symmetric key should be zeroed and discarded after use. + key.fill(0) + normalizedPassword.fill(0) + m.fill(0) + } } fun encrypt( secretKeyHex: String, password: String, - logn: Int = 16, + logn: Int = DEFAULT_LOG_N, ksb: Byte = EncryptedInfo.CLIENT_DOES_NOT_TRACK, ): String = encrypt(secretKeyHex.hexToByteArray(), password, logn, ksb) @@ -81,21 +119,31 @@ class Nip49 { val normalizedPassword = UnicodeNormalizer().normalizeNFKC(password).encodeToByteArray() val n = 2.0.pow(logn.toDouble()).toInt() - val key = SCrypt.scrypt(normalizedPassword, salt, n, 8, 1, 32) + val key = deriveKey(normalizedPassword, salt, n, logn) val ciphertext = ByteArray(48) - // byte[] c, long[] cLen, - // byte[] m, long mLen, - // byte[] ad, long adLen, - // byte[] nSec, byte[] nPub, byte[] k - LibSodiumInstance.cryptoAeadXChaCha20Poly1305IetfEncrypt( - ciphertext, - secretKey, - byteArrayOf(ksb), - key, - nonce, - key, - ) + try { + // byte[] c, long[] cLen, + // byte[] m, long mLen, + // byte[] ad, long adLen, + // byte[] nSec, byte[] nPub, byte[] k + val encrypted = + LibSodiumInstance.cryptoAeadXChaCha20Poly1305IetfEncrypt( + ciphertext, + secretKey, + byteArrayOf(ksb), + key, + nonce, + key, + ) + // Never hand back an ncryptsec of an untouched (all-zero) buffer: it would be a + // backup that no password can ever open. + check(encrypted) { "Failed to encrypt the key" } + } finally { + // NIP-49: the symmetric key should be zeroed and discarded after use. + key.fill(0) + normalizedPassword.fill(0) + } return EncryptedInfo( EncryptedInfo.V, @@ -107,6 +155,24 @@ class Nip49 { ).encodePayload() } + /** + * scrypt allocates 128 * r * N bytes up front: 1 GiB at LOG_N 20, which NIP-49 allows and + * other clients may choose. Past the heap that is an OutOfMemoryError, which callers' + * `catch (e: Exception)` would miss, crashing instead of reporting the key as unusable. + */ + private fun deriveKey( + normalizedPassword: ByteArray, + salt: ByteArray, + n: Int, + logn: Int, + ): ByteArray = + try { + SCrypt.scrypt(normalizedPassword, salt, n, 8, 1, 32) + } catch (e: Error) { + normalizedPassword.fill(0) + throw IllegalStateException("Not enough memory for this key's scrypt cost (LOG_N $logn)", e) + } + class EncryptedInfo( val version: Byte, val logn: Byte, diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.kt index 2f5b0225c0..9fa3806a60 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.kt @@ -39,6 +39,8 @@ object LibSodiumInstance { try { val plaintext = XChaCha20Poly1305.decrypt(ciphertext, ad, nPub, k) plaintext.copyInto(message) + // The caller owns the only copy it should have; don't leave another on the heap. + plaintext.fill(0) true } catch (_: Exception) { false diff --git a/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/Bech32TranscriptionTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/Bech32TranscriptionTest.kt new file mode 100644 index 0000000000..c8d13a445b --- /dev/null +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/Bech32TranscriptionTest.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip19Bech32 + +import kotlin.test.Test +import kotlin.test.assertEquals + +class Bech32TranscriptionTest { + private val nsec = "nsec1ptuhw9cg9ayszgxsnr6zm5akhs9juw2r9eujrha0r5q6fzwghjhsl4vqtl" + + @Test + fun splitsAnNsecIntoThreeRowsOf54444() { + assertEquals( + listOf( + listOf("nsec1", "ptuh", "w9cg", "9ays", "zgxs"), + listOf("nr6zm", "5akh", "s9ju", "w2r9", "eujr"), + listOf("ha0r5", "q6fz", "wghj", "hsl4", "vqtl"), + ), + Bech32Transcription.groups(nsec), + ) + } + + @Test + fun groupsRejoinToTheOriginal() { + assertEquals(nsec, Bech32Transcription.groups(nsec).flatten().joinToString("")) + } + + @Test + fun shortInputLeavesAPartialLastRow() { + assertEquals( + listOf(listOf("nsec1", "ptuh", "w9cg", "9ays", "zgxs"), listOf("nr")), + Bech32Transcription.groups("nsec1ptuhw9cg9ayszgxsnr"), + ) + } + + @Test + fun uppercaseHyphenatedTranscriptionDecodesToTheSameKey() { + val written = + """ + NSEC1-PTUH-W9CG-9AYS-ZGXS + NR6ZM-5AKH-S9JU-W2R9-EUJR + HA0R5-Q6FZ-WGHJ-HSL4-VQTL + """.trimIndent() + + val normalized = Bech32Transcription.normalize(written) + assertEquals(nsec, normalized) + assertEquals(decodePrivateKeyAsHexOrNull(nsec), decodePrivateKeyAsHexOrNull(normalized)) + } + + @Test + fun spacesAndMixedCaseAreAccepted() { + assertEquals(nsec, Bech32Transcription.normalize(" Nsec1 ptuh w9cg 9ays zgxs nr6zm 5akh s9ju w2r9 eujr ha0r5 q6fz wghj hsl4 vqtl ")) + } + + @Test + fun nonBech32InputIsOnlyTrimmed() { + assertEquals("alice@example.com", Bech32Transcription.normalize(" alice@example.com ")) + assertEquals("abandon ability able", Bech32Transcription.normalize("abandon ability able")) + assertEquals("ABCDEF-01", Bech32Transcription.normalize("ABCDEF-01")) + } +} diff --git a/quartz/src/jvmTest/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49InteropTest.kt b/quartz/src/jvmTest/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49InteropTest.kt new file mode 100644 index 0000000000..70ea503d27 --- /dev/null +++ b/quartz/src/jvmTest/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49InteropTest.kt @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip49PrivKeyEnc + +import kotlin.test.Test +import kotlin.test.assertEquals + +/** + * ncryptsecs produced by other NIP-49 implementations, which Amethyst must keep opening. + * + * Generated once by encrypting the same cases with each library (encryption is randomized, + * so only decryption can be pinned). Cases cover the three key-security bytes, NFKC (the + * password is given in its un-normalized typed form), astral-plane emoji, significant + * spaces, an empty password, a key whose bytes are all >= 0x80, and a non-default LOG_N. + * The reverse direction (those libraries opening Amethyst's output) was checked at the + * same time against the same versions. + */ +class Nip49InteropTest { + private class Vector( + val producer: String, + val case: String, + val ncryptsec: String, + val password: String, + val secretKeyHex: String, + val logn: Int, + val ksb: Int, + ) + + private val vectors = + listOf( + Vector("nostr-tools 2.25.2", "spec-key-ascii", "ncryptsec1qggzef0f9c0e4jahr32p98weq679sydr6ea4chnz0kzys4egytrt89dc8e3ml28z8jfq9daj6hn8rkd3kltru9mxzvpc4v2ppgmyp4dew7ugcp98hfayqyehss36xdl95eulzrjhv9z8mk745yvkq9la", "nostr", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("nostr-tools 2.25.2", "ksb0", "ncryptsec1qgg2mwlypqz2an0qvkx5wj5kw2xnaunl6648utjxs4acpud2ewpgp4wcv3xwvhf2vgmqqaudk4zl9rcdtryg97j8z7jg6ex0q3tdsl0e2zh4rsedj43jr0th48z4cv5vgausj6fxhsjjzfs8lvkfdu4v", "correct horse battery", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 0), + Vector("nostr-tools 2.25.2", "ksb1", "ncryptsec1qggxwrt3vtsyy6fn8mha8danwhdwe4dx39r4l3r0fgh393kr6f7a2yt230vsmkuug0lsrjedklp7r4eltcfckdp37x5afc8uk5fzaxkcnvx5q3cyt69n4fgfdddxuejjmlkzerggxlgjqpesn5vk2djk", "correct horse battery", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 1), + Vector("nostr-tools 2.25.2", "nfkc-typed-form", "ncryptsec1qgggze6805h7slevp5evyekxhh42fl2qk8hlla2uej8934l0f65v7xfhd2njmtdnm2ws9grf6tuzeugj59hctn3rg8dp03s8e62vycvynmf9ymcxp9sczvhx7mntl8wm8gujg00vx9rjvxxt4s8nq893", "\u212B\u2126\u1E9B\u0323", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("nostr-tools 2.25.2", "emoji", "ncryptsec1qggpnka7pcakst6nszv492xqk53q07ctdjztklevawatwfwcapyw2qvfmm6xuz3kl4sqyefsw8c5g96zpj6p7dhq8kcjkynm2fz7nwy5q7mtx7vf5dwh9mmhj82snl2tnlpcz6rzdqhl7aan7ygz08f8", "\uD83D\uDD11\uD83D\uDD12 key lock \uD83E\uDDE1", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("nostr-tools 2.25.2", "spaces", "ncryptsec1qgg0j53e68fs5ty9d6kvup5qwpglml0knavrkrzhu88345kkrgrfju9hpwksnre3uveqys4elvdjtjz3770l2rdm6a7rfepmumgnp9kzl9wjp9sy575m02xm9rgc86npyj8jgspcq97s9lgd7gtz5lg2", " leading and trailing ", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("nostr-tools 2.25.2", "empty-password", "ncryptsec1qgg0mnjj0x8um28yrku7k0pxhcwg70l8286lqng949qw2xgw3auejrs8g2whr9qavgus9w7etxlxwuxtw9d4t9uzknq558c6d83vxz48ka25xn064df9cxgv7ty820yrej8yll9d9wd0lyfpn5yuny8r", "", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("nostr-tools 2.25.2", "all-high-bytes", "ncryptsec1qgg97h3hl9jwjwneecfa8nfycyh8vh9h4v2td75qxpq2y2xyw2epa9xzjgerxwyl73asymlcmusgx9nygg26kxgtrhepn77aqqej6ufgly4hlzxwl9jdxkt24mpl85lgfus0xcge78pg7ytljva58eyu", "high bytes key!", "8080808080808080808080808080808080808080808080808080808080808080", 16, 2), + Vector("nostr-tools 2.25.2", "logn8", "ncryptsec1qgydpemrwe496lqjlu9hsd8x39yyrv7w0tpt0s5wh2e0amzq9vwshrqs3enjew7hlwnsym8v0jtrzg7r4l7ku8lx9yw9gcy66std9aluchvy8mxpatqkdqlexmdap6hgv2p2l936zlwks3529q8p57vk", "cheap scrypt pw", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 8, 2), + Vector("rust-nostr 0.45.5", "spec-key-ascii", "ncryptsec1qggv857u8hqfyknh9vntpa7vpuw2mlw9fwu46qkfzfd4w07rz3nfyyptcxac2a3qcuxqy3v80kxxkzryjdryu5dl6ygwvq9tvgaft5aap27s6arz7wdjhw23h2jdsknvfndjmtarcu0w4nc4gc39zeu4", "nostr", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("rust-nostr 0.45.5", "ksb0", "ncryptsec1qggw5euqnv6jwzzu4kaqp4rgda8q87ydpyccvujvrvgn4z2mderjhkr6fvyvv85ve0jspp90gpdh9nlqfjj9clvse4xjyd0aq28uwu4t594yxwlx00k7n6dh50l6ag7xksnwy6dulskrgl4rv52pfcv3", "correct horse battery", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 0), + Vector("rust-nostr 0.45.5", "ksb1", "ncryptsec1qgg2jalwa5khtqhydjdpv7qku64knkcpppr9calc90g3vvryerqgtpvjef8vqjxh934qr68zxp5fdrn3478mhna7n6rk85hjsnnn6zkwqjxl5gm3fnrjv58m85n9x4frdu8u7mdl3elkggcg0s0ajrar", "correct horse battery", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 1), + Vector("rust-nostr 0.45.5", "nfkc-typed-form", "ncryptsec1qgg23tn24g595ph4rjz3qw6zaha9p8zh6rwauzfknp3wqywqvlsa9lf4yc54yl9gq6rs9yzl3fvpc63dkahjqqmye7wken7jcjkws4h506ul0qpjh8c5skcyhc08tem7n9hr07484ypmpgaf6sgd470q", "\u212B\u2126\u1E9B\u0323", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("rust-nostr 0.45.5", "emoji", "ncryptsec1qgg2x6rkclt0vwulrq83cclekghuytcyp8ju5lfuka9jmt0qh8u4mqgc6nqllw86lz2syqs5mt39fyk4tj9f00dn8hx9g2ckjurgnpajwy9as9lgta25x7jxxnpjh62j4hlr2a06j9qnzkukzq0jph3s", "\uD83D\uDD11\uD83D\uDD12 key lock \uD83E\uDDE1", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("rust-nostr 0.45.5", "spaces", "ncryptsec1qggzz6tnfts4xrepjkeuy5shg7z5y62levqknlf94tqry8zwefag3uux0qzlyfqh35ms9vzavurvh9adv36v8lhzllw4yf9zdd3nqajlcqje3k8s73jlyzcufpgwsgqu8pcq5la9mr7pg3zp2yegzzk2", " leading and trailing ", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("rust-nostr 0.45.5", "empty-password", "ncryptsec1qggyfqwg66hfdylpgw8drhuwg4yu3940zjn9u39tvaape267qs072a0qmpf48pcm8cgqyq4v0e4ygzuyf70e5req74htar44za03klj9em447gpfnshha6ez3rxh4eah3w2tj6vntqhewcjfasdwaa2k", "", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("rust-nostr 0.45.5", "all-high-bytes", "ncryptsec1qggdxzuj6y3ha9s240p2a4e9yhpatjzq4tjfc764sqc4kvcqhfn9nljhwdtdpspdx6cs95adxsc6gy86j6xkle2cp6fffr2zsv5k4ua0e266l9l2wgl5x0xavwqg8urtx6xe7z4cftdna49axgws6j6a", "high bytes key!", "8080808080808080808080808080808080808080808080808080808080808080", 16, 2), + Vector("rust-nostr 0.45.5", "logn8", "ncryptsec1qgywmddn2ymrmjkn3df9vcr87g2jzm63u0apcf28vu5u64lydlg438ztpvu9svjuqensysr7088xpp8ufu7kmzgtnal4w5gcrmfwsegst9aj8trhjllx74pew92wts8sh4lvpmu5552dfhg4zgnu8klt", "cheap scrypt pw", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 8, 2), + Vector("go-nostr 0.52.3", "spec-key-ascii", "ncryptsec1qggtku4x8v2x5wys9kaf885kslc9g69u7squzxf9v7kz733znjymywgcl7j06p5agvzsya685ztkgnl87gtulwa8htl7w8dp9j45qf77dq3lqak46nchd62cm7lfwt5p4326me9gfvedlv3qgg0xn6h5", "nostr", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("go-nostr 0.52.3", "ksb0", "ncryptsec1qggrt6nkhufyfk39fh2ectkm8yc4rkpxdzq20nawkn0nef9lcx2f7qu25njy6zw8jscqqd7t9p4yhn2mhflgsaltqm6hecngcfv0ezhftcy586xd4n2xpgu0e3sxc5ht4phe2pkrpz4u9n0u4vgggrjj", "correct horse battery", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 0), + Vector("go-nostr 0.52.3", "ksb1", "ncryptsec1qggt49pvsll6rd2efefsv5m6klzwr3adr6t9nuta26yjtkzmapr3falp9w7yqa3u5ktqrtj63skj44r3tfud48t739es23a38vdnqwu9dqnkv4gxj0p4guqx2l38m3tveknycj2wqjmc68lpect44efl", "correct horse battery", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 1), + Vector("go-nostr 0.52.3", "nfkc-typed-form", "ncryptsec1qggp6pz4dk3jsv2k79razl0j0zd35hry3qkd74a4e2qstnsc7h3etcdhwrt2av0a7v5q97vzw7pmnawpxeadt4lxcqj9s25hfheqfudakdkuk8kmczkuq60z8xxz8emm34yu4mkgt6t7jpve0vasa0pm", "\u212B\u2126\u1E9B\u0323", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("go-nostr 0.52.3", "emoji", "ncryptsec1qggx7yhdu7smxvxmszep4wzunthhdxpwnp85yjrkx44gq7u63ylvppp4nez95xlkjafq9270j8g5lsj2tlxf3lv5ecemgcrlu2789zse0a2ywjyf7twxzatz5m3ckt3cj0xth5le35msu7y0wywnuhd4", "\uD83D\uDD11\uD83D\uDD12 key lock \uD83E\uDDE1", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("go-nostr 0.52.3", "spaces", "ncryptsec1qgggqt59jswdm0ph58z45sqynzdpjak894ndu9ueykm9qdnccptnkwz6rsvfmfkhulwsy9atea9jqdqpenfhpqsmgckjw9vr64p4vqznfsua8ty0f9j0y6enk24xfulqy3n04wvj774ct6sg3yfghqdx", " leading and trailing ", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("go-nostr 0.52.3", "empty-password", "ncryptsec1qgg2tmxquvf9924env8er4dxlctjglqqrtksjhnnwu0qvapzn6trs36lqmsswnwvy29s9sdrap2m8m6656hytvr99k9364eqqsy9xe4jyd6ntetvvxnvcxl6ktlpt4dw9yjxe5w9mqhl2ywj8guslyp4", "", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 16, 2), + Vector("go-nostr 0.52.3", "all-high-bytes", "ncryptsec1qggyhcn43gycdv5hftawfywfje8w3hzj5pr4g8v70q9x49vgutfeda8lx0syku8lcras90vzt9hzzdl2t60wnytrkcfhya5t6gkrajkjkdq25t3thlcxmhhklkte7nn6ktfqsys8ynmscwy6cutzpfj2", "high bytes key!", "8080808080808080808080808080808080808080808080808080808080808080", 16, 2), + Vector("go-nostr 0.52.3", "logn8", "ncryptsec1qgyqqtmjm9k402reqysneeg8fj700l6sd03vmjwlt6g2waxrg4de2hs5q2jrtktt72uqynxqa76hsz2kfm7834pra0rwjlcgwy920r7uhg797zw63d6a0aee64wqxugxxflzynrhzvt2c2zk2s9u7cxl", "cheap scrypt pw", "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", 8, 2), + ) + + @Test + fun decryptsEveryForeignVector() { + val nip49 = Nip49() + vectors.forEach { + val label = "${it.producer} / ${it.case}" + val info = Nip49.EncryptedInfo.decodePayload(it.ncryptsec)!! + assertEquals(2, info.version.toInt(), label) + assertEquals(it.logn, info.logn.toInt(), label) + assertEquals(it.ksb, info.keySecurity.toInt(), label) + assertEquals(it.secretKeyHex, nip49.decrypt(it.ncryptsec, it.password), label) + } + } +} diff --git a/quartz/src/jvmTest/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49SpecTest.kt b/quartz/src/jvmTest/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49SpecTest.kt new file mode 100644 index 0000000000..275c84138d --- /dev/null +++ b/quartz/src/jvmTest/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49SpecTest.kt @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip49PrivKeyEnc + +import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription +import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes +import com.vitorpamplona.quartz.nip44Encryption.crypto.XChaCha20Poly1305 +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertNotEquals + +/** + * NIP-49 conformance on the JVM. The device test (androidDeviceTest/NIP49Test) covers the + * same vectors but runs in neither `./gradlew test` nor pre-push, so nothing on the + * default path proved the spec vectors still decrypt. + */ +class Nip49SpecTest { + private val nip49 = Nip49() + + private val specNcryptsec = "ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p" + private val specKey = "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683" + + @Test + fun decryptsTheSpecVector() { + assertEquals(specKey, nip49.decrypt(specNcryptsec, "nostr")) + } + + @Test + fun specVectorFieldsDecode() { + val info = Nip49.EncryptedInfo.decodePayload(specNcryptsec)!! + assertEquals(0x02.toByte(), info.version) + assertEquals(16.toByte(), info.logn) + assertEquals(16, info.salt.size) + assertEquals(24, info.nonce.size) + assertEquals(48, info.encryptedKey.size) + } + + @Test + fun encryptProducesA91BytePayloadWithVersion2() { + val payload = nip49.encrypt(specKey, "nostr").bechToBytes() + assertEquals(91, payload.size) + assertEquals(0x02.toByte(), payload[0]) + assertEquals(16.toByte(), payload[1]) + assertEquals(Nip49.EncryptedInfo.CLIENT_DOES_NOT_TRACK, payload[2 + 16 + 24]) + } + + @Test + fun encryptionIsNonDeterministic() { + assertNotEquals(nip49.encrypt(specKey, "nostr"), nip49.encrypt(specKey, "nostr")) + } + + @Test + fun passwordsAreNfkcNormalized() { + // Spec vector: U+212B U+2126 U+1E9B U+0323 normalizes to U+00C5 U+03A9 U+1E69. + val typed = "ÅΩẛ̣" + val normalized = "ÅΩṩ" + assertNotEquals(typed, normalized) + + val encrypted = nip49.encrypt(specKey, typed, 8, Nip49.EncryptedInfo.CLIENT_DOES_NOT_TRACK) + assertEquals(specKey, nip49.decrypt(encrypted, normalized)) + } + + @Test + fun wrongPasswordIsRejected() { + assertFailsWith { nip49.decrypt(specNcryptsec, "nostr2") } + } + + @Test + fun anyNonEmptyPasswordShapeRoundTrips() { + // NIP-49 puts no length or character-class rules on the password. + listOf("a", " ", " leading and trailing ", "ção", "🔑🔒", "x".repeat(1000)).forEach { + val encrypted = nip49.encrypt(specKey, it, 8, Nip49.EncryptedInfo.CLIENT_DOES_NOT_TRACK) + assertEquals(specKey, nip49.decrypt(encrypted, it)) + } + } + + @Test + fun keysWithNoPositiveSignedByteDecrypt() { + // Every byte >= 0x80 is negative as a signed Kotlin Byte. A valid key (well below + // the secp256k1 order), so the correct password must decrypt it. + val key = "80".repeat(32) + val encrypted = nip49.encrypt(key, "nostr", 8, Nip49.EncryptedInfo.CLIENT_DOES_NOT_TRACK) + assertEquals(key, nip49.decrypt(encrypted, "nostr")) + } + + @Test + fun handCopiedNcryptsecDecrypts() { + val handCopied = Bech32Transcription.groups(specNcryptsec.uppercase()).joinToString("\n") { it.joinToString("-") } + assertEquals(specKey, nip49.decrypt(Bech32Transcription.normalize(handCopied), "nostr")) + } + + @Test + fun passwordLengthCountsNormalizedCodePoints() { + assertEquals(11, Nip49.passwordLength("x".repeat(11))) + assertEquals(false, Nip49.isLongEnough("x".repeat(11))) + assertEquals(true, Nip49.isLongEnough("x".repeat(12))) + // A surrogate-pair emoji is one character, not two. + assertEquals(1, Nip49.passwordLength("\uD83D\uDD11")) + // The spec's normalization vector: 4 code points typed, 3 after NFKC. + assertEquals(3, Nip49.passwordLength("\u212B\u2126\u1E9B\u0323")) + } + + @Test + fun authenticatedButShortCiphertextIsRejected() { + // A tag-valid payload that encrypts only 16 bytes must not decode as a zero-padded key. + val password = "nostr" + val salt = ByteArray(16) { it.toByte() } + val nonce = ByteArray(24) { (it + 1).toByte() } + val ksb = Nip49.EncryptedInfo.CLIENT_DOES_NOT_TRACK + val key = SCrypt.scrypt(password.encodeToByteArray(), salt, 2, 8, 1, 32) + val shortCiphertext = XChaCha20Poly1305.encrypt(ByteArray(16) { 7 }, byteArrayOf(ksb), nonce, key) + + val info = Nip49.EncryptedInfo(Nip49.EncryptedInfo.V, 1, salt, nonce, ksb, shortCiphertext) + assertFailsWith { nip49.decrypt(info, password) } + } +}