From 9281a578e7badc55e117482635db1c8ad52f9f22 Mon Sep 17 00:00:00 2001 From: GT610 <79314033+GT-610@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:07:20 +0800 Subject: [PATCH] fix(container): Parsing results in sudo mode (#1031) * docs(l10n): fix un-updated English translation * feat(container): Add support for requiring a sudo password Add support for sudo password verification for Docker container operations, including: 1. Added ContainerErrType.sudoPasswordRequired error type 2. Add password prompt text in multi-language files 3. Modify the SSH execution logic to correctly handle the input of sudo password 4. Implement password caching and verification mechanism * feat(container): Add sudo password error handling logic Add a new error type `sudoPasswordIncorrect` to handle situations where the sudo password is incorrect Modify the password verification logic in the SSH client, and return a specific error code when a password error is detected Update multilingual files to support password error prompt information * fix(ssh): Remove unnecessary stderr parameter and improve sudo command handling Clean up the no longer needed stderr parameter in the SSH client, which was originally used to handle sudo password prompts Unify the sudo command construction logic, always use the _buildSudoCmd method, and add stderr redirection Clear cached passwords when passwords are incorrect * fix(container): Improved sudo command handling and Podman simulation detection Fix the sudo command processing logic, remove the masking of stderr to capture password errors Override the detection logic simulated by Podman Refactor the command building logic to support sh wrapping of multi-line commands * fix(container): Improve the prompt message for sudo password errors Update the sudo password error prompt messages for all languages to more accurately reflect situations of incorrect password or lack of permission Fix the password error detection logic for both the SSH client and container providers simultaneously * refactor(container): Remove unused sudo and password parameters in exec method Simplify the exec method signature by removing the sudo and password parameters that are no longer needed, as these functions are no longer in use * feat: Add new contributors and optimize container command handling Add two new contributors to the GithubIds list and refactor the container command processing logic: 1. Simplify the command wrapping logic and uniformly use `sh -c` for processing 2. Specific error handling when adding a sudo password incorrectly 3. Remove redundant conditional checks and temporary variables --- lib/core/extension/ssh_client.dart | 45 +++++----- lib/data/model/app/error.dart | 2 + lib/data/provider/container.dart | 139 ++++++++++++++++++++++------- lib/data/res/github_id.dart | 4 +- lib/generated/l10n/l10n.dart | 12 +++ lib/generated/l10n/l10n_de.dart | 8 ++ lib/generated/l10n/l10n_en.dart | 8 ++ lib/generated/l10n/l10n_es.dart | 8 ++ lib/generated/l10n/l10n_fr.dart | 8 ++ lib/generated/l10n/l10n_id.dart | 8 ++ lib/generated/l10n/l10n_ja.dart | 8 ++ lib/generated/l10n/l10n_nl.dart | 8 ++ lib/generated/l10n/l10n_pt.dart | 8 ++ lib/generated/l10n/l10n_ru.dart | 8 ++ lib/generated/l10n/l10n_tr.dart | 8 ++ lib/generated/l10n/l10n_uk.dart | 8 ++ lib/generated/l10n/l10n_zh.dart | 12 +++ lib/l10n/app_de.arb | 2 + lib/l10n/app_en.arb | 4 +- lib/l10n/app_es.arb | 2 + lib/l10n/app_fr.arb | 2 + lib/l10n/app_id.arb | 2 + lib/l10n/app_ja.arb | 2 + lib/l10n/app_nl.arb | 2 + lib/l10n/app_pt.arb | 2 + lib/l10n/app_ru.arb | 2 + lib/l10n/app_tr.arb | 2 + lib/l10n/app_uk.arb | 2 + lib/l10n/app_zh.arb | 2 + lib/l10n/app_zh_tw.arb | 2 + 30 files changed, 278 insertions(+), 52 deletions(-) diff --git a/lib/core/extension/ssh_client.dart b/lib/core/extension/ssh_client.dart index 43e16ef8..09bc2bff 100644 --- a/lib/core/extension/ssh_client.dart +++ b/lib/core/extension/ssh_client.dart @@ -7,13 +7,9 @@ import 'package:flutter/widgets.dart'; import 'package:server_box/data/helper/ssh_decoder.dart'; import 'package:server_box/data/model/server/system.dart'; -import 'package:server_box/data/res/misc.dart'; - typedef OnStdout = void Function(String data, SSHSession session); typedef OnStdin = void Function(SSHSession session); -typedef PwdRequestFunc = Future Function(String? user); - extension SSHClientX on SSHClient { /// Create a persistent PowerShell session for Windows commands Future<(SSHSession, String)> execPowerShell( @@ -47,7 +43,7 @@ extension SSHClientX on SSHClient { session.stderr.listen( (e) { onStderr?.call(e.string, session); - if (stderr) result.add(e); + // Don't add stderr to result, only stdout }, onDone: stderrDone.complete, onError: stderrDone.completeError, @@ -112,6 +108,19 @@ extension SSHClientX on SSHClient { return (session, result.takeBytes().string); } + /// Executes a command with password error detection. + /// + /// This method is used for executing commands where password has already been + /// handled beforehand (e.g., via base64 pipe in container commands). + /// It captures stderr via [onStderr] callback to detect sudo password errors + /// (e.g., "Sorry, try again.", "incorrect password attempt", or + /// "a password is required"), while excluding stderr from the returned + /// output via [stderr: false]. + /// + /// Returns exitCode: + /// - 0: success + /// - 1: general error + /// - 2: sudo password error Future<(int?, String)> execWithPwd( String script, { String? entry, @@ -120,7 +129,8 @@ extension SSHClientX on SSHClient { OnStdout? onStderr, required String id, }) async { - var isRequestingPwd = false; + var hasPasswordError = false; + final (session, output) = await exec( (sess) { sess.stdin.add('$script\n'.uint8List); @@ -128,25 +138,20 @@ extension SSHClientX on SSHClient { }, onStderr: (data, session) async { onStderr?.call(data, session); - if (isRequestingPwd) return; - - if (data.contains('[sudo] password for ')) { - isRequestingPwd = true; - final user = Miscs.pwdRequestWithUserReg.firstMatch(data)?.group(1); - final ctx = context ?? WidgetsBinding.instance.focusManager.primaryFocus?.context; - if (ctx == null) return; - final pwd = ctx.mounted ? await ctx.showPwdDialog(title: user, id: id) : null; - if (pwd == null || pwd.isEmpty) { - session.stdin.close(); - } else { - session.stdin.add('$pwd\n'.uint8List); - } - isRequestingPwd = false; + if (data.contains('Sorry, try again.') || + data.contains('incorrect password attempt') || + data.contains('a password is required')) { + hasPasswordError = true; } }, onStdout: onStdout, entry: entry, + stderr: false, ); + + if (hasPasswordError) { + return (2, output); + } return (session.exitCode, output); } diff --git a/lib/data/model/app/error.dart b/lib/data/model/app/error.dart index d3d64ca8..ad6ecf75 100644 --- a/lib/data/model/app/error.dart +++ b/lib/data/model/app/error.dart @@ -27,6 +27,8 @@ enum ContainerErrType { parseImages, parseStats, podmanDetected, + sudoPasswordRequired, + sudoPasswordIncorrect, } class ContainerErr extends Err { diff --git a/lib/data/provider/container.dart b/lib/data/provider/container.dart index afaaaeda..0a1a9ecf 100644 --- a/lib/data/provider/container.dart +++ b/lib/data/provider/container.dart @@ -37,6 +37,7 @@ abstract class ContainerState with _$ContainerState { @riverpod class ContainerNotifier extends _$ContainerNotifier { var sudoCompleter = Completer(); + String? _cachedPassword; @override ContainerState build(SSHClient? client, String userName, String hostId, BuildContext context) { @@ -49,6 +50,18 @@ class ContainerNotifier extends _$ContainerNotifier { return initialState; } + Future _getSudoPassword() async { + if (_cachedPassword != null) return _cachedPassword; + + if (!context.mounted) return null; + final pwd = await context.showPwdDialog(title: userName, id: hostId); + + if (pwd != null && pwd.isNotEmpty) { + _cachedPassword = pwd; + } + return pwd; + } + Future setType(ContainerType type) async { state = state.copyWith(type: type, error: null, runLog: null, items: null, images: null, version: null); Stores.container.setType(type, hostId); @@ -84,14 +97,39 @@ class ContainerNotifier extends _$ContainerNotifier { state = state.copyWith(isBusy: false); return; } + + String? password; + if (sudo) { + password = await _getSudoPassword(); + if (password == null) { + state = state.copyWith( + isBusy: false, + error: ContainerErr( + type: ContainerErrType.sudoPasswordRequired, + message: l10n.containerSudoPasswordRequired, + ), + ); + return; + } + } + final includeStats = Stores.setting.containerParseStat.fetch(); - final cmd = _wrap(ContainerCmdType.execAll(state.type, sudo: sudo, includeStats: includeStats)); + final cmd = _wrap(ContainerCmdType.execAll(state.type, sudo: sudo, includeStats: includeStats, password: password)); int? code; String raw = ''; - final errs = []; + var isPodmanEmulation = false; if (client != null) { - (code, raw) = await client!.execWithPwd(cmd, context: context, id: hostId); + (code, raw) = await client!.execWithPwd( + cmd, + context: context, + id: hostId, + onStderr: (data, _) { + if (data.contains(_podmanEmulationMsg)) { + isPodmanEmulation = true; + } + }, + ); } else { state = state.copyWith( isBusy: false, @@ -106,13 +144,23 @@ class ContainerNotifier extends _$ContainerNotifier { if (!context.mounted) return; /// Code 127 means command not found - if (code == 127 || raw.contains(_dockerNotFound) || errs.join().contains(_dockerNotFound)) { + if (code == 127 || raw.contains(_dockerNotFound)) { state = state.copyWith(error: ContainerErr(type: ContainerErrType.notInstalled)); return; } + /// Sudo password error (exitCode = 2) + if (code == 2) { + _cachedPassword = null; + state = state.copyWith(error: ContainerErr( + type: ContainerErrType.sudoPasswordIncorrect, + message: l10n.containerSudoPasswordIncorrect, + )); + return; + } + /// Pre-parse Podman detection - if (raw.contains(_podmanEmulationMsg)) { + if (isPodmanEmulation) { state = state.copyWith( error: ContainerErr( type: ContainerErrType.podmanDetected, @@ -122,15 +170,8 @@ class ContainerNotifier extends _$ContainerNotifier { return; } - /// Filter out sudo password prompt from output - if (errs.any((e) => e.contains('[sudo] password'))) { - raw = raw.split('\n').where((line) => !line.contains('[sudo] password')).join('\n'); - } - /// Detect Podman not installed when using Podman mode - if (state.type == ContainerType.podman && - (errs.any((e) => e.contains('podman: not found')) || - raw.contains('podman: not found'))) { + if (state.type == ContainerType.podman && raw.contains('podman: not found')) { state = state.copyWith(error: ContainerErr(type: ContainerErrType.notInstalled)); return; } @@ -276,21 +317,43 @@ class ContainerNotifier extends _$ContainerNotifier { ContainerType.podman => 'podman $cmd', }; + final needSudo = await sudoCompleter.future; + String? password; + if (needSudo) { + password = await _getSudoPassword(); + if (password == null) { + return ContainerErr( + type: ContainerErrType.sudoPasswordRequired, + message: l10n.containerSudoPasswordRequired, + ); + } + } + + if (needSudo) { + cmd = _buildSudoCmd(cmd, password!); + } + state = state.copyWith(runLog: ''); - final errs = []; - final (code, _) = await client?.execWithPwd( - _wrap((await sudoCompleter.future) ? 'sudo -S $cmd' : cmd), + final (code, _) = await client!.execWithPwd( + _wrap(cmd), context: context, onStdout: (data, _) { state = state.copyWith(runLog: '${state.runLog}$data'); }, - onStderr: (data, _) => errs.add(data), id: hostId, - ) ?? (null, null); + ); + state = state.copyWith(runLog: null); + if (code == 2) { + _cachedPassword = null; + return ContainerErr( + type: ContainerErrType.sudoPasswordIncorrect, + message: l10n.containerSudoPasswordIncorrect, + ); + } if (code != 0) { - return ContainerErr(type: ContainerErrType.unknown, message: errs.join('\n').trim()); + return ContainerErr(type: ContainerErrType.unknown, message: 'Command execution failed'); } if (autoRefresh) await refresh(); return null; @@ -310,6 +373,11 @@ class ContainerNotifier extends _$ContainerNotifier { const _jsonFmt = '--format "{{json .}}"'; +String _buildSudoCmd(String baseCmd, String password) { + final pwdBase64 = base64Encode(utf8.encode(password)); + return 'echo "$pwdBase64" | base64 -d | sudo -S $baseCmd'; +} + enum ContainerCmdType { version, ps, @@ -319,30 +387,41 @@ enum ContainerCmdType { // and don't require splitting output with ScriptConstants.separator ; - String exec(ContainerType type, {bool sudo = false, bool includeStats = false}) { - final prefix = sudo ? 'sudo -S ${type.name}' : type.name; - return switch (this) { - ContainerCmdType.version => '$prefix version $_jsonFmt', + String exec(ContainerType type, {bool includeStats = false}) { + final baseCmd = switch (this) { + ContainerCmdType.version => '${type.name} version $_jsonFmt', ContainerCmdType.ps => switch (type) { /// TODO: Rollback to json format when performance recovers. /// Use [_jsonFmt] in Docker will cause the operation to slow down. ContainerType.docker => - '$prefix ps -a --format "table {{printf \\"' + '${type.name} ps -a --format "table {{printf \\"' '%-15.15s ' '%-30.30s ' '${"%-50.50s " * 2}\\"' ' .ID .Status .Names .Image}}"', - ContainerType.podman => '$prefix ps -a $_jsonFmt', + ContainerType.podman => '${type.name} ps -a $_jsonFmt', }, - ContainerCmdType.stats => includeStats ? '$prefix stats --no-stream $_jsonFmt' : 'echo PASS', - ContainerCmdType.images => '$prefix image ls $_jsonFmt', + ContainerCmdType.stats => includeStats ? '${type.name} stats --no-stream $_jsonFmt' : 'echo PASS', + ContainerCmdType.images => '${type.name} image ls $_jsonFmt', }; + + return baseCmd; } - static String execAll(ContainerType type, {bool sudo = false, bool includeStats = false}) { - return ContainerCmdType.values - .map((e) => e.exec(type, sudo: sudo, includeStats: includeStats)) + static String execAll(ContainerType type, {bool sudo = false, bool includeStats = false, String? password}) { + final commands = ContainerCmdType.values + .map((e) => e.exec(type, includeStats: includeStats)) .join('\necho ${ScriptConstants.separator}\n'); + + final wrappedCommands = 'sh -c \'${commands.replaceAll("'", "'\\''")}\''; + + if (sudo && password != null) { + return _buildSudoCmd(wrappedCommands, password); + } + if (sudo) { + return 'sudo -S $wrappedCommands'; + } + return wrappedCommands; } /// Find out the required segment from [segments] diff --git a/lib/data/res/github_id.dart b/lib/data/res/github_id.dart index f3e4fbc0..817c49f5 100644 --- a/lib/data/res/github_id.dart +++ b/lib/data/res/github_id.dart @@ -138,7 +138,9 @@ abstract final class GithubIds { 'itmagpro', 'atikattar1104', 'coldboy404', - 'puskyer' + 'puskyer', + 'wanababy', + 'toarujs' }; } diff --git a/lib/generated/l10n/l10n.dart b/lib/generated/l10n/l10n.dart index 50125318..7ddfc7c6 100644 --- a/lib/generated/l10n/l10n.dart +++ b/lib/generated/l10n/l10n.dart @@ -467,6 +467,18 @@ abstract class AppLocalizations { /// **'For example: In the app, the user is set to aaa, but Docker is installed under the root user. In this case, you need to enable this option.'** String get containerTrySudoTip; + /// No description provided for @containerSudoPasswordRequired. + /// + /// In en, this message translates to: + /// **'Sudo password is required to access Docker. Please enter your password.'** + String get containerSudoPasswordRequired; + + /// No description provided for @containerSudoPasswordIncorrect. + /// + /// In en, this message translates to: + /// **'Sudo password is incorrect or not allowed. Please try again.'** + String get containerSudoPasswordIncorrect; + /// No description provided for @convert. /// /// In en, this message translates to: diff --git a/lib/generated/l10n/l10n_de.dart b/lib/generated/l10n/l10n_de.dart index 1c4d96f2..d63ffcdf 100644 --- a/lib/generated/l10n/l10n_de.dart +++ b/lib/generated/l10n/l10n_de.dart @@ -203,6 +203,14 @@ class AppLocalizationsDe extends AppLocalizations { String get containerTrySudoTip => 'Zum Beispiel: In der App ist der Benutzer auf aaa eingestellt, aber Docker ist unter dem Root-Benutzer installiert. In diesem Fall müssen Sie diese Option aktivieren'; + @override + String get containerSudoPasswordRequired => + 'Ein sudo-Passwort ist erforderlich, um auf Docker zuzugreifen. Bitte geben Sie Ihr Passwort ein.'; + + @override + String get containerSudoPasswordIncorrect => + 'Das sudo-Passwort ist falsch oder nicht erlaubt. Bitte versuchen Sie es erneut.'; + @override String get convert => 'Konvertieren'; diff --git a/lib/generated/l10n/l10n_en.dart b/lib/generated/l10n/l10n_en.dart index f80c7b61..72d7badf 100644 --- a/lib/generated/l10n/l10n_en.dart +++ b/lib/generated/l10n/l10n_en.dart @@ -202,6 +202,14 @@ class AppLocalizationsEn extends AppLocalizations { String get containerTrySudoTip => 'For example: In the app, the user is set to aaa, but Docker is installed under the root user. In this case, you need to enable this option.'; + @override + String get containerSudoPasswordRequired => + 'Sudo password is required to access Docker. Please enter your password.'; + + @override + String get containerSudoPasswordIncorrect => + 'Sudo password is incorrect or not allowed. Please try again.'; + @override String get convert => 'Convert'; diff --git a/lib/generated/l10n/l10n_es.dart b/lib/generated/l10n/l10n_es.dart index 858a19fa..b0a2eea4 100644 --- a/lib/generated/l10n/l10n_es.dart +++ b/lib/generated/l10n/l10n_es.dart @@ -203,6 +203,14 @@ class AppLocalizationsEs extends AppLocalizations { String get containerTrySudoTip => 'Por ejemplo: si configuras el usuario dentro de la app como aaa, pero Docker está instalado bajo el usuario root, entonces necesitarás habilitar esta opción'; + @override + String get containerSudoPasswordRequired => + 'Se requiere contraseña de sudo para acceder a Docker. Por favor ingrese su contraseña.'; + + @override + String get containerSudoPasswordIncorrect => + 'La contraseña de sudo es incorrecta o no está permitida. Por favor intente de nuevo.'; + @override String get convert => 'Convertir'; diff --git a/lib/generated/l10n/l10n_fr.dart b/lib/generated/l10n/l10n_fr.dart index 56b64712..65007a62 100644 --- a/lib/generated/l10n/l10n_fr.dart +++ b/lib/generated/l10n/l10n_fr.dart @@ -203,6 +203,14 @@ class AppLocalizationsFr extends AppLocalizations { String get containerTrySudoTip => 'Par exemple : Dans l\'application, l\'utilisateur est défini comme aaa, mais Docker est installé sous l\'utilisateur root. Dans ce cas, vous devez activer cette option.'; + @override + String get containerSudoPasswordRequired => + 'Un mot de passe sudo est requis pour accéder à Docker. Veuillez entrer votre mot de passe.'; + + @override + String get containerSudoPasswordIncorrect => + 'Le mot de passe sudo est incorrect ou non autorisé. Veuillez réessayer.'; + @override String get convert => 'Convertir'; diff --git a/lib/generated/l10n/l10n_id.dart b/lib/generated/l10n/l10n_id.dart index a89612f1..d6709bf2 100644 --- a/lib/generated/l10n/l10n_id.dart +++ b/lib/generated/l10n/l10n_id.dart @@ -201,6 +201,14 @@ class AppLocalizationsId extends AppLocalizations { String get containerTrySudoTip => 'Contohnya: Di dalam aplikasi, pengguna diatur sebagai aaa, tetapi Docker diinstal di bawah pengguna root. Dalam kasus ini, Anda perlu mengaktifkan opsi ini.'; + @override + String get containerSudoPasswordRequired => + 'Kata sandi sudo diperlukan untuk mengakses Docker. Silakan masukkan kata sandi Anda.'; + + @override + String get containerSudoPasswordIncorrect => + 'Kata sandi sudo salah atau tidak diizinkan. Silakan coba lagi.'; + @override String get convert => 'Mengubah'; diff --git a/lib/generated/l10n/l10n_ja.dart b/lib/generated/l10n/l10n_ja.dart index 1c85a9a9..df6d4124 100644 --- a/lib/generated/l10n/l10n_ja.dart +++ b/lib/generated/l10n/l10n_ja.dart @@ -194,6 +194,14 @@ class AppLocalizationsJa extends AppLocalizations { String get containerTrySudoTip => '例:アプリ内でユーザーをaaaに設定しているが、Dockerがrootユーザーでインストールされている場合、このオプションを有効にする必要があります'; + @override + String get containerSudoPasswordRequired => + 'Dockerにアクセスするにはsudoパスワードが必要です。パスワードを入力してください。'; + + @override + String get containerSudoPasswordIncorrect => + 'sudoパスワードが正しくないか、許可されていません。再試行してください。'; + @override String get convert => '変換'; diff --git a/lib/generated/l10n/l10n_nl.dart b/lib/generated/l10n/l10n_nl.dart index 0fa70a98..69496554 100644 --- a/lib/generated/l10n/l10n_nl.dart +++ b/lib/generated/l10n/l10n_nl.dart @@ -202,6 +202,14 @@ class AppLocalizationsNl extends AppLocalizations { String get containerTrySudoTip => 'Bijvoorbeeld: in de app is de gebruiker ingesteld op aaa, maar Docker is geïnstalleerd onder de rootgebruiker. In dit geval moet u deze optie inschakelen.'; + @override + String get containerSudoPasswordRequired => + 'Een sudo-wachtwoord is vereist om toegang te krijgen tot Docker. Voer uw wachtwoord in.'; + + @override + String get containerSudoPasswordIncorrect => + 'Het sudo-wachtwoord is onjuist of niet toegestaan. Probeer het opnieuw.'; + @override String get convert => 'Converteren'; diff --git a/lib/generated/l10n/l10n_pt.dart b/lib/generated/l10n/l10n_pt.dart index 97e43e35..b752c6ae 100644 --- a/lib/generated/l10n/l10n_pt.dart +++ b/lib/generated/l10n/l10n_pt.dart @@ -201,6 +201,14 @@ class AppLocalizationsPt extends AppLocalizations { String get containerTrySudoTip => 'Por exemplo: se o usuário for definido como aaa dentro do app, mas o Docker estiver instalado sob o usuário root, esta opção precisará ser ativada'; + @override + String get containerSudoPasswordRequired => + 'É necessária uma senha sudo para acessar o Docker. Por favor, insira sua senha.'; + + @override + String get containerSudoPasswordIncorrect => + 'A senha sudo está incorreta ou não é permitida. Por favor, tente novamente.'; + @override String get convert => 'Converter'; diff --git a/lib/generated/l10n/l10n_ru.dart b/lib/generated/l10n/l10n_ru.dart index 04d1c5f8..719755d3 100644 --- a/lib/generated/l10n/l10n_ru.dart +++ b/lib/generated/l10n/l10n_ru.dart @@ -202,6 +202,14 @@ class AppLocalizationsRu extends AppLocalizations { String get containerTrySudoTip => 'Например: если пользователь в приложении установлен как aaa, но Docker установлен под пользователем root, тогда нужно включить эту опцию'; + @override + String get containerSudoPasswordRequired => + 'Для доступа к Docker требуется пароль sudo. Пожалуйста, введите ваш пароль.'; + + @override + String get containerSudoPasswordIncorrect => + 'Пароль sudo неверен или не разрешён. Пожалуйста, попробуйте снова.'; + @override String get convert => 'Конвертировать'; diff --git a/lib/generated/l10n/l10n_tr.dart b/lib/generated/l10n/l10n_tr.dart index c03da488..eaaccdcc 100644 --- a/lib/generated/l10n/l10n_tr.dart +++ b/lib/generated/l10n/l10n_tr.dart @@ -201,6 +201,14 @@ class AppLocalizationsTr extends AppLocalizations { String get containerTrySudoTip => 'Örneğin: Uygulamada kullanıcı aaa olarak ayarlanmış, ancak Docker root kullanıcısı altında kurulmuş. Bu durumda bu seçeneği etkinleştirmeniz gerekir.'; + @override + String get containerSudoPasswordRequired => + 'Docker\'e erişmek için sudo şifresi gereklidir. Lütfen şifrenizi girin.'; + + @override + String get containerSudoPasswordIncorrect => + 'Sudo şifresi yanlış veya izin verilmiyor. Lütfen tekrar deneyin.'; + @override String get convert => 'Dönüştür'; diff --git a/lib/generated/l10n/l10n_uk.dart b/lib/generated/l10n/l10n_uk.dart index 85047a15..15f0f2bc 100644 --- a/lib/generated/l10n/l10n_uk.dart +++ b/lib/generated/l10n/l10n_uk.dart @@ -202,6 +202,14 @@ class AppLocalizationsUk extends AppLocalizations { String get containerTrySudoTip => 'Наприклад: У застосунку користувач це aaa, але Docker встановлений під користувачем root. У цьому випадку вам потрібно активувати цю опцію.'; + @override + String get containerSudoPasswordRequired => + 'Для доступу до Docker потрібен пароль sudo. Будь ласка, введіть ваш пароль.'; + + @override + String get containerSudoPasswordIncorrect => + 'Пароль sudo неправильний або не дозволений. Будь ласка, спробуйте ще раз.'; + @override String get convert => 'Конвертувати'; diff --git a/lib/generated/l10n/l10n_zh.dart b/lib/generated/l10n/l10n_zh.dart index e3805d2a..5faba05b 100644 --- a/lib/generated/l10n/l10n_zh.dart +++ b/lib/generated/l10n/l10n_zh.dart @@ -192,6 +192,12 @@ class AppLocalizationsZh extends AppLocalizations { String get containerTrySudoTip => '例如:在应用内将用户设置为 aaa,但是 Docker 安装在root用户下,这时就需要启用此选项'; + @override + String get containerSudoPasswordRequired => '需要 sudo 密码才能访问 Docker。请输入您的密码。'; + + @override + String get containerSudoPasswordIncorrect => 'sudo 密码错误或无权限。请重试。'; + @override String get convert => '转换'; @@ -1182,6 +1188,12 @@ class AppLocalizationsZhTw extends AppLocalizationsZh { String get containerTrySudoTip => '例如:App 內設定使用者為 aaa,但是 Docker 安裝在 root 使用者,這時就需要開啟此選項'; + @override + String get containerSudoPasswordRequired => '需要 sudo 密碼才能存取 Docker。請輸入您的密碼。'; + + @override + String get containerSudoPasswordIncorrect => 'sudo 密碼錯誤或無權限。請重試。'; + @override String get convert => '轉換'; diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index ac45c9b3..92941f1a 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -58,6 +58,8 @@ "connectionStatsDesc": "Server-Verbindungserfolgsrate und Verlauf anzeigen", "container": "Container", "containerTrySudoTip": "Zum Beispiel: In der App ist der Benutzer auf aaa eingestellt, aber Docker ist unter dem Root-Benutzer installiert. In diesem Fall müssen Sie diese Option aktivieren", + "containerSudoPasswordRequired": "Ein sudo-Passwort ist erforderlich, um auf Docker zuzugreifen. Bitte geben Sie Ihr Passwort ein.", + "containerSudoPasswordIncorrect": "Das sudo-Passwort ist falsch oder nicht erlaubt. Bitte versuchen Sie es erneut.", "convert": "Konvertieren", "copyPath": "Pfad kopieren", "cpuViewAsProgressTip": "Zeigen Sie die Auslastung jedes CPUs in einem Fortschrittsbalken-Stil an (alter Stil)", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 0a40e91b..2e6c5e79 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -47,7 +47,7 @@ "clearServerStatsTitle": "Clear {serverName} Statistics", "clearThisServerStats": "Clear This Server Statistics", "compactDatabase": "Compact Database", - "compactDatabaseContent": "Database size: {size}\n\nThis will rebuild the whole database to reduce file size.", + "compactDatabaseContent": "Database size: {size}\n\nThis will reorganize the database to reduce file size. No data will be deleted.", "confirm": "Confirm", "closeAfterSave": "Save and close", "cmd": "Command", @@ -58,6 +58,8 @@ "connectionStatsDesc": "View server connection success rate and history", "container": "Container", "containerTrySudoTip": "For example: In the app, the user is set to aaa, but Docker is installed under the root user. In this case, you need to enable this option.", + "containerSudoPasswordRequired": "Sudo password is required to access Docker. Please enter your password.", + "containerSudoPasswordIncorrect": "Sudo password is incorrect or not allowed. Please try again.", "convert": "Convert", "copyPath": "Copy path", "cpuViewAsProgressTip": "Display the usage of each CPU in a progress bar style (old style)", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 536c5b17..3033b158 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -57,6 +57,8 @@ "connectionStatsDesc": "Ver la tasa de éxito de conexión del servidor e historial", "container": "Contenedor", "containerTrySudoTip": "Por ejemplo: si configuras el usuario dentro de la app como aaa, pero Docker está instalado bajo el usuario root, entonces necesitarás habilitar esta opción", + "containerSudoPasswordRequired": "Se requiere contraseña de sudo para acceder a Docker. Por favor ingrese su contraseña.", + "containerSudoPasswordIncorrect": "La contraseña de sudo es incorrecta o no está permitida. Por favor intente de nuevo.", "convert": "Convertir", "copyPath": "Copiar ruta", "cpuViewAsProgressTip": "Muestre la tasa de uso de cada CPU en estilo de barra de progreso (estilo antiguo)", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 402ab2d6..eda94e15 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -57,6 +57,8 @@ "connectionStatsDesc": "Voir le taux de réussite de connexion du serveur et l'historique", "container": "Conteneur", "containerTrySudoTip": "Par exemple : Dans l'application, l'utilisateur est défini comme aaa, mais Docker est installé sous l'utilisateur root. Dans ce cas, vous devez activer cette option.", + "containerSudoPasswordRequired": "Un mot de passe sudo est requis pour accéder à Docker. Veuillez entrer votre mot de passe.", + "containerSudoPasswordIncorrect": "Le mot de passe sudo est incorrect ou non autorisé. Veuillez réessayer.", "convert": "Convertir", "copyPath": "Copier le chemin", "cpuViewAsProgressTip": "Afficher le taux d'utilisation de chaque CPU sous forme de barre de progression (ancien style)", diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index f6e776d4..bc22570b 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -57,6 +57,8 @@ "connectionStatsDesc": "Lihat tingkat keberhasilan koneksi server dan riwayat", "container": "Wadah", "containerTrySudoTip": "Contohnya: Di dalam aplikasi, pengguna diatur sebagai aaa, tetapi Docker diinstal di bawah pengguna root. Dalam kasus ini, Anda perlu mengaktifkan opsi ini.", + "containerSudoPasswordRequired": "Kata sandi sudo diperlukan untuk mengakses Docker. Silakan masukkan kata sandi Anda.", + "containerSudoPasswordIncorrect": "Kata sandi sudo salah atau tidak diizinkan. Silakan coba lagi.", "convert": "Mengubah", "copyPath": "Path Copy", "cpuViewAsProgressTip": "Tampilkan tingkat penggunaan setiap CPU dalam gaya bilah kemajuan (gaya lama)", diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 4c90947e..cf4d527a 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -57,6 +57,8 @@ "connectionStatsDesc": "サーバー接続成功率と履歴を表示", "container": "コンテナ", "containerTrySudoTip": "例:アプリ内でユーザーをaaaに設定しているが、Dockerがrootユーザーでインストールされている場合、このオプションを有効にする必要があります", + "containerSudoPasswordRequired": "Dockerにアクセスするにはsudoパスワードが必要です。パスワードを入力してください。", + "containerSudoPasswordIncorrect": "sudoパスワードが正しくないか、許可されていません。再試行してください。", "convert": "変換", "copyPath": "パスをコピー", "cpuViewAsProgressTip": "各CPUの使用率をプログレスバースタイルで表示する(旧スタイル)", diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index a579fc06..fc0111fb 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -57,6 +57,8 @@ "connectionStatsDesc": "Bekijk server verbindingssucces ratio en geschiedenis", "container": "Container", "containerTrySudoTip": "Bijvoorbeeld: in de app is de gebruiker ingesteld op aaa, maar Docker is geïnstalleerd onder de rootgebruiker. In dit geval moet u deze optie inschakelen.", + "containerSudoPasswordRequired": "Een sudo-wachtwoord is vereist om toegang te krijgen tot Docker. Voer uw wachtwoord in.", + "containerSudoPasswordIncorrect": "Het sudo-wachtwoord is onjuist of niet toegestaan. Probeer het opnieuw.", "convert": "Converteren", "copyPath": "Pad kopiëren", "cpuViewAsProgressTip": "Toon het gebruik van elke CPU in een voortgangsbalkstijl (oude stijl)", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index a2589770..8517b32e 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -57,6 +57,8 @@ "connectionStatsDesc": "Ver taxa de sucesso de conexão do servidor e histórico", "container": "Contêiner", "containerTrySudoTip": "Por exemplo: se o usuário for definido como aaa dentro do app, mas o Docker estiver instalado sob o usuário root, esta opção precisará ser ativada", + "containerSudoPasswordRequired": "É necessária uma senha sudo para acessar o Docker. Por favor, insira sua senha.", + "containerSudoPasswordIncorrect": "A senha sudo está incorreta ou não é permitida. Por favor, tente novamente.", "convert": "Converter", "copyPath": "Copiar caminho", "cpuViewAsProgressTip": "Exiba a taxa de uso de cada CPU em estilo de barra de progresso (estilo antigo)", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index ee3268ae..5c52e0a4 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -58,6 +58,8 @@ "connectionStatsDesc": "Просмотр коэффициента успешности подключения к серверу и истории", "container": "Контейнер", "containerTrySudoTip": "Например: если пользователь в приложении установлен как aaa, но Docker установлен под пользователем root, тогда нужно включить эту опцию", + "containerSudoPasswordRequired": "Для доступа к Docker требуется пароль sudo. Пожалуйста, введите ваш пароль.", + "containerSudoPasswordIncorrect": "Пароль sudo неверен или не разрешён. Пожалуйста, попробуйте снова.", "convert": "Конвертировать", "copyPath": "Копировать путь", "cpuViewAsProgressTip": "Отобразите уровень использования каждого процессора в виде индикатора выполнения (старый стиль)", diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index ece319b7..ce3b1c94 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -57,6 +57,8 @@ "connectionStatsDesc": "Sunucu bağlantı başarı oranını ve geçmişi görüntüle", "container": "Konteyner", "containerTrySudoTip": "Örneğin: Uygulamada kullanıcı aaa olarak ayarlanmış, ancak Docker root kullanıcısı altında kurulmuş. Bu durumda bu seçeneği etkinleştirmeniz gerekir.", + "containerSudoPasswordRequired": "Docker'e erişmek için sudo şifresi gereklidir. Lütfen şifrenizi girin.", + "containerSudoPasswordIncorrect": "Sudo şifresi yanlış veya izin verilmiyor. Lütfen tekrar deneyin.", "convert": "Dönüştür", "copyPath": "Yolu kopyala", "cpuViewAsProgressTip": "Her CPU'nun kullanımını ilerleme çubuğu tarzında göster (eski tarz)", diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 244dced6..4049af95 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -57,6 +57,8 @@ "connectionStatsDesc": "Переглянути коефіцієнт успішності підключення до сервера та історію", "container": "Контейнер", "containerTrySudoTip": "Наприклад: У застосунку користувач це aaa, але Docker встановлений під користувачем root. У цьому випадку вам потрібно активувати цю опцію.", + "containerSudoPasswordRequired": "Для доступу до Docker потрібен пароль sudo. Будь ласка, введіть ваш пароль.", + "containerSudoPasswordIncorrect": "Пароль sudo неправильний або не дозволений. Будь ласка, спробуйте ще раз.", "convert": "Конвертувати", "copyPath": "Скопіювати шлях", "cpuViewAsProgressTip": "Відобразити використання кожного процесора у вигляді стовпчикової діаграми (старий стиль)", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 24ea01c6..fa5ef2f5 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -58,6 +58,8 @@ "connectionStatsDesc": "查看服务器连接成功率和历史记录", "container": "容器", "containerTrySudoTip": "例如:在应用内将用户设置为 aaa,但是 Docker 安装在root用户下,这时就需要启用此选项", + "containerSudoPasswordRequired": "需要 sudo 密码才能访问 Docker。请输入您的密码。", + "containerSudoPasswordIncorrect": "sudo 密码错误或无权限。请重试。", "convert": "转换", "copyPath": "复制路径", "cpuViewAsProgressTip": "以进度条样式显示每个 CPU 的使用率(旧版样式)", diff --git a/lib/l10n/app_zh_tw.arb b/lib/l10n/app_zh_tw.arb index 31f82c27..479ae29c 100644 --- a/lib/l10n/app_zh_tw.arb +++ b/lib/l10n/app_zh_tw.arb @@ -57,6 +57,8 @@ "connectionStatsDesc": "檢視伺服器連線成功率和歷史記錄", "container": "容器", "containerTrySudoTip": "例如:App 內設定使用者為 aaa,但是 Docker 安裝在 root 使用者,這時就需要開啟此選項", + "containerSudoPasswordRequired": "需要 sudo 密碼才能存取 Docker。請輸入您的密碼。", + "containerSudoPasswordIncorrect": "sudo 密碼錯誤或無權限。請重試。", "convert": "轉換", "copyPath": "複製路徑", "cpuViewAsProgressTip": "以進度條樣式顯示每個CPU的使用率(舊版樣式)",