|
@@ -2,7 +2,7 @@
|
|
|
// CCLogin.m
|
|
|
// Crypto Cloud Technology Nextcloud
|
|
|
//
|
|
|
-// Created by Marino Faggiana on 11/09/14.
|
|
|
+// Created by Marino Faggiana on 09/04/15.
|
|
|
// Copyright (c) 2014 TWS. All rights reserved.
|
|
|
//
|
|
|
// Author Marino Faggiana <m.faggiana@twsweb.it>
|
|
@@ -22,250 +22,258 @@
|
|
|
//
|
|
|
|
|
|
#import "CCLogin.h"
|
|
|
-
|
|
|
#import "AppDelegate.h"
|
|
|
+#import "CCUtility.h"
|
|
|
+#import "CCCoreData.h"
|
|
|
|
|
|
@implementation CCLogin
|
|
|
|
|
|
-- (id)initWithCoder:(NSCoder *)aDecoder
|
|
|
-{
|
|
|
- if (self = [super initWithCoder:aDecoder]) {
|
|
|
-
|
|
|
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginCorrect) name:@"messageLoginCorrect" object:nil];
|
|
|
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginIncorrect) name:@"messageLoginIncorrect" object:nil];
|
|
|
- }
|
|
|
- return self;
|
|
|
-}
|
|
|
-
|
|
|
- (void)viewDidLoad
|
|
|
{
|
|
|
[super viewDidLoad];
|
|
|
|
|
|
- self.brand.image = [UIImage imageNamed:image_launchscreen];
|
|
|
+ if (([app.typeCloud isEqualToString:typeCloudNextcloud] || [app.typeCloud isEqualToString:typeCloudOwnCloud])&& app.activeAccount) {
|
|
|
+ self.baseUrl.text = app.activeUrl;
|
|
|
+ self.user.text = app.activeUser;
|
|
|
+ }
|
|
|
|
|
|
- [_nextcloud setTitle:[NSString stringWithFormat:@" %@", NSLocalizedString(@"_add_your_nextcloud_", nil)] forState:UIControlStateNormal];
|
|
|
+ [self.baseUrl setDelegate:self];
|
|
|
+ [self.password setDelegate:self];
|
|
|
+ [self.user setDelegate:self];
|
|
|
+
|
|
|
+ [self.baseUrl setFont:[UIFont systemFontOfSize:13]];
|
|
|
+ [self.user setFont:[UIFont systemFontOfSize:13]];
|
|
|
+ [self.password setFont:[UIFont systemFontOfSize:13]];
|
|
|
+
|
|
|
+ self.loadingBaseUrl.image = [UIImage animatedImageWithAnimatedGIFURL:[[NSBundle mainBundle] URLForResource: @"loading" withExtension:@"gif"]];
|
|
|
+ self.loadingBaseUrl.hidden = YES;
|
|
|
+
|
|
|
+ if (_modifyOnlyPassword) {
|
|
|
+ _baseUrl.userInteractionEnabled = NO;
|
|
|
+ _baseUrl.textColor = [UIColor lightGrayColor];
|
|
|
+ _user.userInteractionEnabled = NO;
|
|
|
+ _user.textColor = [UIColor lightGrayColor];
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
--(void)viewDidAppear:(BOOL)animated
|
|
|
+- (void)viewWillAppear:(BOOL)animated
|
|
|
{
|
|
|
- [super viewDidAppear:animated];
|
|
|
+ [super viewWillAppear:animated];
|
|
|
+
|
|
|
+ [self.annulla setTitle:NSLocalizedString(@"_cancel_", nil) forState:UIControlStateNormal];
|
|
|
+ [self.login setTitle:NSLocalizedString(@"_login_", nil) forState:UIControlStateNormal];
|
|
|
|
|
|
- [self selectFunction];
|
|
|
+ // verify URL
|
|
|
+ if (_modifyOnlyPassword && [self.baseUrl.text length] > 0)
|
|
|
+ [self testUrl];
|
|
|
}
|
|
|
|
|
|
-#pragma --------------------------------------------------------------------------------------------
|
|
|
-#pragma mark == select Function ==
|
|
|
-#pragma --------------------------------------------------------------------------------------------
|
|
|
-
|
|
|
-- (void)selectFunction
|
|
|
+- (BOOL)textFieldShouldReturn:(UITextField *)textField
|
|
|
{
|
|
|
- // Show Intro
|
|
|
- if ([CCUtility getIntro:@"1.0"] == NO) {
|
|
|
-
|
|
|
- self.intro = [[CCIntro alloc] initWithDelegate:self delegateView:self.view];
|
|
|
- [self.intro showIntroCryptoCloud:2.0];
|
|
|
- }
|
|
|
-
|
|
|
- //REMOVECODE
|
|
|
- /*
|
|
|
- // Request : Passcode
|
|
|
- if ([CCUtility getIntro:@"1.0"] == YES && [[CCUtility getKeyChainPasscodeForUUID:[CCUtility getUUID]] length] == 0) {
|
|
|
-
|
|
|
- [self passcodeVC];
|
|
|
- }
|
|
|
-
|
|
|
- // Request : Send Passcode email
|
|
|
- if ([CCUtility getIntro:@"1.0"] == YES && [[CCUtility getKeyChainPasscodeForUUID:[CCUtility getUUID]] length] > 0 && [CCUtility getEmail] == nil && [app.activeAccount length] == 0) {
|
|
|
-
|
|
|
- CCSecurityOptions *viewController = [[CCSecurityOptions alloc] initWithDelegate:self];
|
|
|
- UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
|
|
|
- [navigationController setModalPresentationStyle:UIModalPresentationFormSheet];
|
|
|
-
|
|
|
- [self presentViewController:navigationController animated:YES completion:nil];
|
|
|
- }
|
|
|
+ [textField resignFirstResponder];
|
|
|
+ return YES;
|
|
|
+}
|
|
|
|
|
|
-
|
|
|
- // OK all - Close
|
|
|
- if ([CCUtility getIntro:@"1.0"] == YES && [[CCUtility getKeyChainPasscodeForUUID:[CCUtility getUUID]] length] > 0 && [app.activeAccount length] > 0) {
|
|
|
-
|
|
|
- [self loginCorrect];
|
|
|
- }
|
|
|
- */
|
|
|
-
|
|
|
- if ([CCUtility getIntro:@"1.0"] == YES && [app.activeAccount length] > 0) {
|
|
|
- [self loginCorrect];
|
|
|
- }
|
|
|
+- (void)didReceiveMemoryWarning
|
|
|
+{
|
|
|
+ [super didReceiveMemoryWarning];
|
|
|
+ // Dispose of any resources that can be recreated.
|
|
|
}
|
|
|
|
|
|
#pragma --------------------------------------------------------------------------------------------
|
|
|
-#pragma mark == IBAction ==
|
|
|
+#pragma mark == Chech Server URL ==
|
|
|
#pragma --------------------------------------------------------------------------------------------
|
|
|
|
|
|
-- (IBAction)handleNextcloud:(id)sender
|
|
|
+- (void)testUrl
|
|
|
{
|
|
|
- //REMOVECODE
|
|
|
- // Request CODE
|
|
|
- /*
|
|
|
- if ([[CCUtility getKeyChainPasscodeForUUID:[CCUtility getUUID]] length] == 0) {
|
|
|
-
|
|
|
- [self passcodeVC];
|
|
|
- return;
|
|
|
- }
|
|
|
- */
|
|
|
+ self.login.enabled = NO;
|
|
|
+ self.loadingBaseUrl.hidden = NO;
|
|
|
|
|
|
- CCLoginNCOC *loginVC = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"CCLoginNextcloud"];
|
|
|
+ NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.baseUrl.text] cachePolicy:0 timeoutInterval:20.0];
|
|
|
+ [request addValue:[CCUtility getUserAgent:_typeCloud] forHTTPHeaderField:@"User-Agent"];
|
|
|
|
|
|
- [loginVC setModifyOnlyPassword:NO];
|
|
|
- [loginVC setTypeCloud:typeCloudNextcloud];
|
|
|
+ NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
|
|
+ NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
|
|
|
|
|
|
- [self presentViewController:loginVC animated:YES completion:NULL];
|
|
|
-}
|
|
|
-
|
|
|
-#pragma --------------------------------------------------------------------------------------------
|
|
|
-#pragma mark == BKPasscodeViewController ==
|
|
|
-#pragma --------------------------------------------------------------------------------------------
|
|
|
+ NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) {
|
|
|
+
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ self.login.enabled = YES;
|
|
|
+ self.loadingBaseUrl.hidden = YES;
|
|
|
+ });
|
|
|
|
|
|
-- (void)passcodeViewController:(BKPasscodeViewController *)aViewController didFinishWithPasscode:(NSString *)aPasscode
|
|
|
-{
|
|
|
- switch (aViewController.type) {
|
|
|
- case BKPasscodeViewControllerNewPasscodeType:
|
|
|
- case BKPasscodeViewControllerCheckPasscodeType: {
|
|
|
+ if (error != nil) {
|
|
|
|
|
|
- // min passcode 4 chars
|
|
|
- if ([aPasscode length] >= 4) {
|
|
|
+ NSLog(@"[LOG] Error: %ld - %@",(long)[error code] , [error localizedDescription]);
|
|
|
|
|
|
- [CCUtility setKeyChainPasscodeForUUID:[CCUtility getUUID] conPasscode:aPasscode];
|
|
|
-
|
|
|
- // verify
|
|
|
- NSString *pwd = [CCUtility getKeyChainPasscodeForUUID:[CCUtility getUUID]];
|
|
|
-
|
|
|
- if ([pwd isEqualToString:aPasscode] == NO || pwd == nil) {
|
|
|
-
|
|
|
- UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"_error_", nil) message:@"Fatal error writing key" delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"_ok_", nil), nil];
|
|
|
- [alertView show];
|
|
|
- }
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"_error_", nil) message:NSLocalizedString(@"_passcode_too_short_", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"_ok_", nil), nil];
|
|
|
- [alertView show];
|
|
|
- }
|
|
|
+ // self signed certificate
|
|
|
+ if ([error code] == NSURLErrorServerCertificateUntrusted) {
|
|
|
+
|
|
|
+ NSLog(@"[LOG] Error NSURLErrorServerCertificateUntrusted");
|
|
|
+
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ [[CCCertificate sharedManager] presentViewControllerCertificateWithTitle:[error localizedDescription] viewController:self delegate:self];
|
|
|
+ });
|
|
|
|
|
|
- [aViewController dismissViewControllerAnimated:YES completion:nil];
|
|
|
- }
|
|
|
- break;
|
|
|
- case BKPasscodeViewControllerChangePasscodeType:
|
|
|
- if ([aPasscode length]) {
|
|
|
+ } else {
|
|
|
|
|
|
- // [CCUtility WriteDatiLogin:@"" ConNomeUtente:@"" ConPassword:@"" ConPassCode:aPasscode];
|
|
|
- // [aViewController dismissViewControllerAnimated:YES completion:nil];
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+
|
|
|
+ alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"_connection_error_",nil) message:[error localizedDescription] delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"_ok_", nil), nil];
|
|
|
+ [alertView show];
|
|
|
+
|
|
|
+ if (!_modifyOnlyPassword)
|
|
|
+ self.baseUrl.text = @"";
|
|
|
+ });
|
|
|
}
|
|
|
+
|
|
|
+ }
|
|
|
+ }];
|
|
|
+
|
|
|
+ [task resume];
|
|
|
+}
|
|
|
|
|
|
- self.failedAttempts = 0;
|
|
|
- self.lockUntilDate = nil;
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
+- (void)trustedCerticateAccepted
|
|
|
+{
|
|
|
+ NSLog(@"[LOG] Certificate trusted");
|
|
|
}
|
|
|
|
|
|
-- (void)passcodeViewController:(BKPasscodeViewController *)aViewController authenticatePasscode:(NSString *)aPasscode resultHandler:(void (^)(BOOL))aResultHandler
|
|
|
+- (void)trustedCerticateDenied
|
|
|
{
|
|
|
- if ([aPasscode length]) {
|
|
|
-
|
|
|
- self.lockUntilDate = nil;
|
|
|
- self.failedAttempts = 0;
|
|
|
- aResultHandler(YES);
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- aResultHandler(NO);
|
|
|
- }
|
|
|
+ if (_modifyOnlyPassword)
|
|
|
+ [self handleAnnulla:self];
|
|
|
}
|
|
|
|
|
|
-- (void)passcodeViewControllerDidFailAttempt:(BKPasscodeViewController *)aViewController
|
|
|
+-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
|
|
|
+{
|
|
|
+ // The pinnning check
|
|
|
+
|
|
|
+ if ([[CCCertificate sharedManager] checkTrustedChallenge:challenge]) {
|
|
|
+ completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
|
|
|
+ } else {
|
|
|
+ completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#pragma --------------------------------------------------------------------------------------------
|
|
|
+#pragma mark == Login ==
|
|
|
+#pragma --------------------------------------------------------------------------------------------
|
|
|
+
|
|
|
+- (void)loginCloud
|
|
|
{
|
|
|
- self.failedAttempts++;
|
|
|
+ self.login.enabled = NO;
|
|
|
+ self.loadingBaseUrl.hidden = NO;
|
|
|
+
|
|
|
+ // remove last char if /
|
|
|
+ if ([[self.baseUrl.text substringFromIndex:[self.baseUrl.text length] - 1] isEqualToString:@"/"])
|
|
|
+ self.baseUrl.text = [self.baseUrl.text substringToIndex:[self.baseUrl.text length] - 1];
|
|
|
+
|
|
|
+ OCnetworking *ocNet = [[OCnetworking alloc] initWithDelegate:self metadataNet:nil withUser:self.user.text withPassword:self.password.text withUrl:nil withTypeCloud:_typeCloud activityIndicator:NO isCryptoCloudMode:NO];
|
|
|
+ NSError *error = [ocNet readFileSync:[NSString stringWithFormat:@"%@%@", self.baseUrl.text, webDAV]];
|
|
|
|
|
|
- if (self.failedAttempts > 5) {
|
|
|
+ if (!error) {
|
|
|
|
|
|
- NSTimeInterval timeInterval = 60;
|
|
|
+ // account
|
|
|
+ NSString *account = [NSString stringWithFormat:@"%@ %@", self.user.text, self.baseUrl.text];
|
|
|
|
|
|
- if (self.failedAttempts > 6) {
|
|
|
+ if (_modifyOnlyPassword) {
|
|
|
|
|
|
- NSUInteger multiplier = self.failedAttempts - 6;
|
|
|
+ [CCCoreData updateAccount:account withPassword:self.password.text];
|
|
|
|
|
|
- timeInterval = (5 * 60) * multiplier;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ [CCCoreData deleteAccount:account];
|
|
|
+
|
|
|
+ // Add default account
|
|
|
+ [CCCoreData addAccount:account url:self.baseUrl.text user:self.user.text password:self.password.text uid:nil typeCloud:_typeCloud];
|
|
|
+ }
|
|
|
+
|
|
|
+ TableAccount *tableAccount = [CCCoreData setActiveAccount:account];
|
|
|
+
|
|
|
+ // verifica
|
|
|
+ if ([tableAccount.account isEqualToString:account]) {
|
|
|
|
|
|
- if (timeInterval > 3600 * 24) {
|
|
|
- timeInterval = 3600 * 24;
|
|
|
- }
|
|
|
+ [app settingActiveAccount:tableAccount.account activeUrl:tableAccount.url activeUser:tableAccount.user activePassword:tableAccount.password activeUID:nil activeAccessToken:nil typeCloud:tableAccount.typeCloud];
|
|
|
+
|
|
|
+ [self dismissViewControllerAnimated:YES completion:nil];
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ if (_modifyOnlyPassword == NO)
|
|
|
+ [CCCoreData deleteAccount:account];
|
|
|
+
|
|
|
+ alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"_error_", nil) message:@"Fatal error writing database" delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"_ok_", nil), nil];
|
|
|
+ [alertView show];
|
|
|
}
|
|
|
+
|
|
|
+ } else {
|
|
|
|
|
|
- self.lockUntilDate = [NSDate dateWithTimeIntervalSinceNow:timeInterval];
|
|
|
+ if ([error code] != NSURLErrorServerCertificateUntrusted) {
|
|
|
+
|
|
|
+ NSString *description = [error.userInfo objectForKey:@"NSLocalizedDescription"];
|
|
|
+ NSString *message = [NSString stringWithFormat:@"%@.\n%@", NSLocalizedStringFromTable(@"_not_possible_connect_to_server_", @"Error", nil), description];
|
|
|
+
|
|
|
+ alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"_error_", nil) message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"_ok_", nil), nil];
|
|
|
+ [alertView show];
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ self.login.enabled = YES;
|
|
|
+ self.loadingBaseUrl.hidden = YES;
|
|
|
}
|
|
|
|
|
|
-- (NSUInteger)passcodeViewControllerNumberOfFailedAttempts:(BKPasscodeViewController *)aViewController
|
|
|
-{
|
|
|
- return self.failedAttempts;
|
|
|
-}
|
|
|
+#pragma --------------------------------------------------------------------------------------------
|
|
|
+#pragma mark == TextField ==
|
|
|
+#pragma --------------------------------------------------------------------------------------------
|
|
|
|
|
|
-- (NSDate *)passcodeViewControllerLockUntilDate:(BKPasscodeViewController *)aViewController
|
|
|
+-(void)textFieldDidBeginEditing:(UITextField *)textField
|
|
|
{
|
|
|
- return self.lockUntilDate;
|
|
|
+ if (textField == self.password) {
|
|
|
+ self.toggleVisiblePassword.hidden = NO;
|
|
|
+ self.password.defaultTextAttributes = @{NSFontAttributeName: [UIFont systemFontOfSize:14.0f], NSForegroundColorAttributeName: [UIColor darkGrayColor]};
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-- (void)passcodeViewCloseButtonPressed:(id)sender
|
|
|
+-(void)textFieldDidEndEditing:(UITextField *)textField
|
|
|
{
|
|
|
- [self dismissViewControllerAnimated:YES completion:nil];
|
|
|
+ if (textField == self.password) {
|
|
|
+ self.toggleVisiblePassword.hidden = YES;
|
|
|
+ self.password.defaultTextAttributes = @{NSFontAttributeName: [UIFont systemFontOfSize:14.0f], NSForegroundColorAttributeName: [UIColor darkGrayColor]};
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
#pragma --------------------------------------------------------------------------------------------
|
|
|
-#pragma mark == Intro Delegate ==
|
|
|
+#pragma mark == IBAction ==
|
|
|
#pragma --------------------------------------------------------------------------------------------
|
|
|
|
|
|
-- (void)introDidFinish:(EAIntroView *)introView wasSkipped:(BOOL)wasSkipped
|
|
|
+- (IBAction)handlebaseUrlchange:(id)sender
|
|
|
{
|
|
|
- [CCUtility setIntro:@"1.0"];
|
|
|
-
|
|
|
- [self selectFunction];
|
|
|
+ if ([self.baseUrl.text length] > 0)
|
|
|
+ [self performSelector:@selector(testUrl) withObject:nil];
|
|
|
}
|
|
|
|
|
|
-#pragma --------------------------------------------------------------------------------------------
|
|
|
-#pragma mark == navigation ==
|
|
|
-#pragma --------------------------------------------------------------------------------------------
|
|
|
-
|
|
|
-- (void)passcodeVC
|
|
|
+- (IBAction)handleButtonLogin:(id)sender
|
|
|
{
|
|
|
- CCBKPasscode *viewController = [[CCBKPasscode alloc] initWithNibName:nil bundle:nil];
|
|
|
- viewController.delegate = self;
|
|
|
- viewController.type = BKPasscodeViewControllerNewPasscodeType;
|
|
|
-
|
|
|
- viewController.passcodeStyle = BKPasscodeInputViewNormalPasscodeStyle;
|
|
|
- viewController.passcodeInputView.maximumLength = 64;
|
|
|
-
|
|
|
- viewController.title = NSLocalizedString(@"_key_aes_256_", nil);
|
|
|
-
|
|
|
- UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
|
|
|
-
|
|
|
- [self presentViewController:navigationController animated:YES completion:nil];
|
|
|
+ if ([self.baseUrl.text length] > 0 && [self.user.text length] && [self.password.text length])
|
|
|
+ [self performSelector:@selector(loginCloud) withObject:nil];
|
|
|
}
|
|
|
|
|
|
-- (void)loginCorrect
|
|
|
-{
|
|
|
- [[NSNotificationCenter defaultCenter] postNotificationName:@"initializeMain" object:nil];
|
|
|
+- (IBAction)handleAnnulla:(id)sender
|
|
|
+{
|
|
|
+ [[NSNotificationCenter defaultCenter] postNotificationName:@"messageLoginIncorrect" object:nil];
|
|
|
|
|
|
- // close
|
|
|
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
|
|
-
|
|
|
- [self dismissViewControllerAnimated:YES completion:nil];
|
|
|
- });
|
|
|
+ [self dismissViewControllerAnimated:YES completion:nil];
|
|
|
}
|
|
|
|
|
|
-- (void)loginIncorrect
|
|
|
+- (IBAction)handleToggleVisiblePassword:(id)sender
|
|
|
{
|
|
|
- NSLog(@"[LOG] Incorrect login");
|
|
|
+ NSString *currentPassword = self.password.text;
|
|
|
+
|
|
|
+ self.password.secureTextEntry = ! self.password.secureTextEntry;
|
|
|
+
|
|
|
+ self.password.text = @"";
|
|
|
+ self.password.text = currentPassword;
|
|
|
+ self.password.defaultTextAttributes = @{NSFontAttributeName: [UIFont systemFontOfSize:14.0f], NSForegroundColorAttributeName: [UIColor darkGrayColor]};
|
|
|
}
|
|
|
|
|
|
@end
|