mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-29 07:42:40 +00:00
Registration support.
Support the 2 following flows: m.login.email.identity and m.login.recaptcha.
This commit is contained in:
parent
236d202142
commit
87811e8350
7 changed files with 628 additions and 179 deletions
|
@ -16,12 +16,14 @@
|
|||
|
||||
// Titles
|
||||
"title_recents" = "Messages";
|
||||
"warning" = "Warning";
|
||||
|
||||
// Actions
|
||||
"view" = "View";
|
||||
"mark_all_as_read_prompt" = "Mark all as read?";
|
||||
"next" = "Next";
|
||||
"back" = "Back";
|
||||
"continue" = "Continue";
|
||||
"create" = "Create";
|
||||
"leave" = "Leave";
|
||||
"remove" = "Remove";
|
||||
|
@ -40,10 +42,21 @@
|
|||
"auth_user_id_placeholder" = "Email or user name";
|
||||
"auth_password_placeholder" = "Password";
|
||||
"auth_user_name_placeholder" = "Your name";
|
||||
"auth_optional_email_placeholder" = "Email address (optional)";
|
||||
"auth_email_placeholder" = "Email address";
|
||||
"auth_repeat_password_placeholder" = "Repeat password";
|
||||
"auth_invalid_login_param" = "Incorrect username and/or password";
|
||||
"auth_invalid_user_name" = "User names may only contain letters, numbers, dots, hyphens and underscores";
|
||||
"auth_invalid_password" = "Password too short (min 6)";
|
||||
"auth_missing_password" = "Missing password";
|
||||
"auth_missing_optional_email" = "If you don't specify an email address, you won't be able to reset your password. Are you sure?";
|
||||
"auth_missing_email" = "Missing email address";
|
||||
"auth_password_dont_match" = "Passwords don't match";
|
||||
"auth_forgot_password" = "Forgot password?";
|
||||
"auth_use_server_options" = "Use custom server options (advanced)";
|
||||
"auth_email_validation_message" = "Please check your email to continue registration";
|
||||
"auth_recaptcha_message" = "This Home Server would like to make sure you are not a robot";
|
||||
"auth_username_in_use" = "Username in use";
|
||||
|
||||
// Chat creation
|
||||
"room_creation_title" = "New Chat";
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
@property (weak, nonatomic) IBOutlet UINavigationItem *mainNavigationItem;
|
||||
@property (weak, nonatomic) IBOutlet UIBarButtonItem *rightBarButtonItem;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIView *optionsContainer;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIButton *forgotPasswordButton;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *serverOptionsTickButton;
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
self.submitButton.backgroundColor = kVectorColorGreen;
|
||||
[self.submitButton setTitle:NSLocalizedStringFromTable(@"auth_login", @"Vector", nil) forState:UIControlStateNormal];
|
||||
[self.submitButton setTitle:NSLocalizedStringFromTable(@"auth_login", @"Vector", nil) forState:UIControlStateHighlighted];
|
||||
self.submitButton.enabled = YES;
|
||||
|
||||
[self.forgotPasswordButton setTitle:NSLocalizedStringFromTable(@"auth_forgot_password", @"Vector", nil) forState:UIControlStateNormal];
|
||||
[self.forgotPasswordButton setTitle:NSLocalizedStringFromTable(@"auth_forgot_password", @"Vector", nil) forState:UIControlStateHighlighted];
|
||||
|
@ -111,6 +112,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void)setUserInteractionEnabled:(BOOL)userInteractionEnabled
|
||||
{
|
||||
super.userInteractionEnabled = userInteractionEnabled;
|
||||
|
||||
// Show/Hide server options
|
||||
_optionsContainer.hidden = !userInteractionEnabled;
|
||||
}
|
||||
|
||||
- (IBAction)onButtonPressed:(id)sender
|
||||
{
|
||||
if (sender == self.serverOptionsTickButton)
|
||||
|
@ -140,6 +149,40 @@
|
|||
|
||||
[self hideServerOptionsContainer:YES];
|
||||
}
|
||||
else if (sender == self.submitButton)
|
||||
{
|
||||
// Check whether the user should set the email
|
||||
if (self.authInputsView.shouldPromptUserForEmailAddress)
|
||||
{
|
||||
[self dismissKeyboard];
|
||||
|
||||
if (alert)
|
||||
{
|
||||
[alert dismiss:NO];
|
||||
}
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
alert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"warning", @"Vector", nil) message:NSLocalizedStringFromTable(@"auth_missing_optional_email", @"Vector", nil) style:MXKAlertStyleAlert];
|
||||
[alert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"continue"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {
|
||||
|
||||
__strong __typeof(weakSelf)strongSelf = weakSelf;
|
||||
strongSelf->alert = nil;
|
||||
|
||||
[super onButtonPressed:sender];
|
||||
}];
|
||||
alert.cancelButtonIndex = [alert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {
|
||||
|
||||
__strong __typeof(weakSelf)strongSelf = weakSelf;
|
||||
strongSelf->alert = nil;
|
||||
}];
|
||||
[alert showInViewController:self];
|
||||
}
|
||||
else
|
||||
{
|
||||
[super onButtonPressed:sender];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[super onButtonPressed:sender];
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9532" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AuthenticationViewController">
|
||||
|
@ -29,6 +29,7 @@
|
|||
<outlet property="identityServerTextField" destination="PZC-Hd-Q6a" id="vKg-sd-dzJ"/>
|
||||
<outlet property="mainNavigationItem" destination="rj9-wP-8QS" id="yNN-Dg-4Yw"/>
|
||||
<outlet property="noFlowLabel" destination="54b-4O-ip9" id="f18-H1-cQm"/>
|
||||
<outlet property="optionsContainer" destination="Gg0-TE-OGb" id="RWa-Pl-eaL"/>
|
||||
<outlet property="retryButton" destination="wIH-Kd-r7q" id="42j-Ad-zVS"/>
|
||||
<outlet property="rightBarButtonItem" destination="Kwt-KN-aVL" id="Y3F-wA-tf8"/>
|
||||
<outlet property="serverOptionsContainer" destination="uOi-KN-l9I" id="DPa-Kr-caW"/>
|
||||
|
@ -119,8 +120,11 @@
|
|||
<constraint firstAttribute="centerX" secondItem="30E-gm-z6O" secondAttribute="centerX" id="sSN-PO-Q6t"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gg0-TE-OGb">
|
||||
<rect key="frame" x="0.0" y="300" width="600" height="300"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AJ2-lJ-NUq">
|
||||
<rect key="frame" x="19" y="333" width="123" height="30"/>
|
||||
<rect key="frame" x="19" y="33" width="123" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="1mr-dZ-KtP"/>
|
||||
</constraints>
|
||||
|
@ -132,7 +136,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="k3J-Eg-itz" userLabel="SubmitBtn">
|
||||
<rect key="frame" x="469" y="333" width="120" height="30"/>
|
||||
<rect key="frame" x="469" y="33" width="120" height="30"/>
|
||||
<color key="backgroundColor" red="0.028153735480000001" green="0.82494870580000002" blue="0.051896891280000003" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="120" id="H9x-Zc-0sE"/>
|
||||
|
@ -148,7 +152,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="middleTruncation" hasAttributedTitle="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6yx-o1-vbD">
|
||||
<rect key="frame" x="19" y="373" width="562" height="30"/>
|
||||
<rect key="frame" x="19" y="73" width="562" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="buF-NU-DPO"/>
|
||||
</constraints>
|
||||
|
@ -168,7 +172,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uOi-KN-l9I" userLabel="ServerOptionsContainerView">
|
||||
<rect key="frame" x="0.0" y="406" width="600" height="140"/>
|
||||
<rect key="frame" x="0.0" y="106" width="600" height="140"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1YY-gb-LG4">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="70"/>
|
||||
|
@ -275,24 +279,34 @@
|
|||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="uOi-KN-l9I" secondAttribute="trailing" id="1Sf-bE-wYd"/>
|
||||
<constraint firstItem="uOi-KN-l9I" firstAttribute="leading" secondItem="rhx-dD-4EJ" secondAttribute="leading" id="2fA-Yk-wWM"/>
|
||||
<constraint firstAttribute="trailing" secondItem="6yx-o1-vbD" secondAttribute="trailing" constant="19" id="R2S-Ws-WMJ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="uOi-KN-l9I" secondAttribute="trailing" id="SWf-ih-6pd"/>
|
||||
<constraint firstAttribute="trailing" secondItem="k3J-Eg-itz" secondAttribute="trailing" constant="11" id="ZyA-Tq-Sfq"/>
|
||||
<constraint firstItem="uOi-KN-l9I" firstAttribute="leading" secondItem="Gg0-TE-OGb" secondAttribute="leading" id="aiw-9p-H6e"/>
|
||||
<constraint firstItem="6yx-o1-vbD" firstAttribute="top" secondItem="k3J-Eg-itz" secondAttribute="bottom" constant="10" id="cg9-yK-6ei"/>
|
||||
<constraint firstItem="AJ2-lJ-NUq" firstAttribute="centerY" secondItem="k3J-Eg-itz" secondAttribute="centerY" id="dcE-Vs-7Rt"/>
|
||||
<constraint firstItem="uOi-KN-l9I" firstAttribute="top" secondItem="6yx-o1-vbD" secondAttribute="bottom" constant="3" id="dk7-BQ-XYO"/>
|
||||
<constraint firstItem="k3J-Eg-itz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="AJ2-lJ-NUq" secondAttribute="trailing" constant="10" id="hr4-Hl-7dk"/>
|
||||
<constraint firstItem="6yx-o1-vbD" firstAttribute="leading" secondItem="Gg0-TE-OGb" secondAttribute="leading" constant="19" id="jwU-gh-qcW"/>
|
||||
<constraint firstAttribute="height" constant="300" id="lXv-gM-CjN"/>
|
||||
<constraint firstItem="k3J-Eg-itz" firstAttribute="top" secondItem="Gg0-TE-OGb" secondAttribute="top" constant="33" id="mor-t9-7Ke"/>
|
||||
<constraint firstItem="AJ2-lJ-NUq" firstAttribute="top" secondItem="Gg0-TE-OGb" secondAttribute="top" constant="33" id="v8n-Gp-nQM"/>
|
||||
<constraint firstItem="AJ2-lJ-NUq" firstAttribute="leading" secondItem="Gg0-TE-OGb" secondAttribute="leading" constant="19" id="xFm-Bs-yzw"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="555" id="6v6-fz-e8o"/>
|
||||
<constraint firstItem="k3J-Eg-itz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="AJ2-lJ-NUq" secondAttribute="trailing" constant="10" id="Dqz-kf-feR"/>
|
||||
<constraint firstItem="6yx-o1-vbD" firstAttribute="leading" secondItem="rhx-dD-4EJ" secondAttribute="leading" constant="19" id="N10-Ro-yH2"/>
|
||||
<constraint firstAttribute="trailing" secondItem="6yx-o1-vbD" secondAttribute="trailing" constant="19" id="OOw-6o-Tgu"/>
|
||||
<constraint firstItem="uOi-KN-l9I" firstAttribute="top" secondItem="rhx-dD-4EJ" secondAttribute="top" constant="406" id="XV1-Eu-q2K"/>
|
||||
<constraint firstItem="Gg0-TE-OGb" firstAttribute="width" secondItem="rhx-dD-4EJ" secondAttribute="width" id="EBX-KN-pRT"/>
|
||||
<constraint firstItem="Gg0-TE-OGb" firstAttribute="top" secondItem="rhx-dD-4EJ" secondAttribute="top" constant="300" id="UEM-Mh-0H9"/>
|
||||
<constraint firstItem="xWb-IJ-v7F" firstAttribute="leading" secondItem="rhx-dD-4EJ" secondAttribute="leading" id="YnP-Nk-QxR"/>
|
||||
<constraint firstItem="6yx-o1-vbD" firstAttribute="top" secondItem="AJ2-lJ-NUq" secondAttribute="bottom" constant="10" id="aKJ-nR-LVK"/>
|
||||
<constraint firstItem="k3J-Eg-itz" firstAttribute="top" secondItem="rhx-dD-4EJ" secondAttribute="top" constant="333" id="bga-yP-JTC"/>
|
||||
<constraint firstAttribute="width" constant="600" placeholder="YES" id="hOT-Wn-hIb"/>
|
||||
<constraint firstAttribute="trailing" secondItem="xWb-IJ-v7F" secondAttribute="trailing" id="hko-ol-XDd"/>
|
||||
<constraint firstAttribute="trailing" secondItem="k3J-Eg-itz" secondAttribute="trailing" constant="11" id="i9P-es-EQL"/>
|
||||
<constraint firstItem="AJ2-lJ-NUq" firstAttribute="leading" secondItem="rhx-dD-4EJ" secondAttribute="leading" constant="19" id="j4p-mo-ZxL"/>
|
||||
<constraint firstItem="xWb-IJ-v7F" firstAttribute="top" secondItem="rhx-dD-4EJ" secondAttribute="top" constant="76" id="khR-Uj-OTH"/>
|
||||
<constraint firstItem="d8r-TX-pwX" firstAttribute="top" secondItem="rhx-dD-4EJ" secondAttribute="top" constant="30" id="l68-Ta-YKg"/>
|
||||
<constraint firstAttribute="centerX" secondItem="d8r-TX-pwX" secondAttribute="centerX" id="l6k-EH-Yb8"/>
|
||||
<constraint firstItem="AJ2-lJ-NUq" firstAttribute="centerY" secondItem="k3J-Eg-itz" secondAttribute="centerY" id="xNG-4j-ETw"/>
|
||||
<constraint firstItem="Gg0-TE-OGb" firstAttribute="leading" secondItem="rhx-dD-4EJ" secondAttribute="leading" id="rS3-go-zbf"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "MXKAuthInputsView.h"
|
||||
#import <MatrixKit/MatrixKit.h>
|
||||
|
||||
@interface AuthInputsView : MXKAuthInputsView
|
||||
|
||||
|
@ -36,4 +36,8 @@
|
|||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *userLoginContainerTopConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *passwordContainerTopConstraint;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *messageLabel;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet MXKAuthenticationRecaptchaWebView *recaptchaWebView;
|
||||
|
||||
@end
|
||||
|
|
|
@ -18,6 +18,13 @@
|
|||
|
||||
#import "VectorDesignValues.h"
|
||||
|
||||
@interface AuthInputsView ()
|
||||
{
|
||||
MXK3PID *submittedEmail;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation AuthInputsView
|
||||
|
||||
+ (UINib *)nib
|
||||
|
@ -39,8 +46,16 @@
|
|||
self.passWordTextField.placeholder = NSLocalizedStringFromTable(@"auth_password_placeholder", @"Vector", nil);
|
||||
self.passWordTextField.textColor = kVectorTextColorBlack;
|
||||
|
||||
self.emailTextField.placeholder = NSLocalizedStringFromTable(@"auth_email_placeholder", @"Vector", nil);
|
||||
self.emailTextField.textColor = kVectorTextColorBlack;
|
||||
|
||||
self.messageLabel.numberOfLines = 0;
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
[super destroy];
|
||||
|
||||
submittedEmail = nil;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -50,6 +65,9 @@
|
|||
// Validate first the provided session
|
||||
MXAuthenticationSession *validSession = [self validateAuthenticationSession:authSession];
|
||||
|
||||
// Reset UI by hidding all items
|
||||
[self hideInputsContainer];
|
||||
|
||||
if ([super setAuthSession:validSession withAuthType:authType])
|
||||
{
|
||||
if (authType == MXKAuthenticationTypeLogin)
|
||||
|
@ -61,6 +79,8 @@
|
|||
self.userLoginContainerTopConstraint.constant = 0;
|
||||
self.passwordContainerTopConstraint.constant = 50;
|
||||
|
||||
self.userLoginContainer.hidden = NO;
|
||||
self.passwordContainer.hidden = NO;
|
||||
self.emailContainer.hidden = YES;
|
||||
self.repeatPasswordContainer.hidden = YES;
|
||||
}
|
||||
|
@ -70,39 +90,290 @@
|
|||
|
||||
self.userLoginTextField.placeholder = NSLocalizedStringFromTable(@"auth_user_name_placeholder", @"Vector", nil);
|
||||
|
||||
if (self.isEmailIdentityFlowSupported)
|
||||
{
|
||||
if (self.isEmailIdentityFlowRequired)
|
||||
{
|
||||
self.emailTextField.placeholder = NSLocalizedStringFromTable(@"auth_email_placeholder", @"Vector", nil);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.emailTextField.placeholder = NSLocalizedStringFromTable(@"auth_optional_email_placeholder", @"Vector", nil);
|
||||
}
|
||||
|
||||
self.userLoginContainerTopConstraint.constant = 50;
|
||||
self.passwordContainerTopConstraint.constant = 100;
|
||||
|
||||
self.emailContainer.hidden = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.userLoginContainerTopConstraint.constant = 0;
|
||||
self.passwordContainerTopConstraint.constant = 50;
|
||||
|
||||
self.emailContainer.hidden = YES;
|
||||
}
|
||||
|
||||
self.userLoginContainer.hidden = NO;
|
||||
self.passwordContainer.hidden = NO;
|
||||
self.repeatPasswordContainer.hidden = NO;
|
||||
}
|
||||
|
||||
CGRect frame = self.repeatPasswordContainer.frame;
|
||||
self.viewHeightConstraint.constant = frame.origin.y + frame.size.height;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CGFloat)actualHeight
|
||||
- (void)prepareParameters:(void (^)(NSDictionary *parameters))callback;
|
||||
{
|
||||
return self.viewHeightConstraint.constant;
|
||||
if (callback)
|
||||
{
|
||||
// Prepare here parameters dict by checking each required fields.
|
||||
NSDictionary *parameters = nil;
|
||||
|
||||
// Remove whitespace in user login text field
|
||||
NSString *userLogin = self.userLoginTextField.text;
|
||||
self.userLoginTextField.text = [userLogin stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
|
||||
// Handle here the supported login flow
|
||||
if (type == MXKAuthenticationTypeLogin)
|
||||
{
|
||||
if (self.isPasswordBasedFlowSupported)
|
||||
{
|
||||
// Check required fields
|
||||
if (self.userLoginTextField.text.length && self.passWordTextField.text.length)
|
||||
{
|
||||
//Check whether user login is an email or a username.
|
||||
NSString *user = self.userLoginTextField.text;
|
||||
|
||||
if ([MXTools isEmailAddress:user])
|
||||
{
|
||||
parameters = @{
|
||||
@"type": kMXLoginFlowTypePassword,
|
||||
@"medium": @"email",
|
||||
@"address": user,
|
||||
@"password": self.passWordTextField.text
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = @{
|
||||
@"type": kMXLoginFlowTypePassword,
|
||||
@"user": user,
|
||||
@"password": self.passWordTextField.text
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inputsAlert)
|
||||
{
|
||||
[inputsAlert dismiss:NO];
|
||||
}
|
||||
|
||||
inputsAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"auth_invalid_login_param", @"Vector", nil) message:nil style:MXKAlertStyleAlert];
|
||||
inputsAlert.cancelButtonIndex = [inputsAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {
|
||||
inputsAlert = nil;
|
||||
}];
|
||||
|
||||
[self.delegate authInputsView:self presentMXKAlert:inputsAlert];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check the validity of the parameters
|
||||
NSString *alertTitle = nil;
|
||||
|
||||
if (!self.userLoginTextField.text.length)
|
||||
{
|
||||
// FIXME check validity of the non empty user name
|
||||
NSLog(@"[AuthInputsView] Invalid user name");
|
||||
alertTitle = NSLocalizedStringFromTable(@"auth_invalid_user_name", @"Vector", nil);
|
||||
}
|
||||
else if (!self.passWordTextField.text.length)
|
||||
{
|
||||
NSLog(@"[AuthInputsView] Missing Passwords");
|
||||
alertTitle = NSLocalizedStringFromTable(@"auth_missing_password", @"Vector", nil);
|
||||
}
|
||||
else if (self.passWordTextField.text.length < 6)
|
||||
{
|
||||
NSLog(@"[AuthInputsView] Invalid Passwords");
|
||||
alertTitle = NSLocalizedStringFromTable(@"auth_invalid_password", @"Vector", nil);
|
||||
}
|
||||
else if ([self.repeatPasswordTextField.text isEqualToString:self.passWordTextField.text] == NO)
|
||||
{
|
||||
NSLog(@"[AuthInputsView] Passwords don't match");
|
||||
alertTitle = NSLocalizedStringFromTable(@"auth_password_dont_match", @"Vector", nil);
|
||||
}
|
||||
else if (self.isEmailIdentityFlowRequired && !self.emailTextField.text.length)
|
||||
{
|
||||
NSLog(@"[AuthInputsView] Missing email");
|
||||
alertTitle = NSLocalizedStringFromTable(@"auth_missing_email", @"Vector", nil);
|
||||
}
|
||||
|
||||
if (alertTitle)
|
||||
{
|
||||
if (inputsAlert)
|
||||
{
|
||||
[inputsAlert dismiss:NO];
|
||||
}
|
||||
|
||||
inputsAlert = [[MXKAlert alloc] initWithTitle:alertTitle message:nil style:MXKAlertStyleAlert];
|
||||
inputsAlert.cancelButtonIndex = [inputsAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {
|
||||
inputsAlert = nil;
|
||||
}];
|
||||
|
||||
[self.delegate authInputsView:self presentMXKAlert:inputsAlert];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check whether an email has been set, and if it is not handled yet
|
||||
if (!self.emailContainer.isHidden && self.emailTextField.text.length && !self.isEmailIdentityFlowCompleted)
|
||||
{
|
||||
// Retrieve the REST client from delegate
|
||||
MXRestClient *restClient;
|
||||
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsViewEmailValidationRestClient:)])
|
||||
{
|
||||
restClient = [self.delegate authInputsViewEmailValidationRestClient:self];
|
||||
}
|
||||
|
||||
if (restClient)
|
||||
{
|
||||
// Launch email validation
|
||||
submittedEmail = [[MXK3PID alloc] initWithMedium:kMX3PIDMediumEmail andAddress:self.emailTextField.text];
|
||||
[submittedEmail requestValidationTokenWithMatrixRestClient:restClient
|
||||
success:^{
|
||||
|
||||
NSURL *identServerURL = [NSURL URLWithString:restClient.identityServer];
|
||||
NSDictionary *parameters;
|
||||
parameters = @{
|
||||
@"auth": @{@"session":currentSession.session, @"threepid_creds": @{@"client_secret": submittedEmail.clientSecret, @"id_server": identServerURL.host, @"sid": submittedEmail.sid}, @"type": kMXLoginFlowTypeEmailIdentity},
|
||||
@"username": self.userLoginTextField.text,
|
||||
@"password": self.passWordTextField.text,
|
||||
@"bind_email": @(YES)
|
||||
};
|
||||
|
||||
[self hideInputsContainer];
|
||||
|
||||
self.messageLabel.text = NSLocalizedStringFromTable(@"auth_email_validation_message", @"Vector", nil);
|
||||
self.messageLabel.hidden = NO;
|
||||
|
||||
callback(parameters);
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
NSLog(@"[AuthInputsView] Failed to request email token: %@", error);
|
||||
|
||||
callback(nil);
|
||||
|
||||
}];
|
||||
|
||||
// Async response
|
||||
return;
|
||||
}
|
||||
else if (self.isEmailIdentityFlowRequired)
|
||||
{
|
||||
NSLog(@"[AuthInputsView] Authentication failed during the email identity stage");
|
||||
}
|
||||
}
|
||||
else if (self.isRecaptchaFlowRequired)
|
||||
{
|
||||
[self displayRecaptchaForm:^(NSString *response) {
|
||||
|
||||
if (response.length)
|
||||
{
|
||||
NSDictionary *parameters = @{
|
||||
@"auth": @{@"session":currentSession.session, @"response": response, @"type": kMXLoginFlowTypeRecaptcha},
|
||||
@"username": self.userLoginTextField.text,
|
||||
@"password": self.passWordTextField.text,
|
||||
@"bind_email": [NSNumber numberWithBool:self.isEmailIdentityFlowCompleted]
|
||||
};
|
||||
|
||||
callback(parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[AuthInputsView] reCaptcha stage failed");
|
||||
callback(nil);
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
// Async response
|
||||
return;
|
||||
}
|
||||
else if (self.isPasswordBasedFlowSupported)
|
||||
{
|
||||
parameters = @{
|
||||
@"username": self.userLoginTextField.text,
|
||||
@"password": self.passWordTextField.text,
|
||||
@"bind_email": @(NO)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callback(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateAuthSessionWithCompletedStages:(NSArray *)completedStages didUpdateParameters:(void (^)(NSDictionary *parameters))callback
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
if (currentSession)
|
||||
{
|
||||
currentSession.completed = completedStages;
|
||||
|
||||
// Check the supported use case
|
||||
if ([completedStages indexOfObject:kMXLoginFlowTypeEmailIdentity] != NSNotFound && self.isRecaptchaFlowRequired)
|
||||
{
|
||||
[self displayRecaptchaForm:^(NSString *response) {
|
||||
|
||||
if (response.length)
|
||||
{
|
||||
// Update the parameters dict
|
||||
NSDictionary *parameters = @{
|
||||
@"auth": @{@"session": currentSession.session, @"response": response, @"type": kMXLoginFlowTypeRecaptcha},
|
||||
@"username": self.userLoginTextField.text,
|
||||
@"password": self.passWordTextField.text,
|
||||
@"bind_email": @(YES)
|
||||
};
|
||||
|
||||
callback (parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[AuthInputsView] reCaptcha stage failed");
|
||||
callback (nil);
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NSLog(@"[AuthInputsView] updateAuthSessionWithCompletedStages failed");
|
||||
callback (nil);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)areAllRequiredFieldsFilled
|
||||
{
|
||||
if (self.isPasswordBasedFlowSupported)
|
||||
{
|
||||
if (type == MXKAuthenticationTypeLogin)
|
||||
{
|
||||
return (self.userLoginTextField.text.length && self.passWordTextField.text.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (self.userLoginTextField.text.length && self.passWordTextField.text.length && self.repeatPasswordTextField.text.length);
|
||||
}
|
||||
}
|
||||
// Input fields are checked during parameters preparation
|
||||
return YES;
|
||||
}
|
||||
|
||||
return (self.userLoginTextField.text.length && (!self.isEmailIdentityFlowRequired || self.emailTextField.text.length) && self.passWordTextField.text.length && self.repeatPasswordTextField.text.length);
|
||||
- (BOOL)shouldPromptUserForEmailAddress
|
||||
{
|
||||
return (self.isEmailIdentityFlowSupported && !self.emailTextField.text.length);
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard
|
||||
|
@ -124,11 +395,8 @@
|
|||
// "Done" key has been pressed
|
||||
[textField resignFirstResponder];
|
||||
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsDoneKeyHasBeenPressed:)])
|
||||
{
|
||||
// Launch authentication now
|
||||
[self.delegate authInputsDoneKeyHasBeenPressed:self];
|
||||
}
|
||||
[self.delegate authInputsViewDidPressDoneKey:self];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -152,6 +420,59 @@
|
|||
|
||||
#pragma mark -
|
||||
|
||||
- (void)hideInputsContainer
|
||||
{
|
||||
// Hide all inputs container
|
||||
self.userLoginContainer.hidden = YES;
|
||||
self.passwordContainer.hidden = YES;
|
||||
self.emailContainer.hidden = YES;
|
||||
self.repeatPasswordContainer.hidden = YES;
|
||||
|
||||
// Hide other items
|
||||
self.messageLabel.hidden = YES;
|
||||
self.recaptchaWebView.hidden = YES;
|
||||
}
|
||||
|
||||
- (BOOL)displayRecaptchaForm:(void (^)(NSString *response))callback
|
||||
{
|
||||
// Retrieve the site key
|
||||
NSString *siteKey;
|
||||
|
||||
id recaptchaParams = [currentSession.params objectForKey:kMXLoginFlowTypeRecaptcha];
|
||||
if (recaptchaParams && [recaptchaParams isKindOfClass:NSDictionary.class])
|
||||
{
|
||||
NSDictionary *recaptchaParamsDict = (NSDictionary*)recaptchaParams;
|
||||
siteKey = [recaptchaParamsDict objectForKey:@"public_key"];
|
||||
}
|
||||
|
||||
// Retrieve the REST client from delegate
|
||||
MXRestClient *restClient;
|
||||
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsViewEmailValidationRestClient:)])
|
||||
{
|
||||
restClient = [self.delegate authInputsViewEmailValidationRestClient:self];
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (siteKey.length && restClient && callback)
|
||||
{
|
||||
[self hideInputsContainer];
|
||||
|
||||
self.messageLabel.hidden = NO;
|
||||
self.messageLabel.text = NSLocalizedStringFromTable(@"auth_recaptcha_message", @"Vector", nil);
|
||||
|
||||
self.recaptchaWebView.hidden = NO;
|
||||
CGRect frame = self.recaptchaWebView.frame;
|
||||
self.viewHeightConstraint.constant = frame.origin.y + frame.size.height;
|
||||
|
||||
[self.recaptchaWebView openRecaptchaWidgetWithSiteKey:siteKey fromHomeServer:restClient.homeserver callback:callback];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Tell whether a flow type is supported or not by this view.
|
||||
- (BOOL)isSupportedFlowType:(MXLoginFlowType)flowType
|
||||
{
|
||||
|
@ -258,9 +579,9 @@
|
|||
|
||||
- (BOOL)isPasswordBasedFlowSupported
|
||||
{
|
||||
if (session)
|
||||
if (currentSession)
|
||||
{
|
||||
for (MXLoginFlow *loginFlow in session.flows)
|
||||
for (MXLoginFlow *loginFlow in currentSession.flows)
|
||||
{
|
||||
if ([loginFlow.type isEqualToString:kMXLoginFlowTypePassword] || [loginFlow.stages indexOfObject:kMXLoginFlowTypePassword] != NSNotFound)
|
||||
{
|
||||
|
@ -274,9 +595,9 @@
|
|||
|
||||
- (BOOL)isEmailIdentityFlowSupported
|
||||
{
|
||||
if (session)
|
||||
if (currentSession)
|
||||
{
|
||||
for (MXLoginFlow *loginFlow in session.flows)
|
||||
for (MXLoginFlow *loginFlow in currentSession.flows)
|
||||
{
|
||||
if ([loginFlow.stages indexOfObject:kMXLoginFlowTypeEmailIdentity] != NSNotFound || [loginFlow.type isEqualToString:kMXLoginFlowTypeEmailIdentity])
|
||||
{
|
||||
|
@ -290,9 +611,9 @@
|
|||
|
||||
- (BOOL)isEmailIdentityFlowRequired
|
||||
{
|
||||
if (session && session.flows)
|
||||
if (currentSession && currentSession.flows)
|
||||
{
|
||||
for (MXLoginFlow *loginFlow in session.flows)
|
||||
for (MXLoginFlow *loginFlow in currentSession.flows)
|
||||
{
|
||||
if ([loginFlow.stages indexOfObject:kMXLoginFlowTypeEmailIdentity] == NSNotFound && ![loginFlow.type isEqualToString:kMXLoginFlowTypeEmailIdentity])
|
||||
{
|
||||
|
@ -306,4 +627,35 @@
|
|||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isEmailIdentityFlowCompleted
|
||||
{
|
||||
if (currentSession && currentSession.completed)
|
||||
{
|
||||
if ([currentSession.completed indexOfObject:kMXLoginFlowTypeEmailIdentity] != NSNotFound)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isRecaptchaFlowRequired
|
||||
{
|
||||
if (currentSession && currentSession.flows)
|
||||
{
|
||||
for (MXLoginFlow *loginFlow in currentSession.flows)
|
||||
{
|
||||
if ([loginFlow.stages indexOfObject:kMXLoginFlowTypeRecaptcha] == NSNotFound && ![loginFlow.type isEqualToString:kMXLoginFlowTypeRecaptcha])
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
<constraint firstAttribute="height" constant="21" id="Kvu-hz-22A"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done" secureTextEntry="YES"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="emailAddress" returnKeyType="done"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="x74-04-ezp" id="ViI-x8-eWu"/>
|
||||
</connections>
|
||||
|
@ -142,22 +142,41 @@
|
|||
<constraint firstItem="BQM-LP-8Eq" firstAttribute="top" secondItem="rb1-L5-udI" secondAttribute="top" constant="18" id="yhI-hm-zp5"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="68j-f9-JG4">
|
||||
<rect key="frame" x="8" y="8" width="38" height="18"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<webView hidden="YES" contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="whs-Ob-uzD" customClass="MXKAuthenticationRecaptchaWebView">
|
||||
<rect key="frame" x="0.0" y="26" width="600" height="500"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="500" id="Opu-bi-f6t"/>
|
||||
</constraints>
|
||||
</webView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="UfH-jv-6w4" firstAttribute="top" secondItem="x74-04-ezp" secondAttribute="top" constant="50" id="1LY-GW-rgL"/>
|
||||
<constraint firstItem="rb1-L5-udI" firstAttribute="top" secondItem="x74-04-ezp" secondAttribute="top" constant="150" id="75U-tx-PsQ"/>
|
||||
<constraint firstItem="UfH-jv-6w4" firstAttribute="leading" secondItem="x74-04-ezp" secondAttribute="leading" id="7Bk-GF-MZ0"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="68j-f9-JG4" secondAttribute="trailing" constant="8" id="8Aa-YT-MP5"/>
|
||||
<constraint firstAttribute="trailing" secondItem="UfH-jv-6w4" secondAttribute="trailing" id="8dz-wY-Kxx"/>
|
||||
<constraint firstItem="whs-Ob-uzD" firstAttribute="centerX" secondItem="x74-04-ezp" secondAttribute="centerX" id="8lX-k1-85c"/>
|
||||
<constraint firstItem="68j-f9-JG4" firstAttribute="top" secondItem="x74-04-ezp" secondAttribute="top" constant="8" id="BK1-XE-vz5"/>
|
||||
<constraint firstItem="bXz-VI-5FS" firstAttribute="leading" secondItem="x74-04-ezp" secondAttribute="leading" id="Frq-sH-HZT"/>
|
||||
<constraint firstItem="xOW-lo-QGC" firstAttribute="leading" secondItem="x74-04-ezp" secondAttribute="leading" id="NOu-LR-RvE"/>
|
||||
<constraint firstAttribute="trailing" secondItem="bXz-VI-5FS" secondAttribute="trailing" id="NiV-pJ-PfV"/>
|
||||
<constraint firstAttribute="trailing" secondItem="xOW-lo-QGC" secondAttribute="trailing" id="SNm-WQ-Piu"/>
|
||||
<constraint firstItem="xOW-lo-QGC" firstAttribute="top" secondItem="x74-04-ezp" secondAttribute="top" id="WmX-gO-hPJ"/>
|
||||
<constraint firstItem="rb1-L5-udI" firstAttribute="leading" secondItem="x74-04-ezp" secondAttribute="leading" id="XAJ-ST-sWV"/>
|
||||
<constraint firstItem="68j-f9-JG4" firstAttribute="leading" secondItem="x74-04-ezp" secondAttribute="leading" constant="8" id="aYh-VJ-bss"/>
|
||||
<constraint firstAttribute="trailing" secondItem="rb1-L5-udI" secondAttribute="trailing" id="c49-Cf-H9a"/>
|
||||
<constraint firstItem="bXz-VI-5FS" firstAttribute="top" secondItem="x74-04-ezp" secondAttribute="top" id="enV-j0-cgR"/>
|
||||
<constraint firstItem="whs-Ob-uzD" firstAttribute="top" secondItem="68j-f9-JG4" secondAttribute="bottom" id="g87-rp-bgb"/>
|
||||
<constraint firstAttribute="height" constant="200" id="qBF-0J-3VM"/>
|
||||
<constraint firstItem="whs-Ob-uzD" firstAttribute="width" secondItem="x74-04-ezp" secondAttribute="width" id="wa3-pP-FzX"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
|
@ -167,10 +186,12 @@
|
|||
<outlet property="emailContainer" destination="bXz-VI-5FS" id="4J7-D0-Dmf"/>
|
||||
<outlet property="emailSeparator" destination="YQ4-Kj-XPh" id="iub-NG-iJR"/>
|
||||
<outlet property="emailTextField" destination="odF-W1-Vdr" id="DOS-H7-MZy"/>
|
||||
<outlet property="messageLabel" destination="68j-f9-JG4" id="LfM-qs-gEM"/>
|
||||
<outlet property="passWordTextField" destination="6rs-rR-DkS" id="VeL-kt-Fpp"/>
|
||||
<outlet property="passwordContainer" destination="UfH-jv-6w4" id="aGz-rZ-j5q"/>
|
||||
<outlet property="passwordContainerTopConstraint" destination="1LY-GW-rgL" id="feb-7y-uob"/>
|
||||
<outlet property="passwordSeparator" destination="vUH-bJ-5gJ" id="mub-of-o9s"/>
|
||||
<outlet property="recaptchaWebView" destination="whs-Ob-uzD" id="0S8-PN-Ykm"/>
|
||||
<outlet property="repeatPasswordContainer" destination="rb1-L5-udI" id="NjO-O7-WYX"/>
|
||||
<outlet property="repeatPasswordSeparator" destination="ddx-5u-PbG" id="MtA-Rf-dhU"/>
|
||||
<outlet property="repeatPasswordTextField" destination="BQM-LP-8Eq" id="mgM-dU-mJo"/>
|
||||
|
|
Loading…
Reference in a new issue