fix: честные ошибки при вводе пароля и дубликат в Keychain
This commit is contained in:
@@ -488,7 +488,7 @@ class AccountModule {
|
||||
final data = _requireMapPayload(packet, 'checkPassword');
|
||||
|
||||
if (data['error'] != null) {
|
||||
throw Exception('checkPassword: неверный пароль');
|
||||
throw const WrongPasswordException();
|
||||
}
|
||||
|
||||
final tokenAttrs = data['tokenAttrs'];
|
||||
|
||||
@@ -290,6 +290,12 @@ class WrongDeviceTokenException implements Exception {
|
||||
String toString() => 'WrongDeviceTokenException';
|
||||
}
|
||||
|
||||
class WrongPasswordException implements Exception {
|
||||
const WrongPasswordException();
|
||||
@override
|
||||
String toString() => 'WrongPasswordException';
|
||||
}
|
||||
|
||||
class RequestCodeResult {
|
||||
final String token;
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ class TwoFactorModule extends AccountApiBase {
|
||||
checkPacketError(packet, 'check2faPassword');
|
||||
final data = packet.payload;
|
||||
if (data is Map && data['error'] != null) {
|
||||
throw Exception('Неверный пароль');
|
||||
throw const WrongPasswordException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:flutter/services.dart' show PlatformException;
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
@@ -14,10 +15,25 @@ class TokenStorage {
|
||||
mOptions: MacOsOptions(usesDataProtectionKeychain: false),
|
||||
);
|
||||
|
||||
static Future<void> writeSecure(String key, String value) async {
|
||||
await _secure.write(key: key, value: value);
|
||||
static const int _duplicateKeychainItem = -25299;
|
||||
|
||||
static bool _isDuplicateItem(PlatformException error) =>
|
||||
error.details == _duplicateKeychainItem ||
|
||||
(error.message?.contains('$_duplicateKeychainItem') ?? false);
|
||||
|
||||
static Future<void> _write(String key, String value) async {
|
||||
try {
|
||||
await _secure.write(key: key, value: value);
|
||||
} on PlatformException catch (e) {
|
||||
if (!_isDuplicateItem(e)) rethrow;
|
||||
await _secure.delete(key: key);
|
||||
await _secure.write(key: key, value: value);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> writeSecure(String key, String value) =>
|
||||
_write(key, value);
|
||||
|
||||
static Future<String?> readSecure(String key) async {
|
||||
return _secure.read(key: key);
|
||||
}
|
||||
@@ -31,9 +47,8 @@ class TokenStorage {
|
||||
return all.keys.where((key) => key.startsWith(prefix)).toList();
|
||||
}
|
||||
|
||||
static Future<void> saveToken(String token, int accountId) async {
|
||||
await _secure.write(key: '$_tokenPrefix$accountId', value: token);
|
||||
}
|
||||
static Future<void> saveToken(String token, int accountId) =>
|
||||
_write('$_tokenPrefix$accountId', token);
|
||||
|
||||
static Future<String?> readToken(int accountId) async {
|
||||
final key = '$_tokenPrefix$accountId';
|
||||
@@ -43,7 +58,7 @@ class TokenStorage {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final legacy = prefs.getString(key);
|
||||
if (legacy != null) {
|
||||
await _secure.write(key: key, value: legacy);
|
||||
await _write(key, legacy);
|
||||
await prefs.remove(key);
|
||||
return legacy;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import '../../../backend/modules/account/account_models.dart';
|
||||
import '../../../core/protocol/packet.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import '../../../main.dart';
|
||||
import '../../widgets/animated_slash_icon.dart';
|
||||
import '../../widgets/custom_notification.dart';
|
||||
@@ -101,10 +103,13 @@ class _Password2FAScreenState extends State<Password2FAScreen>
|
||||
_isLoading = false;
|
||||
});
|
||||
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
if (!passed && (isSessionStateError(e) || sessionStale)) {
|
||||
recoverStaleSession();
|
||||
} else if (e is WrongPasswordException) {
|
||||
showCustomNotification(context, l10n.passwordEntryWrongPassword);
|
||||
} else {
|
||||
showCustomNotification(context, 'Неверный пароль: $e');
|
||||
showCustomNotification(context, l10n.devicesGenericError('$e'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import '../../../main.dart' show accountModule;
|
||||
import '../../../backend/modules/account.dart' show TwoFactorDetails;
|
||||
import '../../../core/storage/app_database.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import '../../widgets/animated_slash_icon.dart';
|
||||
@@ -11,6 +10,13 @@ import '../../widgets/primary_loading_button.dart';
|
||||
import '../../widgets/small_spinner.dart';
|
||||
import '../../../core/config/app_fonts.dart';
|
||||
import '../../../core/config/app_shape.dart';
|
||||
import '../../../backend/modules/account/account_models.dart';
|
||||
|
||||
|
||||
String _passwordErrorText(Object error, AppLocalizations l10n) =>
|
||||
error is WrongPasswordException
|
||||
? l10n.passwordEntryWrongPassword
|
||||
: l10n.devicesGenericError('$error');
|
||||
|
||||
class PasswordEntryScreen extends StatefulWidget {
|
||||
const PasswordEntryScreen({super.key});
|
||||
@@ -56,12 +62,13 @@ class _PasswordEntryScreenState extends State<PasswordEntryScreen> {
|
||||
_details = details;
|
||||
});
|
||||
_passwordController.clear();
|
||||
} catch (_) {
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
setState(
|
||||
() => _errorMessage = AppLocalizations.of(
|
||||
context,
|
||||
)!.passwordEntryWrongPassword,
|
||||
() => _errorMessage = _passwordErrorText(
|
||||
e,
|
||||
AppLocalizations.of(context)!,
|
||||
),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
@@ -621,7 +628,14 @@ class _TwoFactorSetupScreenState extends State<TwoFactorSetupScreen> {
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) setState(() => _errorMessage = e.toString());
|
||||
if (mounted) {
|
||||
setState(
|
||||
() => _errorMessage = _passwordErrorText(
|
||||
e,
|
||||
AppLocalizations.of(context)!,
|
||||
),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
_isLoading.value = false;
|
||||
@@ -1011,7 +1025,14 @@ class _TwoFactorPasswordChangeScreenState
|
||||
Navigator.popUntil(context, ModalRoute.withName('SecurityScreen'));
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) setState(() => _errorMessage = e.toString());
|
||||
if (mounted) {
|
||||
setState(
|
||||
() => _errorMessage = _passwordErrorText(
|
||||
e,
|
||||
AppLocalizations.of(context)!,
|
||||
),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) _isLoading.value = false;
|
||||
}
|
||||
@@ -1182,7 +1203,14 @@ class _TwoFactorEmailChangeScreenState
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) setState(() => _errorMessage = e.toString());
|
||||
if (mounted) {
|
||||
setState(
|
||||
() => _errorMessage = _passwordErrorText(
|
||||
e,
|
||||
AppLocalizations.of(context)!,
|
||||
),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) _isLoading.value = false;
|
||||
}
|
||||
@@ -1335,7 +1363,14 @@ class _TwoFactorRemoveScreenState extends State<TwoFactorRemoveScreen> {
|
||||
Navigator.popUntil(context, ModalRoute.withName('SecurityScreen'));
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) setState(() => _errorMessage = e.toString());
|
||||
if (mounted) {
|
||||
setState(
|
||||
() => _errorMessage = _passwordErrorText(
|
||||
e,
|
||||
AppLocalizations.of(context)!,
|
||||
),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) _isLoading.value = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user