Migrate athentication from webview to deep linking

This commit is contained in:
Yegor Vialov 2019-10-20 16:45:44 +00:00
parent 085aead36b
commit 520fd6bc38
7 changed files with 41 additions and 40 deletions

View File

@ -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

View File

@ -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(

View File

@ -9,24 +9,38 @@ class AuthManager {
} }
AuthManager._internal(); AuthManager._internal();
StreamSubscription deepLinksSubscription;
Future getTempToken({String oauthUrl}) { Future start({String oauthUrl}) {
Completer completer = Completer(); Completer completer = Completer();
final flutterWebviewPlugin = new FlutterWebviewPlugin(); deepLinksSubscription?.cancel();
flutterWebviewPlugin.onUrlChanged.listen((String url) { deepLinksSubscription = getUriLinksStream().listen((Uri uri) {
if (url.startsWith("http://ha-client.homemade.systems/service/auth_callback.html")) { Logger.d("[LINKED AUTH] We got something private: $uri");
String authCode = url.split("=")[1]; Logger.d("[LINKED AUTH] code=${uri.queryParameters["code"]}");
Logger.d("We have auth code. Getting temporary access token..."); _getTempToken(oauthUrl, uri.queryParameters["code"])
ConnectionManager().sendHTTPPost( .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();
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;
} }

View File

@ -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");

View File

@ -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();

View File

@ -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) {

View File

@ -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