Migrate athentication from webview to deep linking
This commit is contained in:
		| @@ -52,6 +52,14 @@ | |||||||
|                 <action android:name="android.intent.action.MAIN"/> |                 <action android:name="android.intent.action.MAIN"/> | ||||||
|                 <category android:name="android.intent.category.LAUNCHER"/> |                 <category android:name="android.intent.category.LAUNCHER"/> | ||||||
|             </intent-filter> |             </intent-filter> | ||||||
|  |             <intent-filter android:autoVerify="true"> | ||||||
|  |                 <action android:name="android.intent.action.VIEW" /> | ||||||
|  |                 <category android:name="android.intent.category.DEFAULT" /> | ||||||
|  |                 <category android:name="android.intent.category.BROWSABLE" /> | ||||||
|  |                 <data | ||||||
|  |                 android:scheme="haclient" | ||||||
|  |                 android:host="auth" /> | ||||||
|  |             </intent-filter> | ||||||
|         </activity> |         </activity> | ||||||
|  |  | ||||||
|         <service |         <service | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ import 'package:share/receive_share_state.dart'; | |||||||
| import 'package:share/share.dart'; | import 'package:share/share.dart'; | ||||||
| import 'plugins/dynamic_multi_column_layout.dart'; | import 'plugins/dynamic_multi_column_layout.dart'; | ||||||
| import 'plugins/spoiler_card.dart'; | import 'plugins/spoiler_card.dart'; | ||||||
|  | import 'package:uni_links/uni_links.dart'; | ||||||
|  |  | ||||||
| import 'utils/logger.dart'; | import 'utils/logger.dart'; | ||||||
|  |  | ||||||
| @@ -185,24 +186,6 @@ class HAClientApp extends StatelessWidget { | |||||||
|         ), |         ), | ||||||
|         "/log-view": (context) => LogViewPage(title: "Log"), |         "/log-view": (context) => LogViewPage(title: "Log"), | ||||||
|         "/whats-new": (context) => WhatsNewPage(), |         "/whats-new": (context) => WhatsNewPage(), | ||||||
|         "/login": (context) => WebviewScaffold( |  | ||||||
|           url: "${ConnectionManager().oauthUrl}", |  | ||||||
|           appBar: new AppBar( |  | ||||||
|             leading: IconButton( |  | ||||||
|                 icon: Icon(Icons.help), |  | ||||||
|                 onPressed: () => Launcher.launchURLInCustomTab(context: context, url: "http://ha-client.homemade.systems/docs#authentication") |  | ||||||
|             ), |  | ||||||
|             title: new Text("Login with HA"), |  | ||||||
|             actions: <Widget>[ |  | ||||||
|               FlatButton( |  | ||||||
|                 child: Text("Manual", style: TextStyle(color: Colors.white)), |  | ||||||
|                 onPressed: () { |  | ||||||
|                   eventBus.fire(ShowPageEvent(path: "/connection-settings", goBackFirst: true)); |  | ||||||
|                 }, |  | ||||||
|               ) |  | ||||||
|             ], |  | ||||||
|           ), |  | ||||||
|         ), |  | ||||||
|         "/webview": (context) => WebviewScaffold( |         "/webview": (context) => WebviewScaffold( | ||||||
|           url: "${(ModalRoute.of(context).settings.arguments as Map)['url']}", |           url: "${(ModalRoute.of(context).settings.arguments as Map)['url']}", | ||||||
|           appBar: new AppBar( |           appBar: new AppBar( | ||||||
|   | |||||||
| @@ -9,24 +9,38 @@ class AuthManager { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   AuthManager._internal(); |   AuthManager._internal(); | ||||||
|  |   StreamSubscription deepLinksSubscription; | ||||||
|  |  | ||||||
|   Future getTempToken({String oauthUrl}) { |   Future start({String oauthUrl}) { | ||||||
|  |     Completer completer = Completer(); | ||||||
|  |     deepLinksSubscription?.cancel(); | ||||||
|  |     deepLinksSubscription = getUriLinksStream().listen((Uri uri) { | ||||||
|  |             Logger.d("[LINKED AUTH] We got something private: $uri"); | ||||||
|  |             Logger.d("[LINKED AUTH] code=${uri.queryParameters["code"]}"); | ||||||
|  |             _getTempToken(oauthUrl, uri.queryParameters["code"]) | ||||||
|  |               .then((tempToken) => completer.complete(tempToken)) | ||||||
|  |               .catchError((_){ | ||||||
|  |                 completer.completeError(HAError("Auth error")); | ||||||
|  |               }); | ||||||
|  |           }, onError: (err) { | ||||||
|  |             Logger.e("[LINKED AUTH] Error handling linked auth: $e"); | ||||||
|  |             completer.completeError(HAError("Auth error")); | ||||||
|  |           }); | ||||||
|  |     Logger.d("Launching OAuth"); | ||||||
|  |     eventBus.fire(StartAuthEvent(oauthUrl, true)); | ||||||
|  |     return completer.future; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future _getTempToken(String oauthUrl,String authCode) { | ||||||
|     Completer completer = Completer(); |     Completer completer = Completer(); | ||||||
|     final flutterWebviewPlugin = new FlutterWebviewPlugin(); |  | ||||||
|     flutterWebviewPlugin.onUrlChanged.listen((String url) { |  | ||||||
|       if (url.startsWith("http://ha-client.homemade.systems/service/auth_callback.html")) { |  | ||||||
|         String authCode = url.split("=")[1]; |  | ||||||
|         Logger.d("We have auth code. Getting temporary access token..."); |  | ||||||
|     ConnectionManager().sendHTTPPost( |     ConnectionManager().sendHTTPPost( | ||||||
|             endPoint: "/auth/token", |             endPoint: "/auth/token", | ||||||
|             contentType: "application/x-www-form-urlencoded", |             contentType: "application/x-www-form-urlencoded", | ||||||
|             includeAuthHeader: false, |             includeAuthHeader: false, | ||||||
|             data: "grant_type=authorization_code&code=$authCode&client_id=${Uri.encodeComponent('http://ha-client.homemade.systems/')}" |             data: "grant_type=authorization_code&code=$authCode&client_id=${Uri.encodeComponent('http://ha-client.homemade.systems')}" | ||||||
|         ).then((response) { |         ).then((response) { | ||||||
|           Logger.d("Got temp token"); |           Logger.d("Got temp token"); | ||||||
|           String tempToken = json.decode(response)['access_token']; |           String tempToken = json.decode(response)['access_token']; | ||||||
|           Logger.d("Closing webview..."); |  | ||||||
|           //flutterWebviewPlugin.close(); |  | ||||||
|           eventBus.fire(StartAuthEvent(oauthUrl, false)); |           eventBus.fire(StartAuthEvent(oauthUrl, false)); | ||||||
|           completer.complete(tempToken); |           completer.complete(tempToken); | ||||||
|         }).catchError((e) { |         }).catchError((e) { | ||||||
| @@ -35,10 +49,6 @@ class AuthManager { | |||||||
|           eventBus.fire(StartAuthEvent(oauthUrl, false)); |           eventBus.fire(StartAuthEvent(oauthUrl, false)); | ||||||
|           completer.completeError(HAError("Error getting temp token")); |           completer.completeError(HAError("Error getting temp token")); | ||||||
|         }); |         }); | ||||||
|       } |  | ||||||
|     }); |  | ||||||
|     Logger.d("Launching OAuth"); |  | ||||||
|     eventBus.fire(StartAuthEvent(oauthUrl, true)); |  | ||||||
|     return completer.future; |     return completer.future; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -59,9 +59,9 @@ class ConnectionManager { | |||||||
|           _token = await storage.read(key: "hacl_llt"); |           _token = await storage.read(key: "hacl_llt"); | ||||||
|           Logger.e("Long-lived token read successful"); |           Logger.e("Long-lived token read successful"); | ||||||
|           oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent( |           oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent( | ||||||
|               'http://ha-client.homemade.systems/')}&redirect_uri=${Uri |               'http://ha-client.homemade.systems')}&redirect_uri=${Uri | ||||||
|               .encodeComponent( |               .encodeComponent( | ||||||
|               'http://ha-client.homemade.systems/service/auth_callback.html')}"; |               'haclient://auth')}"; | ||||||
|           settingsLoaded = true; |           settingsLoaded = true; | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|           completer.completeError(HAError("Error reading login details", actions: [HAErrorAction.tryAgain(type: HAErrorActionType.FULL_RELOAD), HAErrorAction.loginAgain()])); |           completer.completeError(HAError("Error reading login details", actions: [HAErrorAction.tryAgain(type: HAErrorActionType.FULL_RELOAD), HAErrorAction.loginAgain()])); | ||||||
| @@ -79,7 +79,7 @@ class ConnectionManager { | |||||||
|  |  | ||||||
|     if (!stopInit) { |     if (!stopInit) { | ||||||
|       if (_token == null) { |       if (_token == null) { | ||||||
|         AuthManager().getTempToken( |         AuthManager().start( | ||||||
|             oauthUrl: oauthUrl |             oauthUrl: oauthUrl | ||||||
|         ).then((token) { |         ).then((token) { | ||||||
|           Logger.d("Token from AuthManager recived"); |           Logger.d("Token from AuthManager recived"); | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ class StartupUserMessagesManager { | |||||||
|   bool _supportAppDevelopmentMessageShown; |   bool _supportAppDevelopmentMessageShown; | ||||||
|   bool _whatsNewMessageShown; |   bool _whatsNewMessageShown; | ||||||
|   static final _supportAppDevelopmentMessageKey = "user-message-shown-support-development_3"; |   static final _supportAppDevelopmentMessageKey = "user-message-shown-support-development_3"; | ||||||
|   static final _whatsNewMessageKey = "user-message-shown-whats-new-673"; |   static final _whatsNewMessageKey = "user-message-shown-whats-new-675"; | ||||||
|  |  | ||||||
|   void checkMessagesToShow() async { |   void checkMessagesToShow() async { | ||||||
|     SharedPreferences prefs = await SharedPreferences.getInstance(); |     SharedPreferences prefs = await SharedPreferences.getInstance(); | ||||||
|   | |||||||
| @@ -75,8 +75,6 @@ class _MainPageState extends ReceiveShareState<MainPage> with WidgetsBindingObse | |||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     _fullLoad(); |     _fullLoad(); | ||||||
|  |  | ||||||
|  |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override void receiveShare(Share shared) { |   @override void receiveShare(Share shared) { | ||||||
| @@ -254,7 +252,6 @@ class _MainPageState extends ReceiveShareState<MainPage> with WidgetsBindingObse | |||||||
|           _showOAuth(); |           _showOAuth(); | ||||||
|         } else { |         } else { | ||||||
|           _preventAppRefresh = false; |           _preventAppRefresh = false; | ||||||
|           Navigator.of(context).pop(); |  | ||||||
|         } |         } | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
| @@ -268,7 +265,9 @@ class _MainPageState extends ReceiveShareState<MainPage> with WidgetsBindingObse | |||||||
|  |  | ||||||
|   void _showOAuth() { |   void _showOAuth() { | ||||||
|     _preventAppRefresh = true; |     _preventAppRefresh = true; | ||||||
|     Navigator.of(context).pushNamed('/login'); |     Launcher.launchURLInCustomTab( | ||||||
|  |       url: ConnectionManager().oauthUrl | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   _setErrorState(HAError e) { |   _setErrorState(HAError e) { | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ dependencies: | |||||||
| #  flutter_svg: ^0.10.3 | #  flutter_svg: ^0.10.3 | ||||||
|   flutter_custom_tabs: ^0.6.0 |   flutter_custom_tabs: ^0.6.0 | ||||||
|   firebase_messaging: ^5.1.6 |   firebase_messaging: ^5.1.6 | ||||||
|  |   uni_links: ^0.2.0 | ||||||
|   flutter_webview_plugin: ^0.3.8 |   flutter_webview_plugin: ^0.3.8 | ||||||
|   flutter_secure_storage: ^3.3.1+1 |   flutter_secure_storage: ^3.3.1+1 | ||||||
|   device_info: ^0.4.0+3 |   device_info: ^0.4.0+3 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user