Migrate athentication from webview to deep linking
This commit is contained in:
parent
085aead36b
commit
520fd6bc38
@ -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();
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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