Change Password: Confirm before signing out from other devices (#1542)

This commit is contained in:
Neeraj Gupta 2023-11-26 16:20:29 +05:30 committed by GitHub
commit 6763a42fc6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 98 additions and 10 deletions

View file

@ -564,6 +564,7 @@ class MessageLookup extends MessageLookupByLibrary {
"discord": MessageLookupByLibrary.simpleMessage("Discord"),
"dismiss": MessageLookupByLibrary.simpleMessage("Dismiss"),
"distanceInKMUnit": MessageLookupByLibrary.simpleMessage("km"),
"doNotSignOut": MessageLookupByLibrary.simpleMessage("Do not sign out"),
"doThisLater": MessageLookupByLibrary.simpleMessage("Do this later"),
"doYouWantToDiscardTheEditsYouHaveMade":
MessageLookupByLibrary.simpleMessage(
@ -1208,6 +1209,12 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Shared with you"),
"sharing": MessageLookupByLibrary.simpleMessage("Sharing..."),
"showMemories": MessageLookupByLibrary.simpleMessage("Show memories"),
"signOutFromOtherDevices":
MessageLookupByLibrary.simpleMessage("Sign out from other devices"),
"signOutOtherBody": MessageLookupByLibrary.simpleMessage(
"If you think someone might know your password, you can force all other devices using your account to sign out."),
"signOutOtherDevices":
MessageLookupByLibrary.simpleMessage("Sign out other devices"),
"signUpTerms": MessageLookupByLibrary.simpleMessage(
"I agree to the <u-terms>terms of service</u-terms> and <u-policy>privacy policy</u-policy>"),
"singleFileDeleteFromDevice": m49,

View file

@ -8097,6 +8097,46 @@ class S {
args: [],
);
}
/// `Sign out from other devices`
String get signOutFromOtherDevices {
return Intl.message(
'Sign out from other devices',
name: 'signOutFromOtherDevices',
desc: '',
args: [],
);
}
/// `If you think someone might know your password, you can force all other devices using your account to sign out.`
String get signOutOtherBody {
return Intl.message(
'If you think someone might know your password, you can force all other devices using your account to sign out.',
name: 'signOutOtherBody',
desc: '',
args: [],
);
}
/// `Sign out other devices`
String get signOutOtherDevices {
return Intl.message(
'Sign out other devices',
name: 'signOutOtherDevices',
desc: '',
args: [],
);
}
/// `Do not sign out`
String get doNotSignOut {
return Intl.message(
'Do not sign out',
name: 'doNotSignOut',
desc: '',
args: [],
);
}
}
class AppLocalizationDelegate extends LocalizationsDelegate<S> {

View file

@ -1152,5 +1152,10 @@
},
"contacts": "Contacts",
"noInternetConnection": "No internet connection",
"pleaseCheckYourInternetConnectionAndTryAgain": "Please check your internet connection and try again."
"pleaseCheckYourInternetConnectionAndTryAgain": "Please check your internet connection and try again.",
"signOutFromOtherDevices": "Sign out from other devices",
"signOutOtherBody": "If you think someone might know your password, you can force all other devices using your account to sign out.",
"signOutOtherDevices": "Sign out other devices",
"doNotSignOut": "Do not sign out"
}

View file

@ -502,6 +502,7 @@ class UserService {
Future<void> registerOrUpdateSrp(
Uint8List loginKey, {
SetKeysRequest? setKeysRequest,
bool logOutOtherDevices = false,
}) async {
try {
final String username = const Uuid().v4().toString();
@ -558,6 +559,7 @@ class UserService {
'setupID': setupSRPResponse.setupID,
'srpM1': base64Encode(SRP6Util.encodeBigInt(clientM!)),
'updatedKeyAttr': setKeysRequest.toMap(),
'logOutOtherDevices': logOutOtherDevices,
},
);
}
@ -676,8 +678,9 @@ class UserService {
Future<void> updateKeyAttributes(
KeyAttributes keyAttributes,
Uint8List loginKey,
) async {
Uint8List loginKey, {
required bool logoutOtherDevices,
}) async {
try {
final setKeyRequest = SetKeysRequest(
kekSalt: keyAttributes.kekSalt,
@ -686,7 +689,11 @@ class UserService {
memLimit: keyAttributes.memLimit!,
opsLimit: keyAttributes.opsLimit!,
);
await registerOrUpdateSrp(loginKey, setKeysRequest: setKeyRequest);
await registerOrUpdateSrp(
loginKey,
setKeysRequest: setKeyRequest,
logOutOtherDevices: logoutOtherDevices,
);
await _config.setKeyAttributes(keyAttributes);
} catch (e) {
_logger.severe(e);

View file

@ -7,11 +7,13 @@ import 'package:photos/core/event_bus.dart';
import 'package:photos/events/account_configured_event.dart';
import 'package:photos/events/subscription_purchased_event.dart';
import "package:photos/generated/l10n.dart";
import "package:photos/l10n/l10n.dart";
import "package:photos/models/key_gen_result.dart";
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/account/recovery_key_page.dart';
import 'package:photos/ui/common/dynamic_fab.dart';
import 'package:photos/ui/common/web_page.dart';
import "package:photos/ui/components/models/button_type.dart";
import 'package:photos/ui/payment/subscription.dart';
import 'package:photos/utils/dialog_util.dart';
import 'package:photos/utils/navigation_util.dart';
@ -27,9 +29,10 @@ enum PasswordEntryMode {
class PasswordEntryPage extends StatefulWidget {
final PasswordEntryMode mode;
const PasswordEntryPage({required this.mode, Key?
key,})
: super(key: key);
const PasswordEntryPage({
required this.mode,
Key? key,
}) : super(key: key);
@override
State<PasswordEntryPage> createState() => _PasswordEntryPageState();
@ -379,13 +382,18 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
}
void _updatePassword() async {
final logOutFromOthers = await logOutFromOtherDevices(context);
final dialog =
createProgressDialog(context, S.of(context).generatingEncryptionKeys);
await dialog.show();
try {
final result = await Configuration.instance
.getAttributesForNewPassword(_passwordController1.text);
await UserService.instance.updateKeyAttributes(result.item1, result.item2);
await UserService.instance.updateKeyAttributes(
result.item1,
result.item2,
logoutOtherDevices: logOutFromOthers,
);
await dialog.hide();
showShortToast(context, S.of(context).passwordChangedSuccessfully);
Navigator.of(context).pop();
@ -400,12 +408,33 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
}
}
Future<bool> logOutFromOtherDevices(BuildContext context) async {
bool logOutFromOther = true;
await showChoiceDialog(
context,
title: context.l10n.signOutFromOtherDevices,
body: context.l10n.signOutOtherBody,
isDismissible: false,
firstButtonLabel: context.l10n.signOutOtherDevices,
firstButtonType: ButtonType.critical,
firstButtonOnTap: () async {
logOutFromOther = true;
},
secondButtonLabel: context.l10n.doNotSignOut,
secondButtonOnTap: () async {
logOutFromOther = false;
},
);
return logOutFromOther;
}
Future<void> _showRecoveryCodeDialog(String password) async {
final dialog =
createProgressDialog(context, S.of(context).generatingEncryptionKeys);
await dialog.show();
try {
final KeyGenResult result = await Configuration.instance.generateKey(password);
final KeyGenResult result =
await Configuration.instance.generateKey(password);
Configuration.instance.setVolatilePassword(null);
await dialog.hide();
onDone() async {

View file

@ -12,7 +12,7 @@ description: ente photos application
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.8.2+522
version: 0.8.3+523
environment:
sdk: ">=3.0.0 <4.0.0"