починил 2фа
This commit is contained in:
@@ -621,15 +621,17 @@ class AccountModule {
|
||||
String? hint,
|
||||
}) async {
|
||||
_ensureOnline();
|
||||
final capabilities = <int>[0, if (hint != null) 3, 4];
|
||||
final payload = <dynamic, dynamic>{
|
||||
'expectedCapabilities': [0, 3, 4],
|
||||
'expectedCapabilities': capabilities,
|
||||
'trackId': trackId,
|
||||
'password': password,
|
||||
};
|
||||
if (hint != null) payload['hint'] = hint;
|
||||
final packet = await _api.sendRequest(Opcode.authSet2fa, payload);
|
||||
_checkPacketError(packet, 'confirm2fa');
|
||||
return _processProfileUpdate(packet);
|
||||
return _processProfileUpdate(
|
||||
_api.sendRequest(Opcode.authSet2fa, payload),
|
||||
'confirm2fa',
|
||||
);
|
||||
}
|
||||
|
||||
// 2FA Management (when already set)
|
||||
@@ -707,15 +709,16 @@ class AccountModule {
|
||||
}
|
||||
|
||||
final payload = <dynamic, dynamic>{
|
||||
'expectedCapabilities': [1, 3],
|
||||
'expectedCapabilities': <int>[1, if (hint != null) 3],
|
||||
'trackId': trackId,
|
||||
'password': newPassword,
|
||||
};
|
||||
if (hint != null) payload['hint'] = hint;
|
||||
|
||||
final packet = await _api.sendRequest(Opcode.authSet2fa, payload);
|
||||
_checkPacketError(packet, 'update2faPassword');
|
||||
return _processProfileUpdate(packet);
|
||||
return _processProfileUpdate(
|
||||
_api.sendRequest(Opcode.authSet2fa, payload),
|
||||
'update2faPassword',
|
||||
);
|
||||
}
|
||||
|
||||
Future<ProfileData> update2faEmail({
|
||||
@@ -740,9 +743,10 @@ class AccountModule {
|
||||
'expectedCapabilities': [4],
|
||||
'trackId': trackId,
|
||||
};
|
||||
final packet = await _api.sendRequest(Opcode.authSet2fa, payload);
|
||||
_checkPacketError(packet, 'update2faEmail');
|
||||
return _processProfileUpdate(packet);
|
||||
return _processProfileUpdate(
|
||||
_api.sendRequest(Opcode.authSet2fa, payload),
|
||||
'update2faEmail',
|
||||
);
|
||||
}
|
||||
|
||||
Future<ProfileData> remove2fa(String trackId) async {
|
||||
@@ -752,34 +756,46 @@ class AccountModule {
|
||||
'trackId': trackId,
|
||||
'remove2fa': true,
|
||||
};
|
||||
final packet = await _api.sendRequest(Opcode.authSet2fa, payload);
|
||||
_checkPacketError(packet, 'remove2fa');
|
||||
return _processProfileUpdate(packet);
|
||||
return _processProfileUpdate(
|
||||
_api.sendRequest(Opcode.authSet2fa, payload),
|
||||
'remove2fa',
|
||||
);
|
||||
}
|
||||
|
||||
Future<ProfileData> _processProfileUpdate(Packet packet) async {
|
||||
_api.registerPushHandler(Opcode.notifProfile, (p) {});
|
||||
try {
|
||||
await for (final push in _api.pushStream
|
||||
.where((p) => p.opcode == Opcode.notifProfile)
|
||||
.timeout(const Duration(seconds: 15))) {
|
||||
final payload = push.payload;
|
||||
if (payload is Map) {
|
||||
final profile = payload['profile'];
|
||||
if (profile is Map) {
|
||||
final contact = profile['contact'];
|
||||
if (contact is Map) {
|
||||
return ProfileData.fromServerMap(contact.cast<dynamic, dynamic>());
|
||||
}
|
||||
}
|
||||
}
|
||||
Future<ProfileData> _processProfileUpdate(
|
||||
Future<Packet> requestFuture,
|
||||
String tag,
|
||||
) async {
|
||||
final completer = Completer<ProfileData>();
|
||||
final sub = _api.pushStream
|
||||
.where((p) => p.opcode == Opcode.notifProfile)
|
||||
.listen((push) {
|
||||
if (completer.isCompleted) return;
|
||||
final payload = push.payload;
|
||||
if (payload is! Map) return;
|
||||
final profile = payload['profile'];
|
||||
if (profile is! Map) return;
|
||||
final contact = profile['contact'];
|
||||
if (contact is! Map) return;
|
||||
completer.complete(
|
||||
ProfileData.fromServerMap(contact.cast<dynamic, dynamic>()),
|
||||
);
|
||||
});
|
||||
final timer = Timer(const Duration(seconds: 15), () {
|
||||
if (!completer.isCompleted) {
|
||||
completer.completeError(
|
||||
Exception('Таймаут ожидания обновления профиля'),
|
||||
);
|
||||
}
|
||||
} on TimeoutException {
|
||||
throw Exception('Таймаут ожидания обновления профиля');
|
||||
});
|
||||
try {
|
||||
final packet = await requestFuture;
|
||||
_checkPacketError(packet, tag);
|
||||
return await completer.future;
|
||||
} finally {
|
||||
_api.unregisterPushHandler(Opcode.notifProfile);
|
||||
timer.cancel();
|
||||
await sub.cancel();
|
||||
}
|
||||
throw Exception('Не удалось получить обновлённый профиль');
|
||||
}
|
||||
|
||||
Future<RequestCodeResult> requestCode(
|
||||
|
||||
@@ -564,18 +564,9 @@ class _TwoFactorSetupScreenState extends State<TwoFactorSetupScreen> {
|
||||
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 14),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
_PasswordField(
|
||||
controller: _passwordController,
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Введите пароль',
|
||||
filled: true,
|
||||
fillColor: cs.surfaceContainerHighest,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
),
|
||||
hintText: 'Введите пароль',
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -599,18 +590,9 @@ class _TwoFactorSetupScreenState extends State<TwoFactorSetupScreen> {
|
||||
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 14),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
_PasswordField(
|
||||
controller: _passwordController,
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Повторите пароль',
|
||||
filled: true,
|
||||
fillColor: cs.surfaceContainerHighest,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
),
|
||||
hintText: 'Повторите пароль',
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -818,18 +800,9 @@ class _TwoFactorManageScreenState extends State<TwoFactorManageScreen> {
|
||||
style: TextStyle(color: cs.onErrorContainer),
|
||||
),
|
||||
),
|
||||
TextField(
|
||||
_PasswordField(
|
||||
controller: _passwordController,
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Пароль',
|
||||
filled: true,
|
||||
fillColor: cs.surfaceContainerHighest,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
),
|
||||
hintText: 'Пароль',
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
SizedBox(
|
||||
@@ -1035,18 +1008,9 @@ class _TwoFactorPasswordChangeScreenState
|
||||
style: TextStyle(color: cs.onErrorContainer),
|
||||
),
|
||||
),
|
||||
TextField(
|
||||
_PasswordField(
|
||||
controller: _passwordController,
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Введите новый пароль',
|
||||
filled: true,
|
||||
fillColor: cs.surfaceContainerHighest,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
),
|
||||
hintText: 'Введите новый пароль',
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
@@ -1216,18 +1180,9 @@ class _TwoFactorEmailChangeScreenState
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
_PasswordField(
|
||||
controller: _passwordController,
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Пароль',
|
||||
filled: true,
|
||||
fillColor: cs.surfaceContainerHighest,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
),
|
||||
hintText: 'Пароль',
|
||||
),
|
||||
] else ...[
|
||||
if (_errorMessage != null)
|
||||
@@ -1440,18 +1395,9 @@ class _TwoFactorRemoveScreenState extends State<TwoFactorRemoveScreen> {
|
||||
style: TextStyle(color: cs.onErrorContainer),
|
||||
),
|
||||
),
|
||||
TextField(
|
||||
_PasswordField(
|
||||
controller: _passwordController,
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Пароль',
|
||||
filled: true,
|
||||
fillColor: cs.surfaceContainerHighest,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
),
|
||||
hintText: 'Пароль',
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
SizedBox(
|
||||
@@ -1484,3 +1430,45 @@ class _TwoFactorRemoveScreenState extends State<TwoFactorRemoveScreen> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PasswordField extends StatefulWidget {
|
||||
final TextEditingController controller;
|
||||
final String hintText;
|
||||
|
||||
const _PasswordField({
|
||||
required this.controller,
|
||||
required this.hintText,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_PasswordField> createState() => _PasswordFieldState();
|
||||
}
|
||||
|
||||
class _PasswordFieldState extends State<_PasswordField> {
|
||||
bool _visible = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final cs = Theme.of(context).colorScheme;
|
||||
return TextField(
|
||||
controller: widget.controller,
|
||||
obscureText: !_visible,
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.hintText,
|
||||
filled: true,
|
||||
fillColor: cs.surfaceContainerHighest,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_visible ? Symbols.visibility_off : Symbols.visibility,
|
||||
color: cs.onSurfaceVariant,
|
||||
),
|
||||
onPressed: () => setState(() => _visible = !_visible),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user