diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index 171ef0dd72..33162f80dc 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -1,9 +1,9 @@ { "icons": [ - { "title": "1xBet", - "altNames": ["1x", "1x bet", "1x-bet" - ] - }, + { "title": "1xBet", + "altNames": ["1x", "1x bet", "1x-bet" + ] + }, { "title": "3Commas" }, @@ -14,6 +14,10 @@ { "title": "Airtable" }, + { + "title": "airtm", + "hex": "000000" + }, { "title": "Anycoin Direct", "slug": "anycoindirect" @@ -116,6 +120,9 @@ { "title": "DEGIRO" }, + { + "title": "deriv" + }, { "title": "DirectAdmin" }, @@ -334,8 +341,8 @@ { "title": "Odido" }, - { "title": "okx", - "hex": "858585" }, + { "title": "okx", + "hex": "858585" }, { "title": "Parsec" }, @@ -553,8 +560,8 @@ ], "slug": "Yandex" }, - { "title": "yahoo" }, - { + { "title": "yahoo" }, + { "title": "YNAB", "altNames": [ diff --git a/auth/assets/custom-icons/icons/airtm.svg b/auth/assets/custom-icons/icons/airtm.svg new file mode 100644 index 0000000000..bfef999bac --- /dev/null +++ b/auth/assets/custom-icons/icons/airtm.svg @@ -0,0 +1 @@ + diff --git a/auth/assets/custom-icons/icons/bitget.svg b/auth/assets/custom-icons/icons/bitget.svg index 19b60c978a..845282f0e2 100644 --- a/auth/assets/custom-icons/icons/bitget.svg +++ b/auth/assets/custom-icons/icons/bitget.svg @@ -1,18 +1 @@ - - - - - - - - - - - - - - - - - - + diff --git a/auth/assets/custom-icons/icons/deriv.svg b/auth/assets/custom-icons/icons/deriv.svg new file mode 100644 index 0000000000..41581a265d --- /dev/null +++ b/auth/assets/custom-icons/icons/deriv.svg @@ -0,0 +1 @@ + diff --git a/auth/assets/custom-icons/icons/yahoo.svg b/auth/assets/custom-icons/icons/yahoo.svg index 182be51925..38885c8bb1 100644 --- a/auth/assets/custom-icons/icons/yahoo.svg +++ b/auth/assets/custom-icons/icons/yahoo.svg @@ -1 +1 @@ - + diff --git a/docs/docs/photos/faq/security-and-privacy.md b/docs/docs/photos/faq/security-and-privacy.md index 9dadf8bdf1..3990e2b623 100644 --- a/docs/docs/photos/faq/security-and-privacy.md +++ b/docs/docs/photos/faq/security-and-privacy.md @@ -1,73 +1,77 @@ --- -title: Security and privacy FAQ -description: - Frequently asked questions about security and privacy of Ente Photos +title: Security and Privacy FAQ +description: Comprehensive information about security and privacy measures in Ente Photos --- -# Security and privacy +# Security and Privacy FAQ -## Can Ente see my photos and videos? +Welcome to Ente Photos' Security and Privacy FAQ. This document provides +detailed information about our security practices, privacy measures, and how we +protect your data. We are committed to maintaining the highest standards of data +protection and transparency. -No. +## Data Encryption and Storage -Your files are encrypted with a key before they are uploaded to our servers. +### Can Ente see my photos and videos? +No. Your files are encrypted on your device before being uploaded to our +servers. The encryption keys are derived from your password using advanced key +derivation functions. Since only you know your password, only you can decrypt +your files. For technical details, please see our [architecture +document](https://ente.io/architecture). -These keys can be accessed only with your password. +### How is my data encrypted? +We use the following encryption algorithms: +- Encryption: `XChaCha20` and `XSalsa20` +- Authentication: Poly1305 message authentication code (MAC) +- Key derivation: Argon2id with high memory and computation parameters -Since only you know your password, only you can decrypt your files. +These algorithms are implemented using +[libsodium](https://libsodium.gitbook.io/doc/), a externally audited +cryptographic library. Our [architecture document](https://ente.io/architecture) +provides full technical specifications. -To learn more about our encryption protocol, please read about our -[architecture](https://ente.io/architecture). +### Where is my data stored? +Your encrypted data is stored redundantly across multiple providers in the EU: +- Amsterdam, Netherlands +- Paris, France +- Frankfurt, Germany -## How is my data encrypted? +We use a combination of object storage and distributed databases to ensure high +availability and durability. Our [reliability +document](https://ente.io/reliability) provides in-depth information about our +storage infrastructure and data replication strategies. -We use [libsodium](https://libsodium.gitbook.io/doc/)'s implementations -`XChaCha20` and `XSalsa20` to encrypt your data, along with `Poly1305` MAC for -authentication. +### How does Ente's encryption compare to industry standards? +Our encryption model goes beyond industry standards. While many services use +server-side encryption, we implement end-to-end encryption. This means that even +in the unlikely event of a server breach, your data remains protected. -Please refer to the document on our [architecture](https://ente.io/architecture) -for more details. +## Account Security -## Where is my data stored? +### What happens if I forget my password? +You can reset your password using your recovery key. This key is a randomly +generated string provided to you during account creation. Store it securely, as +it's your lifeline if you forget your password. If you lose both your password +and recovery key, we cannot recover your account or data due to our +zero-knowledge architecture. -Your data is replicated to multiple providers in different countries in the EU. - -Currently we have datacenters in the following locations: - -- Amsterdam, Netherlands -- Paris, France -- Frankfurt, Germany - -Much more details about our replication and reliability are documented -[here](https://ente.io/reliability). - -## What happens if I forget my password? - -You can reset your password with your recovery key. - -If you lose both your password and your recovery key, you will not be able to -decrypt your data. - -## Can I change my password? - -Yes. - -You can change your password from any of our apps. - -Thanks to our [architecture](https://ente.io/architecture), you can do so -without having to re-encrypt any of your files. +### Can I change my password? +Yes, you can change your password at any time from our apps. Our architecture +allows password changes without re-encrypting your entire library. The privacy of your account is a function of the strength of your password, please choose a strong one. -## Do you support 2FA? +### Do you support two-factor authentication (2FA)? +Yes, we recommend enabling 2FA for an additional layer of security. We support: +- Time-based One-Time Passwords (TOTP) +- WebAuthn/FIDO2 for hardware security keys -Yes. +You can set up 2FA in the settings of our mobile or desktop apps. -You can setup two-factor authentication from the settings screen of the mobile -app or from the side bar of our desktop app. +## Sharing and Collaboration -## How does sharing work? +### How does sharing work? The information required to decrypt an album is encrypted with the recipient's public key such that only they can decrypt them. @@ -81,22 +85,31 @@ and is never sent to our servers. Please note that only users on the paid plan are allowed to share albums. The receiver just needs a free Ente account. -## Has the Ente Photos app been audited by a credible source? +## Security Audits +## Has the Ente Photos app been audited by a credible source? Yes, Ente Photos has undergone a thorough security audit conducted by Cure53, in collaboration with Symbolic Software. Cure53 is a prominent German cybersecurity firm, while Symbolic Software specializes in applied cryptography. Please find the full report here: https://ente.io/blog/cryptography-audit/ -## How can I delete my account? +## Account Management + +### How can I delete my account? You can delete your account at any time by using the "Delete account" option in the settings. For security reasons, we request you to delete your account on your own instead of contacting support to ask them to delete your account. -Note that both Ente photos and Ente auth data will be deleted when you delete +Note that both Ente Photos and Ente Auth data will be deleted when you delete your account (irrespective of which app you delete it from) since both photos and auth use the same underlying account. To know details of how your data is deleted, including when you delete your account, please see https://ente.io/blog/how-ente-deletes-data/. + +## Additional Support + +For any security or privacy questions not covered here, please contact our team +at security@ente.io. We're committed to addressing your concerns and +continuously improving our security measures. diff --git a/docs/docs/photos/troubleshooting/sharing-logs.md b/docs/docs/photos/troubleshooting/sharing-logs.md index 3015a691f8..58902f2aab 100644 --- a/docs/docs/photos/troubleshooting/sharing-logs.md +++ b/docs/docs/photos/troubleshooting/sharing-logs.md @@ -5,41 +5,41 @@ description: How to report bugs and share the logs from your Ente Photos app # Sharing debug logs -In some cases when you report a bug, our customer support might request you to -share debug logs from your app to help our developers find the issue. +In some cases when you report an issue, our customer support might request you +to share debug logs from your app to help our developers find the issue. Note that the debug logs contain potentially sensitive information like the file names, so please feel free to not share them if you have any hesitation or want to keep these private. We will try to diagnose the issue even without the logs, the logs just make the process a bit faster and easier. -### Mobile +## Mobile -To **_Report a bug_** on your mobile device, follow these steps: +- Open settings (tap on the three horizontal lines button). +- Tap on _Support_ from the settings. +- Select for the option to _Report a Bug_. +- Tap on _Report a bug_. -- Tap on the three horizontal lines to access the settings. -- Tap on **"Support"** from the settings. -- Select for the option to **"Report a Bug"**. -- Tap on **"Report a bug"** . +## Desktop -### Desktop +- Click on _Help_ menu at the top of your screen, and select the _View logs_ + option. +- Open settings (click on the three horizontal lines button located at the top + left corner of the screen). +- Click on _Support_. This will open your email client where you can attach + the logs in the email and describe the issue. -To **_Report a bug_** on the desktop app, follow these steps: +## Web -- Click on the three horizontal lines located in the top left corner of the - screen to access the settings. -- Click on **"Debug logs"** from the settings. -- Click on **Download logs**. -- Then Click on **"Support"**. -- Attach the downloaded logs in the email and describe the issue. +- Open settings (click on the three horizontal lines button located at the top + left corner of the screen). +- Click on _Debug Logs_ towards the bottom of settings. +- Click on _Download logs_ +- Click on _Support_. This will open your email client where you can attach + the logs in the email and describe the issue. -### Web +## Send email manually -To **_Report a bug_** on the web, follow these steps: - -- Click on the three horizontal lines located in the top left corner of the - screen to access the settings. -- Click on **"Debug Logs"** -- Click on **Download logs** -- Click on **"Support"** from the settings. -- Attach the downloaded logs in the email and describe the issue. +If _Report a bug_ or _Support_ doesn't automatically open your email client, you +can also directly send a mail to support@ente.io. diff --git a/mobile/lib/services/local_authentication_service.dart b/mobile/lib/services/local_authentication_service.dart index a989da5124..fecca7ac70 100644 --- a/mobile/lib/services/local_authentication_service.dart +++ b/mobile/lib/services/local_authentication_service.dart @@ -21,7 +21,11 @@ class LocalAuthenticationService { ) async { if (await _isLocalAuthSupportedOnDevice()) { AppLock.of(context)!.setEnabled(false); - final result = await requestAuthentication(context, infoMessage); + final result = await requestAuthentication( + context, + infoMessage, + isAuthenticatingForInAppChange: true, + ); AppLock.of(context)!.setEnabled( await Configuration.instance.shouldShowLockScreen(), ); @@ -39,15 +43,17 @@ class LocalAuthenticationService { BuildContext context, String? savedPin, String? savedPassword, { - bool isOnOpeningApp = false, + bool isAuthenticatingOnAppLaunch = false, + bool isAuthenticatingForInAppChange = false, }) async { if (savedPassword != null) { final result = await Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) { return LockScreenPassword( - isAuthenticating: true, - isOnOpeningApp: isOnOpeningApp, + isChangingLockScreenSettings: true, + isAuthenticatingForInAppChange: isAuthenticatingForInAppChange, + isAuthenticatingOnAppLaunch: isAuthenticatingOnAppLaunch, authPass: savedPassword, ); }, @@ -62,8 +68,9 @@ class LocalAuthenticationService { MaterialPageRoute( builder: (BuildContext context) { return LockScreenPin( - isAuthenticating: true, - isOnOpeningApp: isOnOpeningApp, + isChangingLockScreenSettings: true, + isAuthenticatingForInAppChange: isAuthenticatingForInAppChange, + isAuthenticatingOnAppLaunch: isAuthenticatingOnAppLaunch, authPin: savedPin, ); }, diff --git a/mobile/lib/ui/settings/lock_screen/lock_screen_password.dart b/mobile/lib/ui/settings/lock_screen/lock_screen_password.dart index bdce585a40..5341f21b66 100644 --- a/mobile/lib/ui/settings/lock_screen/lock_screen_password.dart +++ b/mobile/lib/ui/settings/lock_screen/lock_screen_password.dart @@ -16,14 +16,24 @@ import "package:photos/utils/lock_screen_settings.dart"; class LockScreenPassword extends StatefulWidget { const LockScreenPassword({ super.key, - this.isAuthenticating = false, - this.isOnOpeningApp = false, + this.isChangingLockScreenSettings = false, + this.isAuthenticatingOnAppLaunch = false, + this.isAuthenticatingForInAppChange = false, this.authPass, }); - //Is false when setting a new password - final bool isAuthenticating; - final bool isOnOpeningApp; + /// [isChangingLockScreenSettings] Authentication required for changing lock screen settings. + /// Set to true when the app requires the user to authenticate before allowing + /// changes to the lock screen settings. + final bool isChangingLockScreenSettings; + + /// [isAuthenticatingOnAppLaunch] Authentication required on app launch. + /// Set to true when the app requires the user to authenticate immediately upon opening. + final bool isAuthenticatingOnAppLaunch; + + /// [isAuthenticatingForInAppChange] Authentication required for in-app changes (e.g., email, password). + /// Set to true when the app requires the to authenticate for sensitive actions like email, password changes. + final bool isAuthenticatingForInAppChange; final String? authPass; @override State createState() => _LockScreenPasswordState(); @@ -155,7 +165,7 @@ class _LockScreenPasswordState extends State { ), ), Text( - widget.isAuthenticating + widget.isChangingLockScreenSettings ? S.of(context).enterPassword : S.of(context).setNewPassword, textAlign: TextAlign.center, @@ -201,7 +211,8 @@ class _LockScreenPasswordState extends State { if (widget.authPass == base64Encode(hash)) { await _lockscreenSetting.setInvalidAttemptCount(0); - widget.isOnOpeningApp + widget.isAuthenticatingOnAppLaunch || + widget.isAuthenticatingForInAppChange ? Navigator.of(context).pop(true) : Navigator.of(context).pushReplacement( MaterialPageRoute( @@ -210,7 +221,7 @@ class _LockScreenPasswordState extends State { ); return true; } else { - if (widget.isOnOpeningApp) { + if (widget.isAuthenticatingOnAppLaunch) { invalidAttemptsCount++; await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount); if (invalidAttemptsCount > 4) { @@ -224,7 +235,7 @@ class _LockScreenPasswordState extends State { } Future _confirmPassword() async { - if (widget.isAuthenticating) { + if (widget.isChangingLockScreenSettings) { await _confirmPasswordAuth(_passwordController.text); return; } else { diff --git a/mobile/lib/ui/settings/lock_screen/lock_screen_pin.dart b/mobile/lib/ui/settings/lock_screen/lock_screen_pin.dart index 4695fedb20..2f526751f2 100644 --- a/mobile/lib/ui/settings/lock_screen/lock_screen_pin.dart +++ b/mobile/lib/ui/settings/lock_screen/lock_screen_pin.dart @@ -18,14 +18,24 @@ import 'package:pinput/pinput.dart'; class LockScreenPin extends StatefulWidget { const LockScreenPin({ super.key, - this.isAuthenticating = false, - this.isOnOpeningApp = false, + this.isChangingLockScreenSettings = false, + this.isAuthenticatingOnAppLaunch = false, + this.isAuthenticatingForInAppChange = false, this.authPin, }); - //Is false when setting a new password - final bool isAuthenticating; - final bool isOnOpeningApp; + /// [isChangingLockScreenSettings] Authentication required for changing lock screen settings. + /// Set to true when the app requires the user to authenticate before allowing + /// changes to the lock screen settings. + final bool isChangingLockScreenSettings; + + /// [isAuthenticatingOnAppLaunch] Authentication required on app launch. + /// Set to true when the app requires the user to authenticate immediately upon opening. + final bool isAuthenticatingOnAppLaunch; + + /// [isAuthenticatingForInAppChange] Authentication required for in-app changes (e.g., email, password). + /// Set to true when the app requires the to authenticate for sensitive actions like email, password changes. + final bool isAuthenticatingForInAppChange; final String? authPin; @override State createState() => _LockScreenPinState(); @@ -62,7 +72,8 @@ class _LockScreenPinState extends State { if (widget.authPin == base64Encode(hash)) { invalidAttemptsCount = 0; await _lockscreenSetting.setInvalidAttemptCount(0); - widget.isOnOpeningApp + widget.isAuthenticatingOnAppLaunch || + widget.isAuthenticatingForInAppChange ? Navigator.of(context).pop(true) : Navigator.of(context).pushReplacement( MaterialPageRoute( @@ -81,7 +92,7 @@ class _LockScreenPinState extends State { isPinValid = false; }); - if (widget.isOnOpeningApp) { + if (widget.isAuthenticatingOnAppLaunch) { invalidAttemptsCount++; await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount); if (invalidAttemptsCount > 4) { @@ -93,7 +104,7 @@ class _LockScreenPinState extends State { } Future _confirmPin(String code) async { - if (widget.isAuthenticating) { + if (widget.isChangingLockScreenSettings) { await confirmPinAuth(code); return; } else { @@ -220,7 +231,7 @@ class _LockScreenPinState extends State { ), ), Text( - widget.isAuthenticating + widget.isChangingLockScreenSettings ? S.of(context).enterPin : S.of(context).setNewPin, style: textTheme.bodyBold, diff --git a/mobile/lib/utils/auth_util.dart b/mobile/lib/utils/auth_util.dart index 9c4e161fbf..f25aff58b7 100644 --- a/mobile/lib/utils/auth_util.dart +++ b/mobile/lib/utils/auth_util.dart @@ -11,6 +11,7 @@ Future requestAuthentication( BuildContext context, String reason, { bool isOpeningApp = false, + bool isAuthenticatingForInAppChange = false, }) async { Logger("AuthUtil").info("Requesting authentication"); await LocalAuthentication().stopAuthentication(); @@ -23,7 +24,8 @@ Future requestAuthentication( context, savedPin, savedPassword, - isOnOpeningApp: isOpeningApp, + isAuthenticatingOnAppLaunch: isOpeningApp, + isAuthenticatingForInAppChange: isAuthenticatingForInAppChange, ); } else { return await LocalAuthentication().authenticate( diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index a0479b453d..8b2cbcfe43 100644 --- a/mobile/pubspec.yaml +++ b/mobile/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.9.6+906 +version: 0.9.7+907 publish_to: none environment: