Skip to content

Commit

Permalink
Merge pull request #39 from luke-/15-session-app-token-header
Browse files Browse the repository at this point in the history
Session tooken rand hash to headers
  • Loading branch information
PrimozRatej authored Feb 9, 2023
2 parents 97211f4 + 46f8f2c commit 323fe0f
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 66 deletions.
18 changes: 17 additions & 1 deletion lib/models/hum_hub.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:math';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:humhub/models/manifest.dart';
import 'package:humhub/util/api_provider.dart';
Expand All @@ -7,18 +9,25 @@ enum RedirectAction { opener, webView }
class HumHub {
Manifest? manifest;
bool isHideDialog;
String? randomHash;

HumHub({this.manifest, this.isHideDialog = false});
HumHub({
this.manifest,
this.isHideDialog = false,
this.randomHash,
});

Map<String, dynamic> toJson() => {
'manifest': manifest != null ? manifest!.toJson() : null,
'isHideDialog': isHideDialog,
'randomHash': randomHash,
};

factory HumHub.fromJson(Map<String, dynamic> json) {
return HumHub(
manifest: Manifest.fromJson(json['manifest']),
isHideDialog: json['isHideDialog'] as bool,
randomHash: json['randomHash'],
);
}

Expand All @@ -39,4 +48,11 @@ class HumHub {
return RedirectAction.webView;
}
}

static String generateHash(int length) {
final random = Random.secure();
const characters = '0123456789abcdef';
return List.generate(
length, (_) => characters[random.nextInt(characters.length)]).join();
}
}
7 changes: 6 additions & 1 deletion lib/pages/opener.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,14 @@ class OpenerState extends ConsumerState<Opener> {
} else {
Manifest manifest = asyncData.value!;
// Set the manifestStateProvider with the manifest value so that it's globally accessible
// Generate hash and save it to store
String lastUrl = await ref.read(humHubProvider).getLastUrl();
String currentUrl = urlTextController.text;
String hash = HumHub.generateHash(32);
if (lastUrl == currentUrl) hash = ref.read(humHubProvider).randomHash ?? hash;
ref
.read(humHubProvider)
.setInstance(HumHub(manifest: manifest));
.setInstance(HumHub(manifest: manifest, randomHash: hash));
redirect();
}
}
Expand Down
140 changes: 77 additions & 63 deletions lib/pages/web_view.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:humhub/pages/opener.dart';
import 'package:humhub/util/const.dart';
import 'package:humhub/util/extensions.dart';
import 'package:humhub/models/manifest.dart';
import 'package:humhub/util/providers.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:webview_flutter/webview_flutter.dart';

import '../models/hum_hub.dart';


class WebViewApp extends ConsumerStatefulWidget {
final Manifest manifest;
const WebViewApp({super.key, required this.manifest});
Expand All @@ -19,10 +22,16 @@ class WebViewApp extends ConsumerStatefulWidget {
}

class WebViewAppState extends ConsumerState<WebViewApp> {
final scaffoldKey = GlobalKey<ScaffoldState>();
late InAppWebViewController inAppWebViewController;
final WebViewCookieManager cookieManager = WebViewCookieManager();
var customHeader = {'my-header-value-01': '111111', 'my-header-value-02': '222222'};
final options = InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
useShouldOverrideUrlLoading: true,
useShouldInterceptAjaxRequest: true,
useShouldInterceptFetchRequest: true,
javaScriptEnabled: true,
),
);

@override
void initState() {
Expand All @@ -32,74 +41,79 @@ class WebViewAppState extends ConsumerState<WebViewApp> {

@override
Widget build(BuildContext context) {
final initialRequest = URLRequest(
url: Uri.parse(widget.manifest.baseUrl), headers: customHeaders);
//Append random hash to customHeaders in this state the header should always exist.
customHeaders.addAll({'x-humhub-app-token': ref.read(humHubProvider).randomHash!});
return WillPopScope(
onWillPop: () => inAppWebViewController.exitApp(context, ref),
child: Scaffold(
backgroundColor: HexColor(widget.manifest.themeColor),
body: SafeArea(
child: InAppWebView(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
useShouldOverrideUrlLoading: true,
useShouldInterceptAjaxRequest: true,
useShouldInterceptFetchRequest: true,
javaScriptEnabled: true,
),
),
shouldOverrideUrlLoading: (controller, action) async {
// 1st check if url is not def. app url and open it in a browser or inApp.
final url = action.request.url!.origin;
if (!url.startsWith(widget.manifest.baseUrl)) {
launchUrl(action.request.url!,
mode: LaunchMode.externalApplication);
return NavigationActionPolicy.CANCEL;
}
// 2nd Append customHeader if url is in app redirect and CANCEL the requests without custom headers
if (Platform.isAndroid ||
action.iosWKNavigationType ==
IOSWKNavigationType.LINK_ACTIVATED) {
controller.loadUrl(
urlRequest: URLRequest(
url: action.request.url, headers: customHeader));
return NavigationActionPolicy.CANCEL;
}
return NavigationActionPolicy.ALLOW;
},
shouldInterceptAjaxRequest: (controller, ajaxReq) async {
// Append headers on every AJAX request
ajaxReq.headers = AjaxRequestHeaders(customHeader);
return ajaxReq;
},
shouldInterceptFetchRequest: (controller, fetchReq) async {
fetchReq.headers?.addAll(customHeader);
return fetchReq;
},
initialUrlRequest: URLRequest(
url: Uri.parse(widget.manifest.baseUrl), headers: customHeader),
onWebViewCreated: (controller) async {
await controller.addWebMessageListener(
WebMessageListener(
jsObjectName: "flutterChannel",
onPostMessage:
(message, sourceOrigin, isMainFrame, replyProxy) {
ref
.read(humHubProvider)
.setIsHideDialog(message == "humhub.mobile.hideOpener");
if (!ref.read(humHubProvider).isHideDialog) {
ref.read(humHubProvider).clearSafeStorage();
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => const Opener()),
(Route<dynamic> route) => false);
}
},
),
);
inAppWebViewController = controller;
},
),
initialUrlRequest: initialRequest,
initialOptions: options,
shouldOverrideUrlLoading: shouldOverrideUrlLoading,
onWebViewCreated: onWebViewCreated,
shouldInterceptAjaxRequest: shouldInterceptAjaxRequest,
shouldInterceptFetchRequest: shouldInterceptFetchRequest),
),
),
);
}

Future<NavigationActionPolicy?> shouldOverrideUrlLoading(
InAppWebViewController controller, NavigationAction action) async {
// 1st check if url is not def. app url and open it in a browser or inApp.
final url = action.request.url!.origin;
if (!url.startsWith(widget.manifest.baseUrl)) {
launchUrl(action.request.url!, mode: LaunchMode.externalApplication);
return NavigationActionPolicy.CANCEL;
}
// 2nd Append customHeader if url is in app redirect and CANCEL the requests without custom headers
if (Platform.isAndroid ||
action.iosWKNavigationType == IOSWKNavigationType.LINK_ACTIVATED) {
controller.loadUrl(
urlRequest:
URLRequest(url: action.request.url, headers: customHeaders));
return NavigationActionPolicy.CANCEL;
}
return NavigationActionPolicy.ALLOW;
}

onWebViewCreated(InAppWebViewController controller) async {
await controller.addWebMessageListener(
WebMessageListener(
jsObjectName: "flutterChannel",
onPostMessage: (message, sourceOrigin, isMainFrame, replyProxy) {
ref
.read(humHubProvider)
.setIsHideDialog(message == "humhub.mobile.hideOpener");
if (!ref.read(humHubProvider).isHideDialog) {
ref.read(humHubProvider).clearSafeStorage();
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => const Opener()),
(Route<dynamic> route) => false);
}
else{
ref.read(humHubProvider).setHash(HumHub.generateHash(32));
}
},
),
);
inAppWebViewController = controller;
}

Future<AjaxRequest?> shouldInterceptAjaxRequest(
InAppWebViewController controller, AjaxRequest ajaxReq) async {
// Append headers on every AJAX request
ajaxReq.headers = AjaxRequestHeaders(customHeaders);
return ajaxReq;
}

Future<FetchRequest?> shouldInterceptFetchRequest(
InAppWebViewController controller, FetchRequest fetchReq) async {
fetchReq.headers?.addAll(customHeaders);
return fetchReq;
}
}
4 changes: 3 additions & 1 deletion lib/util/const.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ const progress = Center(child: CircularProgressIndicator());
class StorageKeys{
static String humhubInstance = "humHubInstance";
static String lastInstanceUrl = "humHubLastUrl";
}
}

var customHeaders = {'my-header-value-01': '111111', 'my-header-value-02': '222222'};
6 changes: 6 additions & 0 deletions lib/util/extensions.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:humhub/models/manifest.dart';
import 'package:humhub/pages/opener.dart';
import 'package:humhub/util/providers.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:webview_flutter/webview_flutter.dart';

import 'const.dart';

extension MyCookies on WebViewCookieManager {
Future<void> setMyCookies(Manifest manifest) async {
await setCookie(
Expand All @@ -20,6 +25,7 @@ extension MyCookies on WebViewCookieManager {
}

extension MyWebViewController on InAppWebViewController {

Future<bool> exitApp(BuildContext context, ref) async {
bool canGoBack = await this.canGoBack();
if (canGoBack) {
Expand Down
8 changes: 8 additions & 0 deletions lib/util/providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class HumHubNotifier extends ChangeNotifier {

bool get isHideDialog => _humHubInstance.isHideDialog;
Manifest? get manifest => _humHubInstance.manifest;
String? get randomHash => _humHubInstance.randomHash;

void setIsHideDialog(bool isHide) {
_humHubInstance.isHideDialog = isHide;
Expand All @@ -32,6 +33,13 @@ class HumHubNotifier extends ChangeNotifier {
void setInstance(HumHub instance) {
_humHubInstance.manifest = instance.manifest;
_humHubInstance.isHideDialog = instance.isHideDialog;
_humHubInstance.randomHash = instance.randomHash;
_updateSafeStorage();
notifyListeners();
}

void setHash(String hash) {
_humHubInstance.randomHash = hash;
_updateSafeStorage();
notifyListeners();
}
Expand Down

0 comments on commit 323fe0f

Please sign in to comment.