починил 2фа
This commit is contained in:
@@ -621,15 +621,17 @@ class AccountModule {
|
|||||||
String? hint,
|
String? hint,
|
||||||
}) async {
|
}) async {
|
||||||
_ensureOnline();
|
_ensureOnline();
|
||||||
|
final capabilities = <int>[0, if (hint != null) 3, 4];
|
||||||
final payload = <dynamic, dynamic>{
|
final payload = <dynamic, dynamic>{
|
||||||
'expectedCapabilities': [0, 3, 4],
|
'expectedCapabilities': capabilities,
|
||||||
'trackId': trackId,
|
'trackId': trackId,
|
||||||
'password': password,
|
'password': password,
|
||||||
};
|
};
|
||||||
if (hint != null) payload['hint'] = hint;
|
if (hint != null) payload['hint'] = hint;
|
||||||
final packet = await _api.sendRequest(Opcode.authSet2fa, payload);
|
return _processProfileUpdate(
|
||||||
_checkPacketError(packet, 'confirm2fa');
|
_api.sendRequest(Opcode.authSet2fa, payload),
|
||||||
return _processProfileUpdate(packet);
|
'confirm2fa',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2FA Management (when already set)
|
// 2FA Management (when already set)
|
||||||
@@ -707,15 +709,16 @@ class AccountModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final payload = <dynamic, dynamic>{
|
final payload = <dynamic, dynamic>{
|
||||||
'expectedCapabilities': [1, 3],
|
'expectedCapabilities': <int>[1, if (hint != null) 3],
|
||||||
'trackId': trackId,
|
'trackId': trackId,
|
||||||
'password': newPassword,
|
'password': newPassword,
|
||||||
};
|
};
|
||||||
if (hint != null) payload['hint'] = hint;
|
if (hint != null) payload['hint'] = hint;
|
||||||
|
|
||||||
final packet = await _api.sendRequest(Opcode.authSet2fa, payload);
|
return _processProfileUpdate(
|
||||||
_checkPacketError(packet, 'update2faPassword');
|
_api.sendRequest(Opcode.authSet2fa, payload),
|
||||||
return _processProfileUpdate(packet);
|
'update2faPassword',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ProfileData> update2faEmail({
|
Future<ProfileData> update2faEmail({
|
||||||
@@ -740,9 +743,10 @@ class AccountModule {
|
|||||||
'expectedCapabilities': [4],
|
'expectedCapabilities': [4],
|
||||||
'trackId': trackId,
|
'trackId': trackId,
|
||||||
};
|
};
|
||||||
final packet = await _api.sendRequest(Opcode.authSet2fa, payload);
|
return _processProfileUpdate(
|
||||||
_checkPacketError(packet, 'update2faEmail');
|
_api.sendRequest(Opcode.authSet2fa, payload),
|
||||||
return _processProfileUpdate(packet);
|
'update2faEmail',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ProfileData> remove2fa(String trackId) async {
|
Future<ProfileData> remove2fa(String trackId) async {
|
||||||
@@ -752,34 +756,46 @@ class AccountModule {
|
|||||||
'trackId': trackId,
|
'trackId': trackId,
|
||||||
'remove2fa': true,
|
'remove2fa': true,
|
||||||
};
|
};
|
||||||
final packet = await _api.sendRequest(Opcode.authSet2fa, payload);
|
return _processProfileUpdate(
|
||||||
_checkPacketError(packet, 'remove2fa');
|
_api.sendRequest(Opcode.authSet2fa, payload),
|
||||||
return _processProfileUpdate(packet);
|
'remove2fa',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ProfileData> _processProfileUpdate(Packet packet) async {
|
Future<ProfileData> _processProfileUpdate(
|
||||||
_api.registerPushHandler(Opcode.notifProfile, (p) {});
|
Future<Packet> requestFuture,
|
||||||
try {
|
String tag,
|
||||||
await for (final push in _api.pushStream
|
) async {
|
||||||
.where((p) => p.opcode == Opcode.notifProfile)
|
final completer = Completer<ProfileData>();
|
||||||
.timeout(const Duration(seconds: 15))) {
|
final sub = _api.pushStream
|
||||||
final payload = push.payload;
|
.where((p) => p.opcode == Opcode.notifProfile)
|
||||||
if (payload is Map) {
|
.listen((push) {
|
||||||
final profile = payload['profile'];
|
if (completer.isCompleted) return;
|
||||||
if (profile is Map) {
|
final payload = push.payload;
|
||||||
final contact = profile['contact'];
|
if (payload is! Map) return;
|
||||||
if (contact is Map) {
|
final profile = payload['profile'];
|
||||||
return ProfileData.fromServerMap(contact.cast<dynamic, dynamic>());
|
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 {
|
} finally {
|
||||||
_api.unregisterPushHandler(Opcode.notifProfile);
|
timer.cancel();
|
||||||
|
await sub.cancel();
|
||||||
}
|
}
|
||||||
throw Exception('Не удалось получить обновлённый профиль');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<RequestCodeResult> requestCode(
|
Future<RequestCodeResult> requestCode(
|
||||||
|
|||||||
@@ -564,18 +564,9 @@ class _TwoFactorSetupScreenState extends State<TwoFactorSetupScreen> {
|
|||||||
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 14),
|
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 14),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextField(
|
_PasswordField(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
obscureText: true,
|
hintText: 'Введите пароль',
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Введите пароль',
|
|
||||||
filled: true,
|
|
||||||
fillColor: cs.surfaceContainerHighest,
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -599,18 +590,9 @@ class _TwoFactorSetupScreenState extends State<TwoFactorSetupScreen> {
|
|||||||
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 14),
|
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 14),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextField(
|
_PasswordField(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
obscureText: true,
|
hintText: 'Повторите пароль',
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Повторите пароль',
|
|
||||||
filled: true,
|
|
||||||
fillColor: cs.surfaceContainerHighest,
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -818,18 +800,9 @@ class _TwoFactorManageScreenState extends State<TwoFactorManageScreen> {
|
|||||||
style: TextStyle(color: cs.onErrorContainer),
|
style: TextStyle(color: cs.onErrorContainer),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextField(
|
_PasswordField(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
obscureText: true,
|
hintText: 'Пароль',
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Пароль',
|
|
||||||
filled: true,
|
|
||||||
fillColor: cs.surfaceContainerHighest,
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@@ -1035,18 +1008,9 @@ class _TwoFactorPasswordChangeScreenState
|
|||||||
style: TextStyle(color: cs.onErrorContainer),
|
style: TextStyle(color: cs.onErrorContainer),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextField(
|
_PasswordField(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
obscureText: true,
|
hintText: 'Введите новый пароль',
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Введите новый пароль',
|
|
||||||
filled: true,
|
|
||||||
fillColor: cs.surfaceContainerHighest,
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
Text(
|
Text(
|
||||||
@@ -1216,18 +1180,9 @@ class _TwoFactorEmailChangeScreenState
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextField(
|
_PasswordField(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
obscureText: true,
|
hintText: 'Пароль',
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Пароль',
|
|
||||||
filled: true,
|
|
||||||
fillColor: cs.surfaceContainerHighest,
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
] else ...[
|
] else ...[
|
||||||
if (_errorMessage != null)
|
if (_errorMessage != null)
|
||||||
@@ -1440,18 +1395,9 @@ class _TwoFactorRemoveScreenState extends State<TwoFactorRemoveScreen> {
|
|||||||
style: TextStyle(color: cs.onErrorContainer),
|
style: TextStyle(color: cs.onErrorContainer),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextField(
|
_PasswordField(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
obscureText: true,
|
hintText: 'Пароль',
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Пароль',
|
|
||||||
filled: true,
|
|
||||||
fillColor: cs.surfaceContainerHighest,
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
SizedBox(
|
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