mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-24 02:22:44 +02:00
Merge MatrixKit develop with commit hash: b85b736313bec0592bd1cabc68035d97f5331137
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
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 "MXKAuthInputsView.h"
|
||||
|
||||
@interface MXKAuthInputsEmailCodeBasedView : MXKAuthInputsView
|
||||
|
||||
/**
|
||||
The input text field related to user id or user login.
|
||||
*/
|
||||
@property (weak, nonatomic) IBOutlet UITextField *userLoginTextField;
|
||||
|
||||
/**
|
||||
The input text field used to fill an email or the related token.
|
||||
*/
|
||||
@property (weak, nonatomic) IBOutlet UITextField *emailAndTokenTextField;
|
||||
|
||||
/**
|
||||
Label used to prompt user to fill the email token.
|
||||
*/
|
||||
@property (weak, nonatomic) IBOutlet UILabel *promptEmailTokenLabel;
|
||||
|
||||
/**
|
||||
The text field related to the display name. This item is displayed in case of registration.
|
||||
*/
|
||||
@property (weak, nonatomic) IBOutlet UITextField *displayNameTextField;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
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 "MXKAuthInputsEmailCodeBasedView.h"
|
||||
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
|
||||
#import "MXKSwiftHeader.h"
|
||||
|
||||
@implementation MXKAuthInputsEmailCodeBasedView
|
||||
|
||||
+ (UINib *)nib
|
||||
{
|
||||
return [UINib nibWithNibName:NSStringFromClass([MXKAuthInputsEmailCodeBasedView class])
|
||||
bundle:[NSBundle bundleForClass:[MXKAuthInputsEmailCodeBasedView class]]];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
_userLoginTextField.placeholder = [MatrixKitL10n loginUserIdPlaceholder];
|
||||
_emailAndTokenTextField.placeholder = [MatrixKitL10n loginEmailPlaceholder];
|
||||
_promptEmailTokenLabel.text = [MatrixKitL10n loginPromptEmailToken];
|
||||
|
||||
_displayNameTextField.placeholder = [MatrixKitL10n loginDisplayNamePlaceholder];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (BOOL)setAuthSession:(MXAuthenticationSession *)authSession withAuthType:(MXKAuthenticationType)authType;
|
||||
{
|
||||
if (type == MXKAuthenticationTypeLogin || type == MXKAuthenticationTypeRegister)
|
||||
{
|
||||
// Validate first the provided session
|
||||
MXAuthenticationSession *validSession = [self validateAuthenticationSession:authSession];
|
||||
|
||||
if ([super setAuthSession:validSession withAuthType:authType])
|
||||
{
|
||||
// Set initial layout
|
||||
self.userLoginTextField.hidden = NO;
|
||||
self.promptEmailTokenLabel.hidden = YES;
|
||||
|
||||
if (type == MXKAuthenticationTypeLogin)
|
||||
{
|
||||
self.emailAndTokenTextField.returnKeyType = UIReturnKeyDone;
|
||||
self.displayNameTextField.hidden = YES;
|
||||
|
||||
self.viewHeightConstraint.constant = self.displayNameTextField.frame.origin.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.emailAndTokenTextField.returnKeyType = UIReturnKeyNext;
|
||||
self.displayNameTextField.hidden = NO;
|
||||
|
||||
self.viewHeightConstraint.constant = 122;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString*)validateParameters
|
||||
{
|
||||
NSString *errorMsg = [super validateParameters];
|
||||
|
||||
if (!errorMsg)
|
||||
{
|
||||
if (!self.areAllRequiredFieldsSet)
|
||||
{
|
||||
errorMsg = [MatrixKitL10n loginInvalidParam];
|
||||
}
|
||||
}
|
||||
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
- (BOOL)areAllRequiredFieldsSet
|
||||
{
|
||||
BOOL ret = [super areAllRequiredFieldsSet];
|
||||
|
||||
// Check required fields //FIXME what are required fields in this authentication flow?
|
||||
ret = (ret && self.userLoginTextField.text.length && self.emailAndTokenTextField.text.length);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard
|
||||
{
|
||||
[self.userLoginTextField resignFirstResponder];
|
||||
[self.emailAndTokenTextField resignFirstResponder];
|
||||
[self.displayNameTextField resignFirstResponder];
|
||||
|
||||
[super dismissKeyboard];
|
||||
}
|
||||
|
||||
- (void)nextStep
|
||||
{
|
||||
// Consider here the email token has been requested with success
|
||||
[super nextStep];
|
||||
|
||||
self.userLoginTextField.hidden = YES;
|
||||
self.promptEmailTokenLabel.hidden = NO;
|
||||
self.emailAndTokenTextField.placeholder = nil;
|
||||
self.emailAndTokenTextField.returnKeyType = UIReturnKeyDone;
|
||||
|
||||
self.displayNameTextField.hidden = YES;
|
||||
}
|
||||
|
||||
- (NSString*)userId
|
||||
{
|
||||
return self.userLoginTextField.text;
|
||||
}
|
||||
|
||||
#pragma mark UITextField delegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField
|
||||
{
|
||||
if (textField.returnKeyType == UIReturnKeyDone)
|
||||
{
|
||||
// "Done" key has been pressed
|
||||
[textField resignFirstResponder];
|
||||
|
||||
// Launch authentication now
|
||||
[self.delegate authInputsViewDidPressDoneKey:self];
|
||||
}
|
||||
else
|
||||
{
|
||||
//"Next" key has been pressed
|
||||
if (textField == self.userLoginTextField)
|
||||
{
|
||||
[self.emailAndTokenTextField becomeFirstResponder];
|
||||
}
|
||||
else if (textField == self.emailAndTokenTextField)
|
||||
{
|
||||
[self.displayNameTextField becomeFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (MXAuthenticationSession*)validateAuthenticationSession:(MXAuthenticationSession*)authSession
|
||||
{
|
||||
// Check whether at least one of the listed flow is supported.
|
||||
BOOL isSupported = NO;
|
||||
|
||||
for (MXLoginFlow *loginFlow in authSession.flows)
|
||||
{
|
||||
// Check whether flow type is defined
|
||||
if ([loginFlow.type isEqualToString:kMXLoginFlowTypeEmailCode])
|
||||
{
|
||||
isSupported = YES;
|
||||
break;
|
||||
}
|
||||
else if (loginFlow.stages.count == 1 && [loginFlow.stages.firstObject isEqualToString:kMXLoginFlowTypeEmailCode])
|
||||
{
|
||||
isSupported = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSupported)
|
||||
{
|
||||
if (authSession.flows.count == 1)
|
||||
{
|
||||
// Return the original session.
|
||||
return authSession;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep only the supported flow.
|
||||
MXAuthenticationSession *updatedAuthSession = [[MXAuthenticationSession alloc] init];
|
||||
updatedAuthSession.session = authSession.session;
|
||||
updatedAuthSession.params = authSession.params;
|
||||
updatedAuthSession.flows = @[[MXLoginFlow modelFromJSON:@{@"stages":@[kMXLoginFlowTypeEmailCode]}]];
|
||||
return updatedAuthSession;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Nmn-Ry-t32" customClass="MXKAuthInputsEmailCodeBasedView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="300" height="122"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Matrix ID (e.g. @bob:matrix.org or bob)" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="oen-Yq-xJw">
|
||||
<rect key="frame" x="14" y="8" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="gfu-Ef-79U"/>
|
||||
<constraint firstAttribute="width" constant="272" id="y4N-L3-qlh"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="next"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Nmn-Ry-t32" id="Ari-Ab-eGE"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Email address" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="mbS-mV-L86" userLabel="Email-Token">
|
||||
<rect key="frame" x="14" y="46" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="ecT-NT-FqH"/>
|
||||
<constraint firstAttribute="width" constant="272" id="xkx-sr-F8M"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done" secureTextEntry="YES"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Nmn-Ry-t32" id="yrA-lO-OCi"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Please enter your email validation token:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vDa-DE-6Bn">
|
||||
<rect key="frame" x="20" y="8" width="260" height="30"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textField hidden="YES" opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Display name (e.g. Bob Obson)" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="FVM-ec-tja" userLabel="DisplayName">
|
||||
<rect key="frame" x="14" y="84" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="272" id="1b5-Ej-eUB"/>
|
||||
<constraint firstAttribute="height" constant="30" id="bEU-4F-cUv"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done" secureTextEntry="YES"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Nmn-Ry-t32" id="Q3D-XL-8Ke"/>
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="FVM-ec-tja" firstAttribute="top" secondItem="mbS-mV-L86" secondAttribute="bottom" constant="8" id="0BV-8c-ZVg"/>
|
||||
<constraint firstAttribute="height" constant="122" id="1nP-RR-5GK"/>
|
||||
<constraint firstAttribute="centerX" secondItem="mbS-mV-L86" secondAttribute="centerX" id="2R2-Du-o97"/>
|
||||
<constraint firstItem="oen-Yq-xJw" firstAttribute="top" secondItem="Nmn-Ry-t32" secondAttribute="top" constant="8" id="BkW-Np-qB3"/>
|
||||
<constraint firstItem="mbS-mV-L86" firstAttribute="top" secondItem="oen-Yq-xJw" secondAttribute="bottom" constant="8" id="TRx-gf-Afp"/>
|
||||
<constraint firstAttribute="centerX" secondItem="FVM-ec-tja" secondAttribute="centerX" id="c9K-6H-ufd"/>
|
||||
<constraint firstItem="mbS-mV-L86" firstAttribute="top" secondItem="vDa-DE-6Bn" secondAttribute="bottom" constant="8" id="cq8-qs-59M"/>
|
||||
<constraint firstItem="vDa-DE-6Bn" firstAttribute="top" secondItem="Nmn-Ry-t32" secondAttribute="top" constant="8" id="eAp-Ob-hFr"/>
|
||||
<constraint firstAttribute="centerX" secondItem="vDa-DE-6Bn" secondAttribute="centerX" id="otm-qx-iNL"/>
|
||||
<constraint firstAttribute="centerX" secondItem="oen-Yq-xJw" secondAttribute="centerX" id="s7Y-qf-yrY"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="displayNameTextField" destination="FVM-ec-tja" id="pMF-oP-7Jj"/>
|
||||
<outlet property="emailAndTokenTextField" destination="mbS-mV-L86" id="nY5-gT-wGe"/>
|
||||
<outlet property="promptEmailTokenLabel" destination="vDa-DE-6Bn" id="X3w-5E-0Kg"/>
|
||||
<outlet property="userLoginTextField" destination="oen-Yq-xJw" id="OM2-gy-O9P"/>
|
||||
<outlet property="viewHeightConstraint" destination="1nP-RR-5GK" id="s3W-1L-bWN"/>
|
||||
</connections>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
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 "MXKAuthInputsView.h"
|
||||
|
||||
@interface MXKAuthInputsPasswordBasedView : MXKAuthInputsView
|
||||
|
||||
/**
|
||||
The input text field related to user id or user login.
|
||||
*/
|
||||
@property (weak, nonatomic) IBOutlet UITextField *userLoginTextField;
|
||||
|
||||
/**
|
||||
The input text field used to fill the password.
|
||||
*/
|
||||
@property (weak, nonatomic) IBOutlet UITextField *passWordTextField;
|
||||
|
||||
/**
|
||||
The input text field used to fill an email. This item is optional, it is added in case of registration.
|
||||
*/
|
||||
@property (weak, nonatomic) IBOutlet UITextField *emailTextField;
|
||||
|
||||
/**
|
||||
Label used to display email field information.
|
||||
*/
|
||||
@property (weak, nonatomic) IBOutlet UILabel *emailInfoLabel;
|
||||
|
||||
/**
|
||||
The text field related to the display name. This item is displayed in case of registration.
|
||||
*/
|
||||
@property (weak, nonatomic) IBOutlet UITextField *displayNameTextField;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations 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 "MXKAuthInputsPasswordBasedView.h"
|
||||
|
||||
#import "MXKTools.h"
|
||||
|
||||
#import "MXKAppSettings.h"
|
||||
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
|
||||
#import "MXKSwiftHeader.h"
|
||||
|
||||
@implementation MXKAuthInputsPasswordBasedView
|
||||
|
||||
+ (UINib *)nib
|
||||
{
|
||||
return [UINib nibWithNibName:NSStringFromClass([MXKAuthInputsPasswordBasedView class])
|
||||
bundle:[NSBundle bundleForClass:[MXKAuthInputsPasswordBasedView class]]];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
_userLoginTextField.placeholder = [MatrixKitL10n loginUserIdPlaceholder];
|
||||
_passWordTextField.placeholder = [MatrixKitL10n loginPasswordPlaceholder];
|
||||
_emailTextField.placeholder = [NSString stringWithFormat:@"%@ (%@)", [MatrixKitL10n loginEmailPlaceholder], [MatrixKitL10n loginOptionalField]];
|
||||
_emailInfoLabel.text = [MatrixKitL10n loginEmailInfo];
|
||||
|
||||
_displayNameTextField.placeholder = [MatrixKitL10n loginDisplayNamePlaceholder];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (BOOL)setAuthSession:(MXAuthenticationSession *)authSession withAuthType:(MXKAuthenticationType)authType;
|
||||
{
|
||||
if (type == MXKAuthenticationTypeLogin || type == MXKAuthenticationTypeRegister)
|
||||
{
|
||||
// Validate first the provided session
|
||||
MXAuthenticationSession *validSession = [self validateAuthenticationSession:authSession];
|
||||
|
||||
if ([super setAuthSession:validSession withAuthType:authType])
|
||||
{
|
||||
if (type == MXKAuthenticationTypeLogin)
|
||||
{
|
||||
self.passWordTextField.returnKeyType = UIReturnKeyDone;
|
||||
self.emailTextField.hidden = YES;
|
||||
self.emailInfoLabel.hidden = YES;
|
||||
self.displayNameTextField.hidden = YES;
|
||||
|
||||
self.viewHeightConstraint.constant = self.displayNameTextField.frame.origin.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.passWordTextField.returnKeyType = UIReturnKeyNext;
|
||||
self.emailTextField.hidden = NO;
|
||||
self.emailInfoLabel.hidden = NO;
|
||||
self.displayNameTextField.hidden = NO;
|
||||
|
||||
self.viewHeightConstraint.constant = 179;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString*)validateParameters
|
||||
{
|
||||
NSString *errorMsg = [super validateParameters];
|
||||
|
||||
if (!errorMsg)
|
||||
{
|
||||
// Check user login and pass fields
|
||||
if (!self.areAllRequiredFieldsSet)
|
||||
{
|
||||
errorMsg = [MatrixKitL10n loginInvalidParam];
|
||||
}
|
||||
}
|
||||
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
- (void)prepareParameters:(void (^)(NSDictionary *parameters, NSError *error))callback
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
// Sanity check on required fields
|
||||
if (!self.areAllRequiredFieldsSet)
|
||||
{
|
||||
callback(nil, [NSError errorWithDomain:MXKAuthErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey:[MatrixKitL10n loginInvalidParam]}]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the user login and check whether it is an email or a username.
|
||||
// TODO: Update the UI view to support the login based on a mobile phone number.
|
||||
NSString *user = self.userLoginTextField.text;
|
||||
user = [user stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
BOOL isEmailAddress = [MXTools isEmailAddress:user];
|
||||
|
||||
NSDictionary *parameters;
|
||||
|
||||
if (isEmailAddress)
|
||||
{
|
||||
parameters = @{
|
||||
@"type": kMXLoginFlowTypePassword,
|
||||
@"identifier": @{
|
||||
@"type": kMXLoginIdentifierTypeThirdParty,
|
||||
@"medium": kMX3PIDMediumEmail,
|
||||
@"address": user
|
||||
},
|
||||
@"password": self.passWordTextField.text
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = @{
|
||||
@"type": kMXLoginFlowTypePassword,
|
||||
@"identifier": @{
|
||||
@"type": kMXLoginIdentifierTypeUser,
|
||||
@"user": user
|
||||
},
|
||||
@"password": self.passWordTextField.text
|
||||
};
|
||||
}
|
||||
|
||||
callback(parameters, nil);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)areAllRequiredFieldsSet
|
||||
{
|
||||
BOOL ret = [super areAllRequiredFieldsSet];
|
||||
|
||||
// Check user login and pass fields
|
||||
ret = (ret && self.userLoginTextField.text.length && self.passWordTextField.text.length);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard
|
||||
{
|
||||
[self.userLoginTextField resignFirstResponder];
|
||||
[self.passWordTextField resignFirstResponder];
|
||||
[self.emailTextField resignFirstResponder];
|
||||
[self.displayNameTextField resignFirstResponder];
|
||||
|
||||
[super dismissKeyboard];
|
||||
}
|
||||
|
||||
- (NSString*)userId
|
||||
{
|
||||
return self.userLoginTextField.text;
|
||||
}
|
||||
|
||||
- (NSString*)password
|
||||
{
|
||||
return self.passWordTextField.text;
|
||||
}
|
||||
|
||||
#pragma mark UITextField delegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField
|
||||
{
|
||||
if (textField.returnKeyType == UIReturnKeyDone)
|
||||
{
|
||||
// "Done" key has been pressed
|
||||
[textField resignFirstResponder];
|
||||
|
||||
// Launch authentication now
|
||||
[self.delegate authInputsViewDidPressDoneKey:self];
|
||||
}
|
||||
else
|
||||
{
|
||||
//"Next" key has been pressed
|
||||
if (textField == self.userLoginTextField)
|
||||
{
|
||||
[self.passWordTextField becomeFirstResponder];
|
||||
}
|
||||
else if (textField == self.passWordTextField)
|
||||
{
|
||||
[self.displayNameTextField becomeFirstResponder];
|
||||
}
|
||||
else if (textField == self.displayNameTextField)
|
||||
{
|
||||
[self.emailTextField becomeFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (MXAuthenticationSession*)validateAuthenticationSession:(MXAuthenticationSession*)authSession
|
||||
{
|
||||
// Check whether at least one of the listed flow is supported.
|
||||
BOOL isSupported = NO;
|
||||
|
||||
for (MXLoginFlow *loginFlow in authSession.flows)
|
||||
{
|
||||
// Check whether flow type is defined
|
||||
if ([loginFlow.type isEqualToString:kMXLoginFlowTypePassword])
|
||||
{
|
||||
isSupported = YES;
|
||||
break;
|
||||
}
|
||||
else if (loginFlow.stages.count == 1 && [loginFlow.stages.firstObject isEqualToString:kMXLoginFlowTypePassword])
|
||||
{
|
||||
isSupported = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSupported)
|
||||
{
|
||||
if (authSession.flows.count == 1)
|
||||
{
|
||||
// Return the original session.
|
||||
return authSession;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep only the supported flow.
|
||||
MXAuthenticationSession *updatedAuthSession = [[MXAuthenticationSession alloc] init];
|
||||
updatedAuthSession.session = authSession.session;
|
||||
updatedAuthSession.params = authSession.params;
|
||||
updatedAuthSession.flows = @[[MXLoginFlow modelFromJSON:@{@"stages":@[kMXLoginFlowTypePassword]}]];
|
||||
return updatedAuthSession;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="x74-04-ezp" customClass="MXKAuthInputsPasswordBasedView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="300" height="179"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Matrix ID (e.g. @bob:matrix.org or bob)" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="i51-ym-i9T">
|
||||
<rect key="frame" x="14" y="8" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="272" id="IhR-uY-MJZ"/>
|
||||
<constraint firstAttribute="height" constant="30" id="x3j-uC-j0U"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="next"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="x74-04-ezp" id="yCp-R2-dNp"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Password" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="6rs-rR-DkS">
|
||||
<rect key="frame" x="14" y="46" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="Fh2-oZ-UBe"/>
|
||||
<constraint firstAttribute="width" constant="272" id="pCs-je-5Rd"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done" secureTextEntry="YES"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="x74-04-ezp" id="t8U-qP-IHU"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField hidden="YES" opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Display name (e.g. Bob Obson)" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="BQM-LP-8Eq" userLabel="DisplayName">
|
||||
<rect key="frame" x="14" y="84" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="Iwg-IP-ITp"/>
|
||||
<constraint firstAttribute="width" constant="272" id="ZG2-Aw-XkP"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="next" secureTextEntry="YES"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="x74-04-ezp" id="qkT-a6-G0Y"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField hidden="YES" opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Email address (optional)" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="odF-W1-Vdr" userLabel="Email">
|
||||
<rect key="frame" x="14" y="126" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="272" id="wZg-GR-5XL"/>
|
||||
<constraint firstAttribute="height" constant="30" id="zVy-8W-zmR"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done" secureTextEntry="YES"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="x74-04-ezp" id="isi-U5-D9A"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="OHZ-Ye-nch" userLabel="EmailInfoLabel">
|
||||
<rect key="frame" x="14" y="156" width="272" height="15"/>
|
||||
<string key="text">Specify an email address lets other users find you on Matrix more easily, and will give you a way to reset your password in the future.</string>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="i51-ym-i9T" firstAttribute="top" secondItem="x74-04-ezp" secondAttribute="top" constant="8" id="2sO-Wi-AFi"/>
|
||||
<constraint firstItem="BQM-LP-8Eq" firstAttribute="top" secondItem="6rs-rR-DkS" secondAttribute="bottom" constant="8" id="2vZ-NH-f0H"/>
|
||||
<constraint firstAttribute="centerX" secondItem="odF-W1-Vdr" secondAttribute="centerX" id="BbL-ex-otM"/>
|
||||
<constraint firstItem="OHZ-Ye-nch" firstAttribute="leading" secondItem="x74-04-ezp" secondAttribute="leading" constant="14" id="Ctv-P7-FQl"/>
|
||||
<constraint firstItem="6rs-rR-DkS" firstAttribute="top" secondItem="i51-ym-i9T" secondAttribute="bottom" constant="8" id="EJf-md-dcj"/>
|
||||
<constraint firstAttribute="height" constant="179" id="JbD-Ce-bTY"/>
|
||||
<constraint firstItem="OHZ-Ye-nch" firstAttribute="top" secondItem="odF-W1-Vdr" secondAttribute="bottom" id="LTI-Eq-pH6"/>
|
||||
<constraint firstAttribute="centerX" secondItem="i51-ym-i9T" secondAttribute="centerX" id="WKP-y0-Jon"/>
|
||||
<constraint firstAttribute="centerX" secondItem="BQM-LP-8Eq" secondAttribute="centerX" id="aQQ-kb-tLS"/>
|
||||
<constraint firstAttribute="centerX" secondItem="6rs-rR-DkS" secondAttribute="centerX" id="nIk-ev-cFe"/>
|
||||
<constraint firstItem="odF-W1-Vdr" firstAttribute="top" secondItem="BQM-LP-8Eq" secondAttribute="bottom" constant="12" id="qjk-LC-4NN"/>
|
||||
<constraint firstAttribute="centerX" secondItem="OHZ-Ye-nch" secondAttribute="centerX" id="tvZ-5z-KAm"/>
|
||||
<constraint firstAttribute="trailing" secondItem="OHZ-Ye-nch" secondAttribute="trailing" constant="14" id="yQg-6n-P8L"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="displayNameTextField" destination="BQM-LP-8Eq" id="Ptq-yP-WaZ"/>
|
||||
<outlet property="emailInfoLabel" destination="OHZ-Ye-nch" id="fh6-Sz-X5K"/>
|
||||
<outlet property="emailTextField" destination="odF-W1-Vdr" id="DOS-H7-MZy"/>
|
||||
<outlet property="passWordTextField" destination="6rs-rR-DkS" id="VeL-kt-Fpp"/>
|
||||
<outlet property="userLoginTextField" destination="i51-ym-i9T" id="XKi-6m-tFv"/>
|
||||
<outlet property="viewHeightConstraint" destination="JbD-Ce-bTY" id="09n-jN-RM1"/>
|
||||
</connections>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C
|
||||
|
||||
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 <MatrixSDK/MatrixSDK.h>
|
||||
|
||||
#import "MXKView.h"
|
||||
|
||||
extern NSString *const MXKAuthErrorDomain;
|
||||
|
||||
/**
|
||||
Authentication types
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
Type used to sign up.
|
||||
*/
|
||||
MXKAuthenticationTypeRegister,
|
||||
/**
|
||||
Type used to sign in.
|
||||
*/
|
||||
MXKAuthenticationTypeLogin,
|
||||
/**
|
||||
Type used to restore an existing account by reseting the password.
|
||||
*/
|
||||
MXKAuthenticationTypeForgotPassword
|
||||
|
||||
} MXKAuthenticationType;
|
||||
|
||||
@class MXKAuthInputsView;
|
||||
|
||||
/**
|
||||
`MXKAuthInputsView` delegate
|
||||
*/
|
||||
@protocol MXKAuthInputsViewDelegate <NSObject>
|
||||
|
||||
/**
|
||||
Tells the delegate that an alert must be presented.
|
||||
|
||||
@param authInputsView the authentication inputs view.
|
||||
@param alert the alert to present.
|
||||
*/
|
||||
- (void)authInputsView:(MXKAuthInputsView*)authInputsView presentAlertController:(UIAlertController*)alert;
|
||||
|
||||
/**
|
||||
For some input fields, the return key of the keyboard is defined as `Done` key.
|
||||
By this method, the delegate is notified when this key is pressed.
|
||||
*/
|
||||
- (void)authInputsViewDidPressDoneKey:(MXKAuthInputsView *)authInputsView;
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
The matrix REST Client used to validate third-party identifiers.
|
||||
*/
|
||||
- (MXRestClient *)authInputsViewThirdPartyIdValidationRestClient:(MXKAuthInputsView *)authInputsView;
|
||||
|
||||
/**
|
||||
The identity service used to validate third-party identifiers.
|
||||
*/
|
||||
- (MXIdentityService *)authInputsViewThirdPartyIdValidationIdentityService:(MXKAuthInputsView *)authInputsView;
|
||||
|
||||
/**
|
||||
Tell the delegate to present a view controller modally.
|
||||
|
||||
Note: This method is used to display the countries list during the phone number handling.
|
||||
|
||||
@param authInputsView the authentication inputs view.
|
||||
@param viewControllerToPresent the view controller to present.
|
||||
@param animated YES to animate the presentation.
|
||||
*/
|
||||
- (void)authInputsView:(MXKAuthInputsView *)authInputsView presentViewController:(UIViewController*)viewControllerToPresent animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Tell the delegate to cancel the current operation.
|
||||
*/
|
||||
- (void)authInputsViewDidCancelOperation:(MXKAuthInputsView *)authInputsView;
|
||||
|
||||
/**
|
||||
Tell the delegate to autodiscover the server configuration.
|
||||
*/
|
||||
- (void)authInputsView:(MXKAuthInputsView *)authInputsView autoDiscoverServerWithDomain:(NSString*)domain;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
`MXKAuthInputsView` is a base class to handle authentication inputs.
|
||||
*/
|
||||
@interface MXKAuthInputsView : MXKView <UITextFieldDelegate>
|
||||
{
|
||||
@protected
|
||||
/**
|
||||
The authentication type (`MXKAuthenticationTypeLogin` by default).
|
||||
*/
|
||||
MXKAuthenticationType type;
|
||||
|
||||
/**
|
||||
The authentication session (nil by default).
|
||||
*/
|
||||
MXAuthenticationSession *currentSession;
|
||||
|
||||
/**
|
||||
Alert used to display inputs error.
|
||||
*/
|
||||
UIAlertController *inputsAlert;
|
||||
}
|
||||
|
||||
/**
|
||||
The view delegate.
|
||||
*/
|
||||
@property (nonatomic, weak) id <MXKAuthInputsViewDelegate> delegate;
|
||||
|
||||
/**
|
||||
The current authentication type (`MXKAuthenticationTypeLogin` by default).
|
||||
*/
|
||||
@property (nonatomic, readonly) MXKAuthenticationType authType;
|
||||
|
||||
/**
|
||||
The current authentication session if any.
|
||||
*/
|
||||
@property (nonatomic, readonly) MXAuthenticationSession *authSession;
|
||||
|
||||
/**
|
||||
The current filled user identifier (nil by default).
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *userId;
|
||||
|
||||
/**
|
||||
The current filled password (nil by default).
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *password;
|
||||
|
||||
/**
|
||||
The layout constraint defined on the view height. This height takes into account shown/hidden fields.
|
||||
*/
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *viewHeightConstraint;
|
||||
|
||||
/**
|
||||
Returns the `UINib` object initialized for the auth inputs view.
|
||||
|
||||
@return The initialized `UINib` object or `nil` if there were errors during
|
||||
initialization or the nib file could not be located.
|
||||
*/
|
||||
+ (UINib *)nib;
|
||||
|
||||
/**
|
||||
Creates and returns a new `MXKAuthInputsView` object.
|
||||
|
||||
@discussion This is the designated initializer for programmatic instantiation.
|
||||
|
||||
@return An initialized `MXKAuthInputsView` object if successful, `nil` otherwise.
|
||||
*/
|
||||
+ (instancetype)authInputsView;
|
||||
|
||||
/**
|
||||
Finalize the authentication inputs view with a session and a type.
|
||||
Use this method to restore the view in its initial step.
|
||||
|
||||
@discussion You may override this method to check/update the flows listed in the provided authentication session.
|
||||
|
||||
@param authSession the authentication session returned by the homeserver.
|
||||
@param authType the authentication type (see 'MXKAuthenticationType').
|
||||
@return YES if the provided session and type are supported by the MXKAuthInputsView-inherited class. Note the unsupported flows should be here removed from the stored authentication session (see the resulting session in the property named 'authSession').
|
||||
*/
|
||||
- (BOOL)setAuthSession:(MXAuthenticationSession *)authSession withAuthType:(MXKAuthenticationType)authType;
|
||||
|
||||
/**
|
||||
Check the validity of the required parameters.
|
||||
|
||||
@return an error message in case of wrong parameters (nil by default).
|
||||
*/
|
||||
- (NSString*)validateParameters;
|
||||
|
||||
/**
|
||||
Prepare the set of the inputs in order to launch an authentication process.
|
||||
|
||||
@param callback the block called when the parameters are prepared. The resulting parameter dictionary is nil
|
||||
if something fails (for example when a parameter or a required input is missing). The failure reason is provided in error parameter (nil by default).
|
||||
*/
|
||||
- (void)prepareParameters:(void (^)(NSDictionary *parameters, NSError *error))callback;
|
||||
|
||||
/**
|
||||
Update the current authentication session by providing the list of successful stages.
|
||||
|
||||
@param completedStages the list of stages the client has completed successfully. This is an array of MXLoginFlowType.
|
||||
@param callback the block called when the parameters have been updated for the next stage. The resulting parameter dictionary is nil
|
||||
if something fails (for example when a parameter or a required input is missing). The failure reason is provided in error parameter (nil by default).
|
||||
*/
|
||||
- (void)updateAuthSessionWithCompletedStages:(NSArray *)completedStages didUpdateParameters:(void (^)(NSDictionary *parameters, NSError *error))callback;
|
||||
|
||||
/**
|
||||
Update the current authentication session by providing a set of registration parameters.
|
||||
|
||||
@discussion This operation failed if the current authentication type is MXKAuthenticationTypeLogin.
|
||||
|
||||
@param registrationParameters a set of parameters to use during the current registration process.
|
||||
@return YES if the provided set of parameters is supported.
|
||||
*/
|
||||
- (BOOL)setExternalRegistrationParameters:(NSDictionary *)registrationParameters;
|
||||
|
||||
/**
|
||||
Update the current authentication session by providing soft logout credentials.
|
||||
*/
|
||||
@property (nonatomic) MXCredentials *softLogoutCredentials;
|
||||
|
||||
/**
|
||||
Tell whether all required fields are set
|
||||
*/
|
||||
- (BOOL)areAllRequiredFieldsSet;
|
||||
|
||||
/**
|
||||
Force dismiss keyboard
|
||||
*/
|
||||
- (void)dismissKeyboard;
|
||||
|
||||
/**
|
||||
Switch in next authentication flow step by updating the layout.
|
||||
|
||||
@discussion This method is supposed to be called only if the current operation succeeds.
|
||||
*/
|
||||
- (void)nextStep;
|
||||
|
||||
/**
|
||||
Dispose any resources and listener.
|
||||
*/
|
||||
- (void)destroy;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations 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 "MXKAuthInputsView.h"
|
||||
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
|
||||
#import "MXKSwiftHeader.h"
|
||||
|
||||
NSString *const MXKAuthErrorDomain = @"MXKAuthErrorDomain";
|
||||
|
||||
@implementation MXKAuthInputsView
|
||||
|
||||
+ (UINib *)nib
|
||||
{
|
||||
// By default, no nib is available.
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (instancetype)authInputsView
|
||||
{
|
||||
// Check whether a xib is defined
|
||||
if ([[self class] nib])
|
||||
{
|
||||
return [[[self class] nib] instantiateWithOwner:nil options:nil].firstObject;
|
||||
}
|
||||
|
||||
return [[[self class] alloc] init];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
[self setTranslatesAutoresizingMaskIntoConstraints: NO];
|
||||
|
||||
type = MXKAuthenticationTypeLogin;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
type = MXKAuthenticationTypeLogin;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (BOOL)setAuthSession:(MXAuthenticationSession *)authSession withAuthType:(MXKAuthenticationType)authType
|
||||
{
|
||||
if (authSession)
|
||||
{
|
||||
type = authType;
|
||||
currentSession = authSession;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *)validateParameters
|
||||
{
|
||||
// Currently no field to check here
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)prepareParameters:(void (^)(NSDictionary *parameters, NSError *error))callback
|
||||
{
|
||||
// Do nothing by default
|
||||
if (callback)
|
||||
{
|
||||
callback (nil, [NSError errorWithDomain:MXKAuthErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey:[MatrixKitL10n notSupportedYet]}]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateAuthSessionWithCompletedStages:(NSArray *)completedStages didUpdateParameters:(void (^)(NSDictionary *parameters, NSError *error))callback
|
||||
{
|
||||
// Do nothing by default
|
||||
if (callback)
|
||||
{
|
||||
callback (nil, [NSError errorWithDomain:MXKAuthErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey:[MatrixKitL10n notSupportedYet]}]);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)setExternalRegistrationParameters:(NSDictionary *)registrationParameters
|
||||
{
|
||||
// Not supported by default
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)areAllRequiredFieldsSet
|
||||
{
|
||||
// Currently no field to check here
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)nextStep
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
if (inputsAlert)
|
||||
{
|
||||
[inputsAlert dismissViewControllerAnimated:NO completion:nil];
|
||||
inputsAlert = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (MXKAuthenticationType)authType
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
- (MXAuthenticationSession*)authSession
|
||||
{
|
||||
return currentSession;
|
||||
}
|
||||
|
||||
- (NSString*)userId
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString*)password
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
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 <MatrixSDK/MatrixSDK.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
@interface MXKAuthenticationFallbackWebView : WKWebView <WKNavigationDelegate>
|
||||
|
||||
/**
|
||||
Open authentication fallback page into the webview.
|
||||
|
||||
@param fallbackPage the fallback page hosted by a homeserver.
|
||||
@param success the block called when the user has been successfully logged in or registered.
|
||||
*/
|
||||
- (void)openFallbackPage:(NSString*)fallbackPage success:(void (^)(MXLoginResponse *loginResponse))success;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
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] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
|
||||
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
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright 2016 OpenMarket Ltd
|
||||
Copyright 2018 New Vector 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 <MatrixSDK/MatrixSDK.h>
|
||||
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
@interface MXKAuthenticationRecaptchaWebView : WKWebView
|
||||
|
||||
/**
|
||||
Open reCAPTCHA widget into a webview.
|
||||
|
||||
@param siteKey the site key.
|
||||
@param homeServer the homeserver URL.
|
||||
@param callback the block called when the user has received reCAPTCHA response.
|
||||
*/
|
||||
- (void)openRecaptchaWidgetWithSiteKey:(NSString*)siteKey fromHomeServer:(NSString*)homeServer callback:(void (^)(NSString *response))callback;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
Copyright 2016 OpenMarket Ltd
|
||||
Copyright 2018 New Vector 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 "MXKAuthenticationRecaptchaWebView.h"
|
||||
|
||||
NSString *kMXKRecaptchaHTMLString = @"<html> \
|
||||
<head> \
|
||||
<meta name='viewport' content='initial-scale=1.0' /> \
|
||||
<script type=\"text/javascript\"> \
|
||||
var verifyCallback = function(response) { \
|
||||
/* Generic method to make a bridge between JS and the WKWebView*/ \
|
||||
var iframe = document.createElement('iframe'); \
|
||||
iframe.setAttribute('src', 'js:' + JSON.stringify({'action': 'verifyCallback', 'response': response})); \
|
||||
\
|
||||
document.documentElement.appendChild(iframe); \
|
||||
iframe.parentNode.removeChild(iframe); \
|
||||
iframe = null; \
|
||||
}; \
|
||||
var onloadCallback = function() { \
|
||||
grecaptcha.render('recaptcha_widget', { \
|
||||
'sitekey' : '%@', \
|
||||
'callback': verifyCallback \
|
||||
}); \
|
||||
}; \
|
||||
</script> \
|
||||
</head> \
|
||||
<body> \
|
||||
<div id=\"recaptcha_widget\"></div> \
|
||||
<script src=\"https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit\" async defer> \
|
||||
</script> \
|
||||
</body> \
|
||||
</html>";
|
||||
|
||||
@interface MXKAuthenticationRecaptchaWebView () <WKNavigationDelegate>
|
||||
{
|
||||
// The block called when the reCAPTCHA response is received
|
||||
void (^onResponse)(NSString *);
|
||||
|
||||
// Activity indicator
|
||||
UIActivityIndicatorView *activityIndicator;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation MXKAuthenticationRecaptchaWebView
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (activityIndicator)
|
||||
{
|
||||
[activityIndicator removeFromSuperview];
|
||||
activityIndicator = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)openRecaptchaWidgetWithSiteKey:(NSString*)siteKey fromHomeServer:(NSString*)homeServer callback:(void (^)(NSString *response))callback
|
||||
{
|
||||
self.navigationDelegate = self;
|
||||
|
||||
onResponse = callback;
|
||||
|
||||
// Add activity indicator
|
||||
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
|
||||
activityIndicator.center = self.center;
|
||||
[self addSubview:activityIndicator];
|
||||
[activityIndicator startAnimating];
|
||||
|
||||
NSString *htmlString = [NSString stringWithFormat:kMXKRecaptchaHTMLString, siteKey];
|
||||
|
||||
[self loadHTMLString:htmlString baseURL:[NSURL URLWithString:homeServer]];
|
||||
}
|
||||
|
||||
#pragma mark - WKNavigationDelegate
|
||||
|
||||
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
|
||||
{
|
||||
if (activityIndicator)
|
||||
{
|
||||
[activityIndicator stopAnimating];
|
||||
[activityIndicator removeFromSuperview];
|
||||
activityIndicator = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
|
||||
{
|
||||
NSString *urlString = navigationAction.request.URL.absoluteString;
|
||||
|
||||
if ([urlString hasPrefix:@"js:"])
|
||||
{
|
||||
// Listen only to scheme of the JS-WKWebView bridge
|
||||
NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
|
||||
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
NSError *error;
|
||||
NSDictionary *parameters = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers
|
||||
error:&error];
|
||||
|
||||
if (!error)
|
||||
{
|
||||
if ([@"verifyCallback" isEqualToString:parameters[@"action"]])
|
||||
{
|
||||
// Transfer the reCAPTCHA response
|
||||
onResponse(parameters[@"response"]);
|
||||
}
|
||||
}
|
||||
decisionHandler(WKNavigationActionPolicyCancel);
|
||||
return;
|
||||
}
|
||||
decisionHandler(WKNavigationActionPolicyAllow);
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user