Add support for handling otpauth:// scheme

This commit is contained in:
Neeraj Gupta 2023-05-06 01:47:04 +05:30
parent ba49d0002d
commit ea3cd1844b
No known key found for this signature in database
GPG key ID: 3C5A1684DC1729E1
4 changed files with 140 additions and 67 deletions

View file

@ -28,6 +28,13 @@
<data android:scheme="ente-auth"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="otpauth" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.

View file

@ -1,68 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>auth</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>es</string>
</array>
<key>CFBundleName</key>
<string>auth</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>MinimumOSVersion</key>
<string>12.0</string>
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan QR codes</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIStatusBarHidden</key>
<false/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>NSFaceIDUsageDescription</key>
<string>Please allow auth to lock itself with FaceID or TouchID</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Please allow auth to pick a file to import data from</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>auth</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>es</string>
</array>
<key>CFBundleName</key>
<string>auth</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleURLSchemes</key>
<array>
<string>otpauth</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>12.0</string>
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan QR codes</string>
<key>NSFaceIDUsageDescription</key>
<string>Please allow auth to lock itself with FaceID or TouchID</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Please allow auth to pick a file to import data from</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIStatusBarHidden</key>
<false/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View file

@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/core/event_bus.dart';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/events/codes_updated_event.dart';
@ -19,10 +20,14 @@ import 'package:ente_auth/ui/home/home_empty_state.dart';
import 'package:ente_auth/ui/home/speed_dial_label_widget.dart';
import 'package:ente_auth/ui/scanner_page.dart';
import 'package:ente_auth/ui/settings_page.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:ente_auth/utils/totp_util.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:logging/logging.dart';
import 'package:move_to_background/move_to_background.dart';
import 'package:uni_links/uni_links.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@ -58,16 +63,15 @@ class _HomePageState extends State<HomePage> {
Bus.instance.on<TriggerLogoutEvent>().listen((event) async {
await autoLogoutAlert(context);
});
_initDeepLinks();
super.initState();
}
void _loadCodes() {
CodeStore.instance.getAllCodes().then((codes) {
_codes = codes;
_filteredCodes = codes;
_hasLoaded = true;
setState(() {});
_applyFiltering();
});
}
@ -263,6 +267,57 @@ class _HomePageState extends State<HomePage> {
}
}
Future<bool> _initDeepLinks() async {
// Platform messages may fail, so we use a try/catch PlatformException.
try {
final String? initialLink = await getInitialLink();
// Parse the link and warn the user, if it is not correct,
// but keep in mind it could be `null`.
if (initialLink != null) {
_handleDeeplink(context, initialLink);
return true;
} else {
_logger.info("No initial link received.");
}
} on PlatformException {
// Handle exception by warning the user their action did not succeed
// return?
_logger.severe("PlatformException thrown while getting initial link");
}
// Attach a listener to the stream
linkStream.listen(
(String? link) {
_handleDeeplink(context, link);
},
onError: (err) {
_logger.severe(err);
},
);
return false;
}
void _handleDeeplink(BuildContext context, String? link) {
if (!Configuration.instance.hasConfiguredAccount() || link == null) {
return;
}
if (mounted && link.toLowerCase().startsWith("otpauth://")) {
try {
final newCode = Code.fromRawData(link);
getNextTotp(newCode);
CodeStore.instance.addCode(newCode);
_showSearchBox = true;
_textController.text = newCode.account;
_searchText = newCode.account;
_applyFiltering();
setState(() {});
} catch (e, s) {
showGenericErrorDialog(context: context);
_logger.severe("error while handling deeplink", e, s);
}
}
}
Widget _getFab() {
return SpeedDial(
icon: Icons.add,

View file

@ -1,5 +1,3 @@
import 'package:ente_auth/core/constants.dart';
import 'package:ente_auth/core/logging/super_logging.dart';
import 'package:ente_auth/l10n/l10n.dart';