diff --git a/OneTimePasswordExample.xcodeproj/project.pbxproj b/OneTimePasswordExample.xcodeproj/project.pbxproj index 635e20d..ad0a947 100644 --- a/OneTimePasswordExample.xcodeproj/project.pbxproj +++ b/OneTimePasswordExample.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 089ECCC427417C0400C7EAB8 /* OneTimePasswordSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 089ECCC327417C0400C7EAB8 /* OneTimePasswordSettings.m */; }; 08C8E26D26BBA376006D4608 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 08C8E26C26BBA376006D4608 /* AppDelegate.m */; }; 08C8E27026BBA376006D4608 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 08C8E26F26BBA376006D4608 /* SceneDelegate.m */; }; 08C8E27326BBA376006D4608 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 08C8E27226BBA376006D4608 /* ViewController.m */; }; @@ -21,6 +22,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 089ECCC227417C0400C7EAB8 /* OneTimePasswordSettings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneTimePasswordSettings.h; sourceTree = ""; }; + 089ECCC327417C0400C7EAB8 /* OneTimePasswordSettings.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneTimePasswordSettings.m; sourceTree = ""; }; 08C8E26826BBA376006D4608 /* OneTimePasswordExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OneTimePasswordExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 08C8E26B26BBA376006D4608 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 08C8E26C26BBA376006D4608 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; @@ -55,6 +58,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 089ECCC127417BDA00C7EAB8 /* Model */ = { + isa = PBXGroup; + children = ( + 089ECCC227417C0400C7EAB8 /* OneTimePasswordSettings.h */, + 089ECCC327417C0400C7EAB8 /* OneTimePasswordSettings.m */, + ); + path = Model; + sourceTree = ""; + }; 08C8E25F26BBA376006D4608 = { isa = PBXGroup; children = ( @@ -76,6 +88,7 @@ 08C8E26A26BBA376006D4608 /* OneTimePasswordExample */ = { isa = PBXGroup; children = ( + 089ECCC127417BDA00C7EAB8 /* Model */, 4F8B41272705F8A900CF6A1A /* SettingsTableViewCell.h */, 4F8B41282705F8CF00CF6A1A /* SettingsTableViewCell.m */, 08C8E26B26BBA376006D4608 /* AppDelegate.h */, @@ -215,6 +228,7 @@ 4F8B41252703520D00CF6A1A /* SettingController.m in Sources */, 08C8E27E26BBA377006D4608 /* main.m in Sources */, 08C8E27026BBA376006D4608 /* SceneDelegate.m in Sources */, + 089ECCC427417C0400C7EAB8 /* OneTimePasswordSettings.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/OneTimePasswordExample/Model/OneTimePasswordSettings.h b/OneTimePasswordExample/Model/OneTimePasswordSettings.h new file mode 100644 index 0000000..2105e5d --- /dev/null +++ b/OneTimePasswordExample/Model/OneTimePasswordSettings.h @@ -0,0 +1,38 @@ +// +// OneTimePasswordSettings.h +// OneTimePasswordExample +// +// Created by KAWASHIMA Yoshiyuki on 2021/11/15. +// + +#import +#import "OneTimePassword.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface OneTimePasswordSettings : NSObject + +@property (nonatomic) NSData *secretData; +@property (nonatomic) NSString *name; +@property (nonatomic) NSString *issuer; +@property (nonatomic) OTPAlgorithm algorithm; +@property (nonatomic) NSUInteger digits; +@property (nonatomic) NSTimeInterval period; + ++ (instancetype)sharedInstance; + +- (NSString *)generateOneTimePassword; + +// 設定の比較用に文字列表現を取得できるようにする +- (NSString *)algorithmString; +- (NSString *)digitsString; +- (NSString *)periodString; + +// 設定の文字列から保存できるようにする +- (void)saveAlgorithmString:(NSString *)algorithmString; +- (void)saveDigitsString:(NSString *)digitsString; +- (void)savePeriodString:(NSString *)periodString; + +@end + +NS_ASSUME_NONNULL_END diff --git a/OneTimePasswordExample/Model/OneTimePasswordSettings.m b/OneTimePasswordExample/Model/OneTimePasswordSettings.m new file mode 100644 index 0000000..bf8513a --- /dev/null +++ b/OneTimePasswordExample/Model/OneTimePasswordSettings.m @@ -0,0 +1,67 @@ +// +// OneTimePasswordSettings.m +// OneTimePasswordExample +// +// Created by KAWASHIMA Yoshiyuki on 2021/11/15. +// + +#import "OneTimePasswordSettings.h" +#import + +@implementation OneTimePasswordSettings + ++ (instancetype)sharedInstance { + static OneTimePasswordSettings *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[OneTimePasswordSettings alloc] init]; + + NSString *name = @"..."; + NSString *issuer = @"..."; + NSString *secretString = @"..."; + + NSData *secretData = [NSData dataWithBase32String:secretString]; + + sharedInstance.secretData = secretData; + sharedInstance.name = name; + sharedInstance.issuer = issuer; + sharedInstance.algorithm = [OTPToken defaultAlgorithm]; + sharedInstance.digits = [OTPToken defaultDigits]; + sharedInstance.period = [OTPToken defaultPeriod]; + }); + return sharedInstance; +} + +- (NSString *)generateOneTimePassword { + OTPToken *token = [OTPToken tokenWithType:OTPTokenTypeTimer secret:self.secretData name:self.name issuer:self.issuer]; + token.algorithm = self.algorithm; + token.digits = self.digits; + token.period = self.period; + return token.password; +} + +- (NSString *)algorithmString { + return [NSString stringForAlgorithm:self.algorithm]; +} + +- (NSString *)digitsString { + return [NSString stringWithFormat:@"%d", (int)self.digits]; +} + +- (NSString *)periodString { + return [NSString stringWithFormat:@"%d", (int)self.period]; +} + +- (void)saveAlgorithmString:(NSString *)algorithmString { + self.algorithm = [algorithmString algorithmValue]; +} + +- (void)saveDigitsString:(NSString *)digitsString { + self.digits = [digitsString intValue]; +} + +- (void)savePeriodString:(NSString *)periodString { + self.period = [periodString intValue]; +} + +@end diff --git a/OneTimePasswordExample/SettingController.m b/OneTimePasswordExample/SettingController.m index 312497b..8ad0cb8 100644 --- a/OneTimePasswordExample/SettingController.m +++ b/OneTimePasswordExample/SettingController.m @@ -7,14 +7,14 @@ #import "SettingController.h" #import "SettingsTableViewCell.h" -#import "ViewController.h" +#import "OneTimePasswordSettings.h" #pragma mark - Settings item typedef NS_ENUM(UInt8, SettingsItem) { AlgorithmItem, DigitsItem, - PeriodItme, + PeriodItem, }; extern SettingsItem SettingsItemUnknown; @@ -24,6 +24,8 @@ typedef NS_ENUM(UInt8, SettingsItem) { @interface SettingController () +@property (nonatomic) OneTimePasswordSettings *settings; + @property (nonatomic) SettingsItem settingsItem; @property (nonatomic) UIPickerView *pickerView; @@ -32,10 +34,6 @@ @interface SettingController () @property (nonatomic) NSArray *digitsPatterns; @property (nonatomic) NSArray *periodPatterns; -@property (nonatomic) NSString *algorithm; -@property (nonatomic) NSString *digits; -@property (nonatomic) NSString *period; - @end @implementation SettingController { @@ -45,6 +43,8 @@ @implementation SettingController { - (void)viewDidLoad { [super viewDidLoad]; + self.settings = [OneTimePasswordSettings sharedInstance]; + self.pickerView = [[UIPickerView alloc] init]; self.pickerView.center = self.view.center; self.pickerView.dataSource = self; @@ -54,10 +54,6 @@ - (void)viewDidLoad { self.algorithmPatterns = @[@"SHA1", @"SHA256", @"SHA512"]; self.digitsPatterns = @[@"4", @"5", @"6", @"7", @"8", @"9", @"10"]; self.periodPatterns = @[@"30", @"60"]; - - self.algorithm = self.algorithmPatterns[0]; - self.digits = self.digitsPatterns[0]; - self.period = self.periodPatterns[0]; } #pragma mark - Table view data source @@ -76,15 +72,15 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N switch (indexPath.row) { case 0: cell.titleLabel.text = @"アルゴリズム"; - cell.valueLabel.text = self.algorithm; + cell.valueLabel.text = [self.settings algorithmString]; break; case 1: cell.titleLabel.text = @"OTP桁数"; - cell.valueLabel.text = self.digits; + cell.valueLabel.text = [self.settings digitsString]; break; case 2: cell.titleLabel.text = @"タイムステップ数"; - cell.valueLabel.text = self.period; + cell.valueLabel.text = [self.settings periodString]; break; } @@ -94,8 +90,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N #pragma mark - Table view delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + // FIXME: タップしても反応しないことがある self.settingsItem = indexPath.row; - [self.pickerView selectRow:0 inComponent:0 animated:true]; + NSInteger selectRow = [self pickerSelectRowWithItem:self.settingsItem]; + [self.pickerView selectRow:selectRow inComponent:0 animated:true]; [self.pickerView reloadAllComponents]; } @@ -111,7 +109,7 @@ - (NSInteger)pickerView:(nonnull UIPickerView *)pickerView numberOfRowsInCompone return self.algorithmPatterns.count; case DigitsItem: return self.digitsPatterns.count; - case PeriodItme: + case PeriodItem: return self.periodPatterns.count; default: return 0; @@ -126,7 +124,7 @@ - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row f return self.algorithmPatterns[row]; case DigitsItem: return self.digitsPatterns[row]; - case PeriodItme: + case PeriodItem: return self.periodPatterns[row]; } @@ -136,25 +134,58 @@ - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row f - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { switch (self.settingsItem) { case AlgorithmItem: - self.algorithm = self.algorithmPatterns[row]; + [self.settings saveAlgorithmString:self.algorithmPatterns[row]]; break; case DigitsItem: - self.digits = self.digitsPatterns[row]; + [self.settings saveDigitsString:self.digitsPatterns[row]]; break; - case PeriodItme: - self.period = self.periodPatterns[row]; + case PeriodItem: + [self.settings savePeriodString:self.periodPatterns[row]]; break; } [self.tableView reloadData]; } --(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender -{ - ViewController *viewController = segue.destinationViewController; - viewController.algorithm = self.algorithm; - viewController.digits = self.digits; - viewController.period = self.period; +#pragma mark - Settigns Index + +- (NSInteger)pickerSelectRowWithItem:(SettingsItem)item{ + switch (item) { + case AlgorithmItem: + return [self indexWithAlgorithmString:[self.settings algorithmString]]; + case DigitsItem: + return [self indexWithDigitsString:[self.settings digitsString]]; + case PeriodItem: + return [self indexWithPeriodString:[self.settings periodString]]; + } + return 0; +} + +- (NSInteger)indexWithAlgorithmString:(NSString *)algorithmString { + for (int i = 0; i < self.algorithmPatterns.count; i++) { + if ([self.algorithmPatterns[i] isEqual:algorithmString]) { + return i; + } + } + return 0; +} + +- (NSInteger)indexWithDigitsString:(NSString *)digitsString { + for (int i = 0; i < self.digitsPatterns.count; i++) { + if ([self.digitsPatterns[i] isEqual:digitsString]) { + return i; + } + } + return 0; +} + +- (NSInteger)indexWithPeriodString:(NSString *)periodString { + for (int i = 0; i < self.periodPatterns.count; i++) { + if ([self.periodPatterns[i] isEqual:periodString]) { + return i; + } + } + return 0; } @end diff --git a/OneTimePasswordExample/ViewController.h b/OneTimePasswordExample/ViewController.h index a1792da..c7eff5d 100644 --- a/OneTimePasswordExample/ViewController.h +++ b/OneTimePasswordExample/ViewController.h @@ -8,9 +8,6 @@ #import @interface ViewController : UIViewController -@property (nonatomic) NSString *algorithm; -@property (nonatomic) NSString *digits; -@property (nonatomic) NSString *period; @end diff --git a/OneTimePasswordExample/ViewController.m b/OneTimePasswordExample/ViewController.m index 69b256e..2e1fe88 100644 --- a/OneTimePasswordExample/ViewController.m +++ b/OneTimePasswordExample/ViewController.m @@ -6,19 +6,18 @@ // #import "ViewController.h" -#import "OneTimePassword.h" #import "SettingController.h" -#import +#import "OneTimePasswordSettings.h" #import @interface ViewController () -@property (strong, nonatomic) OTPToken *token; +@property (strong, nonatomic) OneTimePasswordSettings *settings; @property (weak, nonatomic) IBOutlet UILabel *oneTimePasswordLabel; @property (weak, nonatomic) IBOutlet UAProgressView *oneTimePasswordProgressView; @property (nonatomic, assign) CGFloat localProgress; -@property (nonatomic) float scheduledTimerWithTimeInterval; + @end @implementation ViewController @@ -27,37 +26,12 @@ @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; - [self initOneTimePasswordToken]; [self initOneTimePasswordView]; - - [NSTimer scheduledTimerWithTimeInterval:self.scheduledTimerWithTimeInterval target:self selector:@selector(updateOneTimePasswordView:) userInfo:nil repeats:YES]; -} - -- (void)initOneTimePasswordToken { - NSString *name = @"..."; - NSString *issuer = @"..."; - NSString *secretString = @"..."; - - NSData *secretData = [NSData dataWithBase32String:secretString]; - - self.token = [OTPToken tokenWithType:OTPTokenTypeTimer secret:secretData name:name issuer:issuer]; - self.scheduledTimerWithTimeInterval = 0.03f; - if (_algorithm != nil) { - NSArray *OTPAlgorithmStrings = @[@"SHA1", @"SHA256", @"SHA512"]; - self.token.algorithm = [OTPAlgorithmStrings indexOfObject:_algorithm]; - } - if (_digits != nil) { - self.token.digits = [_digits intValue]; - } - if (_period != nil) { - self.token.period = [_period intValue]; - if([_period isEqualToString:@"60"]) { - self.scheduledTimerWithTimeInterval = 0.06f; - } - } } - (void)initOneTimePasswordView { + self.settings = [OneTimePasswordSettings sharedInstance]; + // UNIXTIME を基準にワンタイムパスワードの残りの有効時間を算出 NSInteger unixtime = [[NSDate date] timeIntervalSince1970]; _localProgress = unixtime % 30 / 30.0; @@ -65,7 +39,11 @@ - (void)initOneTimePasswordView { [self.oneTimePasswordProgressView setProgress:_localProgress animated:NO]; [self.oneTimePasswordProgressView setLineWidth:10]; - [self.oneTimePasswordLabel setText:self.token.password]; + NSString *password = [self.settings generateOneTimePassword]; + [self.oneTimePasswordLabel setText:password]; + + NSTimeInterval timeInterval = self.settings.period / 1000; + [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(updateOneTimePasswordView:) userInfo:nil repeats:YES]; } - (void)updateOneTimePasswordView:(NSTimer *)timer { @@ -74,12 +52,12 @@ - (void)updateOneTimePasswordView:(NSTimer *)timer { CGFloat newProgress = ((int)((_localProgress * 1000.0f) + 1.001) % 1000) / 1000.0f; if (newProgress < _localProgress) { - [self.oneTimePasswordLabel setText:self.token.password]; + NSString *password = [self.settings generateOneTimePassword]; + [self.oneTimePasswordLabel setText:password]; } _localProgress = newProgress; [self.oneTimePasswordProgressView setProgress:_localProgress animated:NO]; - } @end