Files
bundesmessenger-ios/Riot/Modules/MatrixKit/Views/Authentication/MXKAuthenticationFallbackWebView.m

182 lines
7.2 KiB
Objective-C

/*
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "MXKAuthenticationFallbackWebView.h"
// Generic method to make a bridge between JS and the WKWebView
NSString *kMXKJavascriptSendObjectMessage = @"window.sendObjectMessage = function(parameters) { \
var iframe = document.createElement('iframe'); \
iframe.setAttribute('src', 'js:' + JSON.stringify(parameters)); \
\
document.documentElement.appendChild(iframe); \
iframe.parentNode.removeChild(iframe); \
iframe = null; \
};";
// The function the fallback page calls when the registration is complete
NSString *kMXKJavascriptOnRegistered = @"window.matrixRegistration.onRegistered = function(homeserverUrl, userId, accessToken) { \
sendObjectMessage({ \
'action': 'onRegistered', \
'homeServer': homeserverUrl, \
'userId': userId, \
'accessToken': accessToken \
}); \
};";
// The function the fallback page calls when the login is complete
NSString *kMXKJavascriptOnLogin = @"window.matrixLogin.onLogin = function(response) { \
sendObjectMessage({ \
'action': 'onLogin', \
'response': response \
}); \
};";
@interface MXKAuthenticationFallbackWebView ()
{
// The block called when the login or the registration is successful
void (^onSuccess)(MXLoginResponse *);
// Activity indicator
UIActivityIndicatorView *activityIndicator;
}
@end
@implementation MXKAuthenticationFallbackWebView
- (void)dealloc
{
if (activityIndicator)
{
[activityIndicator removeFromSuperview];
activityIndicator = nil;
}
}
- (void)openFallbackPage:(NSString *)fallbackPage success:(void (^)(MXLoginResponse *))success
{
self.navigationDelegate = self;
onSuccess = success;
// Add activity indicator
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.center = self.center;
[self addSubview:activityIndicator];
[activityIndicator startAnimating];
// Delete cookies to launch login process from scratch
for(NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies])
{
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
}
[self loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:fallbackPage]]];
}
#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
if (activityIndicator)
{
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
activityIndicator = nil;
}
[self evaluateJavaScript:kMXKJavascriptSendObjectMessage completionHandler:^(id _Nullable response, NSError * _Nullable error) {
}];
[self evaluateJavaScript:kMXKJavascriptOnRegistered completionHandler:^(id _Nullable response, NSError * _Nullable error) {
}];
[self evaluateJavaScript:kMXKJavascriptOnLogin completionHandler:^(id _Nullable response, NSError * _Nullable error) {
}];
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
MXLogDebug(@"[MXKAuthenticationFallbackWebView] decidePolicyForNavigationAction");
NSString *urlString = navigationAction.request.URL.absoluteString;
if ([urlString hasPrefix:@"js:"])
{
// do not log urlString, it may have an access token
MXLogDebug(@"[MXKAuthenticationFallbackWebView] URL has js: prefix");
// Listen only to scheme of the JS-WKWebView bridge
NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByRemovingPercentEncoding];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSDictionary *parameters = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers
error:&error];
if (error)
{
MXLogDebug(@"[MXKAuthenticationFallbackWebView] Error when parsing json: %@", error);
}
else
{
if ([@"onRegistered" isEqualToString:parameters[@"action"]])
{
// Translate the JS registration event to MXLoginResponse
// We cannot use [MXLoginResponse modelFromJSON:] because of https://github.com/matrix-org/synapse/issues/4756
// Because of this issue, we cannot get the device_id allocated by the homeserver
// TODO: Fix it once the homeserver issue is fixed (filed at https://github.com/vector-im/riot-meta/issues/273).
MXLoginResponse *loginResponse = [MXLoginResponse new];
loginResponse.homeserver = parameters[@"homeServer"];
loginResponse.userId = parameters[@"userId"];
loginResponse.accessToken = parameters[@"accessToken"];
MXLogDebug(@"[MXKAuthenticationFallbackWebView] Registered on homeserver: %@", loginResponse.homeserver);
// Sanity check
if (loginResponse.homeserver.length && loginResponse.userId.length && loginResponse.accessToken.length)
{
MXLogDebug(@"[MXKAuthenticationFallbackWebView] Call success block");
// And inform the client
onSuccess(loginResponse);
}
}
else if ([@"onLogin" isEqualToString:parameters[@"action"]])
{
// Translate the JS login event to MXLoginResponse
MXLoginResponse *loginResponse;
MXJSONModelSetMXJSONModel(loginResponse, MXLoginResponse, parameters[@"response"]);
MXLogDebug(@"[MXKAuthenticationFallbackWebView] Logged in on homeserver: %@", loginResponse.homeserver);
// Sanity check
if (loginResponse.homeserver.length && loginResponse.userId.length && loginResponse.accessToken.length)
{
MXLogDebug(@"[MXKAuthenticationFallbackWebView] Call success block");
// And inform the client
onSuccess(loginResponse);
}
}
}
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
@end