diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart
index 0ba42a0d0..efac6e106 100644
--- a/lib/generated/intl/messages_en.dart
+++ b/lib/generated/intl/messages_en.dart
@@ -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 terms of service and privacy policy"),
"singleFileDeleteFromDevice": m49,
diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart
index 9dbddb101..e0af479e3 100644
--- a/lib/generated/l10n.dart
+++ b/lib/generated/l10n.dart
@@ -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 {
diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb
index 39ff3f697..18943691e 100644
--- a/lib/l10n/intl_en.arb
+++ b/lib/l10n/intl_en.arb
@@ -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"
}
\ No newline at end of file
diff --git a/lib/services/user_service.dart b/lib/services/user_service.dart
index e52a69984..6fb418aae 100644
--- a/lib/services/user_service.dart
+++ b/lib/services/user_service.dart
@@ -502,6 +502,7 @@ class UserService {
Future 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 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);
diff --git a/lib/ui/account/password_entry_page.dart b/lib/ui/account/password_entry_page.dart
index 11889c76e..f148ef21e 100644
--- a/lib/ui/account/password_entry_page.dart
+++ b/lib/ui/account/password_entry_page.dart
@@ -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 createState() => _PasswordEntryPageState();
@@ -379,13 +382,18 @@ class _PasswordEntryPageState extends State {
}
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 {
}
}
+ Future 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 _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 {
diff --git a/pubspec.yaml b/pubspec.yaml
index 8012c5d68..991043101 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -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"