Commit 44900bf7 authored by Vincent L. Cone's avatar Vincent L. Cone Committed by Felix Paul Kühne

Switch from SSKeychain to XKKeychain which supports generic attributes...

Switch from SSKeychain to XKKeychain which supports generic attributes additionally to a secret value. Add keychain methods to VLCNetworkServerLoginInformation. Add VLCNetworkServerLoginInformationField to add support for additional login information such as SMB workgroups. tvOS: Add support for SMB workgroups. tvOS: switch back to official CRKArrayDiff
Signed-off-by: Felix Paul Kühne's avatarFelix Paul Kühne <fkuehne@videolan.org>
parent d5b71e51
......@@ -13,7 +13,6 @@
#import <DropboxTVSDK/DropboxSDK.h>
#import "VLCDropboxController.h"
#import "VLCDropboxCollectionViewController.h"
#import "SSKeychain.h"
#import "VLCPlayerDisplayController.h"
#import "VLCOneDriveController.h"
#import "VLCOneDriveCollectionViewController.h"
......
......@@ -16,7 +16,6 @@
#import "VLCNetworkServerBrowserPlex.h"
#import "VLCNetworkServerBrowserVLCMedia.h"
#import "VLCNetworkServerBrowserFTP.h"
#import <SSKeychain/SSKeychain.h>
#import "VLCLocalNetworkServiceBrowserManualConnect.h"
#import "VLCLocalNetworkServiceBrowserPlex.h"
......@@ -29,6 +28,8 @@
#import "VLCLocalNetworkServiceBrowserBonjour.h"
#import "VLCLocalNetworkServiceBrowserHTTP.h"
#import "VLCNetworkServerLoginInformation+Keychain.h"
#import "VLCRemoteBrowsingTVCell.h"
#import "GRKArrayDiff+UICollectionView.h"
......@@ -165,8 +166,14 @@
if ([service respondsToSelector:@selector(loginInformation)]) {
VLCNetworkServerLoginInformation *login = service.loginInformation;
if (!login) return;
[self showLoginAlertWithLogin:login];
NSError *error = nil;
if ([login loadLoginInformationFromKeychainWithError:&error])
{
[self showLoginAlertWithLogin:login];
} else {
[self showKeychainLoadError:error forLogin:login];
}
return;
}
......@@ -184,55 +191,108 @@
}
}
- (void)showKeychainLoadError:(NSError *)error forLogin:(VLCNetworkServerLoginInformation *)login
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:error.localizedDescription
message:error.localizedFailureReason preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_OK", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[self showLoginAlertWithLogin:login];
}]];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)showKeychainSaveError:(NSError *)error forLogin:(VLCNetworkServerLoginInformation *)login
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:error.localizedDescription
message:error.localizedFailureReason preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_OK", nil)
style:UIAlertActionStyleDefault
handler:nil]];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)showKeychainDeleteError:(NSError *)error
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:error.localizedDescription
message:error.localizedFailureReason preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_OK", nil)
style:UIAlertActionStyleDefault
handler:nil]];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)showLoginAlertWithLogin:(nonnull VLCNetworkServerLoginInformation *)login
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"CONNECT_TO_SERVER", nil)
message:login.address preferredStyle:UIAlertControllerStyleAlert];
NSURLComponents *components = [[NSURLComponents alloc] init];
components.scheme = login.protocolIdentifier;
components.host = login.address;
components.port = login.port;
NSString *serviceIdentifier = components.URL.absoluteString;
NSString *accountName = [SSKeychain accountsForService:serviceIdentifier].firstObject[kSSKeychainAccountKey];
NSString *password = [SSKeychain passwordForService:serviceIdentifier account:accountName];
__block UITextField *usernameField = nil;
__block UITextField *passwordField = nil;
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = NSLocalizedString(@"USER_LABEL", nil);
textField.text = accountName;
textField.text = login.username;
usernameField = textField;
}];
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.secureTextEntry = YES;
textField.placeholder = NSLocalizedString(@"PASSWORD_LABEL", nil);
textField.text = password;
textField.text = login.password;
passwordField = textField;
}];
NSMutableDictionary *additionalFieldsDict = [NSMutableDictionary dictionaryWithCapacity:login.additionalFields.count];
for (VLCNetworkServerLoginInformationField *fieldInfo in login.additionalFields) {
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
switch (fieldInfo.type) {
case VLCNetworkServerLoginInformationFieldTypeNumber:
textField.keyboardType = UIKeyboardTypeNumberPad;
break;
case VLCNetworkServerLoginInformationFieldTypeText:
default:
textField.keyboardType = UIKeyboardTypeDefault;
break;
}
textField.placeholder = fieldInfo.localizedLabel;
textField.text = fieldInfo.textValue;
additionalFieldsDict[fieldInfo.identifier] = textField;
}];
}
void(^loginBlock)(BOOL) = ^(BOOL save) {
login.username = usernameField.text;
login.password = passwordField.text;
for (VLCNetworkServerLoginInformationField *fieldInfo in login.additionalFields) {
UITextField *textField = additionalFieldsDict[fieldInfo.identifier];
fieldInfo.textValue = textField.text;
}
if (save) {
NSError *error = nil;
if (![login saveLoginInformationToKeychainWithError:&error]) {
[self showKeychainSaveError:error forLogin:login];
}
}
[self showBrowserWithLogin:login];
};
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"LOGIN", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
login.username = usernameField.text;
login.password = passwordField.text;
[self showBrowserWithLogin:login];
loginBlock(NO);
}]];
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_SAVE", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
NSString *accountName = usernameField.text;
NSString *password = passwordField.text;
[SSKeychain setPassword:password forService:serviceIdentifier account:accountName];
login.username = accountName;
login.password = password;
[self showBrowserWithLogin:login];
loginBlock(YES);
}]];
if (accountName.length && password.length) {
if (login.username.length || login.password.length) {
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_DELETE", nil)
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * _Nonnull action) {
[SSKeychain deletePasswordForService:serviceIdentifier account:accountName];
NSError *error = nil;
if (![login deleteFromKeychainWithError:&error]){
[self showKeychainDeleteError:error];
}
}]];
} else {
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_ANONYMOUS_LOGIN", nil)
......
......@@ -9,7 +9,7 @@ pod 'OBSlider', '1.1.0'
pod 'InAppSettingsKit', :git => 'git://github.com/fkuehne/InAppSettingsKit.git', :commit => '415ea6bb' #tvOS fix
pod 'upnpx', '~>1.3.6'
pod 'HockeySDK', '~>3.6.4'
pod 'SSKeychain', :git => 'git://github.com/fkuehne/sskeychain.git' #iCloud Keychain sync
pod 'XKKeychain', '~>1.0'
pod 'box-ios-sdk-v2', :git => 'git://github.com/fkuehne/box-ios-sdk-v2.git' #has a logout function added
pod 'CocoaHTTPServer', :git => 'git://github.com/fkuehne/CocoaHTTPServer.git' # has our fixes
pod 'RESideMenu', '~>4.0.7'
......@@ -26,11 +26,12 @@ end
target 'VLC-TV' do
platform :tvos, '9.0'
pod 'SSKeychain', :git => 'git://github.com/fkuehne/sskeychain.git' #iCloud Keychain Sync
pod 'XKKeychain', '~>1.0'
pod 'box-ios-sdk-v2', :git => 'git://github.com/fkuehne/box-ios-sdk-v2.git' #has tvOS support added
pod 'upnpx', '~>1.3.6'
pod 'CocoaHTTPServer', :git => 'git://github.com/fkuehne/CocoaHTTPServer.git' # has our fixes
pod 'MetaDataFetcherKit', :git => 'https://code.videolan.org/fkuehne/MetaDataFetcherKit.git', :commit => '81c45087'
pod "OROpenSubtitleDownloader", :git => 'https://github.com/orta/OROpenSubtitleDownloader.git', :commit => '0509eac2'
pod 'GRKArrayDiff', :git => 'https://github.com/vlcone/GRKArrayDiff.git', :branch => 'patch-1' # added tvOS target
pod 'GRKArrayDiff', '~> 2.1'
end
......@@ -18,7 +18,7 @@ PODS:
- box-ios-sdk-v2/no-arc (= 1.2.3)
- box-ios-sdk-v2/no-arc (1.2.3)
- CocoaHTTPServer (2.3)
- GRKArrayDiff (2.0)
- GRKArrayDiff (2.1)
- HockeySDK (3.6.4)
- InAppSettingsKit (2.2.2)
- MetaDataFetcherKit (0.2.0):
......@@ -30,15 +30,15 @@ PODS:
- AFNetworking
- xmlrpc
- RESideMenu (4.0.7)
- SSKeychain (1.2.3)
- upnpx (1.3.6)
- XKKeychain (1.0.1)
- xmlrpc (2.3.4):
- NSData+Base64 (~> 1.0.0)
DEPENDENCIES:
- box-ios-sdk-v2 (from `git://github.com/fkuehne/box-ios-sdk-v2.git`)
- CocoaHTTPServer (from `git://github.com/fkuehne/CocoaHTTPServer.git`)
- GRKArrayDiff (from `https://github.com/vlcone/GRKArrayDiff.git`, branch `patch-1`)
- GRKArrayDiff (~> 2.1)
- HockeySDK (~> 3.6.4)
- InAppSettingsKit (from `git://github.com/fkuehne/InAppSettingsKit.git`, commit
`415ea6bb`)
......@@ -48,17 +48,14 @@ DEPENDENCIES:
- OROpenSubtitleDownloader (from `https://github.com/orta/OROpenSubtitleDownloader.git`,
commit `0509eac2`)
- RESideMenu (~> 4.0.7)
- SSKeychain (from `git://github.com/fkuehne/sskeychain.git`)
- upnpx (~> 1.3.6)
- XKKeychain (~> 1.0)
EXTERNAL SOURCES:
box-ios-sdk-v2:
:git: git://github.com/fkuehne/box-ios-sdk-v2.git
CocoaHTTPServer:
:git: git://github.com/fkuehne/CocoaHTTPServer.git
GRKArrayDiff:
:branch: patch-1
:git: https://github.com/vlcone/GRKArrayDiff.git
InAppSettingsKit:
:commit: 415ea6bb
:git: git://github.com/fkuehne/InAppSettingsKit.git
......@@ -68,8 +65,6 @@ EXTERNAL SOURCES:
OROpenSubtitleDownloader:
:commit: 0509eac2
:git: https://github.com/orta/OROpenSubtitleDownloader.git
SSKeychain:
:git: git://github.com/fkuehne/sskeychain.git
CHECKOUT OPTIONS:
box-ios-sdk-v2:
......@@ -78,9 +73,6 @@ CHECKOUT OPTIONS:
CocoaHTTPServer:
:commit: 570343ea4207c832e08e8d368b5e6faf35307031
:git: git://github.com/fkuehne/CocoaHTTPServer.git
GRKArrayDiff:
:commit: edc471b0a8c953d04b8c3adf931e42dc21485a1a
:git: https://github.com/vlcone/GRKArrayDiff.git
InAppSettingsKit:
:commit: 415ea6bb
:git: git://github.com/fkuehne/InAppSettingsKit.git
......@@ -90,15 +82,12 @@ CHECKOUT OPTIONS:
OROpenSubtitleDownloader:
:commit: 0509eac2
:git: https://github.com/orta/OROpenSubtitleDownloader.git
SSKeychain:
:commit: a8e9b21f96adf1ec296e51778ef137f0ea3bd078
:git: git://github.com/fkuehne/sskeychain.git
SPEC CHECKSUMS:
AFNetworking: 1100906802d9479aa0949e8e2cbc1d4e6beba327
box-ios-sdk-v2: 9423bd75373350ea40b92f3d2d6e89f81d96d634
CocoaHTTPServer: 07df8b05a8bde406fe367d22c90a24a2fd4ca49f
GRKArrayDiff: 212b45aacf6c5f691d4ee5207bfc7b9a4ececdd6
GRKArrayDiff: cf743e6b30f6b72a3763e1f16cc5d9da39af86a5
HockeySDK: c07cdd580296737edcd0963e292c19885a53f563
InAppSettingsKit: 76d5cfbaa3e3f8aa53fe3628516da7eb1aa6a5cb
MetaDataFetcherKit: 6cbb2f651c56e16015ec08535e090bc923deb6cb
......@@ -106,8 +95,8 @@ SPEC CHECKSUMS:
OBSlider: 490f108007bfdd5414a38650b211fe403a95b8a0
OROpenSubtitleDownloader: 154b8c08acbf8836b77ac259018dc8b5baef907e
RESideMenu: f24c508404b49c667344c54aba7e590883533958
SSKeychain: 3f42991739c6c60a9cf1bbd4dff6c0d3694bcf3d
upnpx: 36b1f70f4e559f35b9e5a76b730deda8f0415104
XKKeychain: 852ef663c56a7194c73d3c68e8d9d4f07b121d4f
xmlrpc: 109bb21d15ed6d108b2c1ac5973a6a223a50f5f4
COCOAPODS: 0.39.0
......@@ -13,7 +13,7 @@
#import "VLCBoxCollectionViewController.h"
#import "VLCBoxController.h"
#import <SSKeychain/SSKeychain.h>
#import <XKKeychain/XKKeychainGenericPasswordItem.h>
#import "VLCPlaybackController.h"
#import "VLCRemoteBrowsingTVCell+CloudStorage.h"
......@@ -181,7 +181,12 @@
- (void)boxApiTokenDidRefresh
{
NSString *token = [BoxSDK sharedSDK].OAuth2Session.refreshToken;
[SSKeychain setPassword:token forService:kVLCBoxService account:kVLCBoxAccount];
XKKeychainGenericPasswordItem *keychainItem = [[XKKeychainGenericPasswordItem alloc] init];
keychainItem.service = kVLCBoxService;
keychainItem.account = kVLCBoxAccount;
keychainItem.secret.stringValue = token;
[keychainItem saveWithError:nil];
NSUbiquitousKeyValueStore *ubiquitousStore = [NSUbiquitousKeyValueStore defaultStore];
[ubiquitousStore setString:token forKey:kVLCStoreBoxCredentials];
[ubiquitousStore synchronize];
......
......@@ -12,7 +12,6 @@
#import "VLCLocalNetworkServiceBrowserFTP.h"
#import "VLCNetworkServerLoginInformation.h"
#import "SSKeychain.h"
@implementation VLCLocalNetworkServiceBrowserFTP
- (instancetype)init {
......@@ -45,18 +44,6 @@ NSString *const VLCNetworkServerProtocolIdentifierFTP = @"ftp";
login.port = [NSNumber numberWithInteger:self.netService.port];
login.protocolIdentifier = VLCNetworkServerProtocolIdentifierFTP;
NSString *serviceString = [NSString stringWithFormat:@"ftp://%@", login.address];
NSArray *accounts = [SSKeychain accountsForService:serviceString];
if (!accounts) {
login.username = login.password = @"";
return login;
}
NSDictionary *account = [accounts firstObject];
NSString *username = [account objectForKey:@"acct"];
login.username = username;
login.password = [SSKeychain passwordForService:serviceString account:username];
return login;
}
@end
/*****************************************************************************
* VLC for iOS
*****************************************************************************
* Copyright (c) 2016 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Vincent L. Cone <vincent.l.cone # tuta.io>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "VLCNetworkServerLoginInformation.h"
NS_ASSUME_NONNULL_BEGIN
@interface VLCNetworkServerLoginInformation (Keychain)
- (BOOL)loadLoginInformationFromKeychainWithError:(NSError * _Nullable __autoreleasing *)error;
- (BOOL)saveLoginInformationToKeychainWithError:(NSError * _Nullable __autoreleasing *)error;
- (BOOL)deleteFromKeychainWithError:(NSError * _Nullable __autoreleasing *)error;
@end
NS_ASSUME_NONNULL_END
\ No newline at end of file
/*****************************************************************************
* VLC for iOS
*****************************************************************************
* Copyright (c) 2016 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Vincent L. Cone <vincent.l.cone # tuta.io>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "VLCNetworkServerLoginInformation+Keychain.h"
#import <XKKeychain/XKKeychainGenericPasswordItem.h>
@implementation VLCNetworkServerLoginInformation (Keychain)
- (NSString *)keychainServiceIdentifier
{
NSURLComponents *components = [[NSURLComponents alloc] init];
components.scheme = self.protocolIdentifier;
components.host = self.address;
components.port = self.port;
NSString *serviceIdentifier = components.URL.absoluteString;
return serviceIdentifier;
}
- (BOOL)loadLoginInformationFromKeychainWithError:(NSError *__autoreleasing _Nullable *)error
{
NSError *localError = nil;
XKKeychainGenericPasswordItem *keychainItem = [XKKeychainGenericPasswordItem itemsForService:self.keychainServiceIdentifier error:&localError].firstObject;
if (localError) {
if (error) {
*error = localError;
}
return NO;
}
if (!keychainItem) {
return YES;
}
self.username = keychainItem.account;
self.password = keychainItem.secret.stringValue;
NSDictionary *genericAttributes = keychainItem.generic.dictionaryValue;
for (VLCNetworkServerLoginInformationField *field in self.additionalFields) {
id value = genericAttributes[field.identifier];
if ([value isKindOfClass:[NSString class]]) {
field.textValue = value;
}
}
return YES;
}
- (BOOL)saveLoginInformationToKeychainWithError:(NSError *__autoreleasing _Nullable *)error
{
XKKeychainGenericPasswordItem *keychainItem = [XKKeychainGenericPasswordItem itemForService:self.keychainServiceIdentifier account:self.username error:nil];
if (!keychainItem) {
keychainItem = [[XKKeychainGenericPasswordItem alloc] init];
keychainItem.service = self.keychainServiceIdentifier;
keychainItem.account = self.username;
}
keychainItem.secret.stringValue = self.password;
NSArray<VLCNetworkServerLoginInformationField *> *fields = self.additionalFields;
NSUInteger fieldsCount = fields.count;
if (fieldsCount) {
NSMutableDictionary *genericAttributes = [NSMutableDictionary dictionaryWithCapacity:fieldsCount];
for (VLCNetworkServerLoginInformationField *field in fields) {
NSString *textValue = field.textValue;
if (textValue) {
genericAttributes[field.identifier] = textValue;
}
}
keychainItem.generic.dictionaryValue = genericAttributes;
}
return [keychainItem saveWithError:error];
}
- (BOOL)deleteFromKeychainWithError:(NSError *__autoreleasing _Nullable *)error
{
XKKeychainGenericPasswordItem *keychainItem = [XKKeychainGenericPasswordItem init];
keychainItem.service = self.keychainServiceIdentifier;
keychainItem.account = self.username;
return [keychainItem deleteWithError:error];
}
@end
......@@ -14,11 +14,26 @@
#import "VLCLocalNetworkService-Protocol.h"
NS_ASSUME_NONNULL_BEGIN
@interface VLCNetworkServerLoginInformationField : NSObject <VLCNetworkServerLoginInformationField>
@property (nonatomic, readonly) VLCNetworkServerLoginInformationFieldType type;
@property (nonatomic, readonly) NSString *identifier;
@property (nonatomic, readonly) NSString *localizedLabel;
@property (nonatomic, copy) NSString *textValue;
- (instancetype)initWithType:(VLCNetworkServerLoginInformationFieldType)type
identifier:(NSString *)identifier
label:(NSString *)localizedLabel
textValue:(nullable NSString *)initialValue NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
@interface VLCNetworkServerLoginInformation : NSObject <VLCNetworkServerLoginInformation>
@property (nonatomic, nullable) NSString *username;
@property (nonatomic, nullable) NSString *password;
@property (nonatomic) NSString *address;
@property (nonatomic) NSNumber *port;
@property (nonatomic) NSString *protocolIdentifier;
@property (nonatomic, copy, nullable) NSString *username;
@property (nonatomic, copy, nullable) NSString *password;
@property (nonatomic, copy) NSString *address;
@property (nonatomic, copy) NSNumber *port;
@property (nonatomic, copy) NSString *protocolIdentifier;
@property (nonatomic, copy) NSArray<VLCNetworkServerLoginInformationField *> *additionalFields;
@end
NS_ASSUME_NONNULL_END
......@@ -12,5 +12,21 @@
#import "VLCNetworkServerLoginInformation.h"
@implementation VLCNetworkServerLoginInformationField
- (instancetype)initWithType:(VLCNetworkServerLoginInformationFieldType)type identifier:(NSString *)identifier label:(NSString *)localizedLabel textValue:(NSString *)initialValue
{
self = [super init];
if (self) {
_type = type;
_identifier = [identifier copy];
_localizedLabel = [localizedLabel copy];
_textValue = [initialValue copy];
}
return self;
}
@end
@implementation VLCNetworkServerLoginInformation
@end
\ No newline at end of file
......@@ -11,7 +11,7 @@
#import "VLCPlexParser.h"
#import "VLCPlexWebAPI.h"
#import "SSKeychain.h"
#import <XKKeychain/XKKeychainGenericPasswordItem.h>
static NSString *const kPlexMediaServerDirInit = @"/library/sections";
static NSString *const kPlexVLCDeviceName = @"VLC for iOS";
......@@ -63,15 +63,14 @@ static NSString *const kPlexVLCDeviceName = @"VLC for iOS";
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if([responseString rangeOfString:@"Unauthorized"].location != NSNotFound) {
NSString *serviceString = [NSString stringWithFormat:@"plex://%@%@", address, port];
NSArray *accounts = [SSKeychain accountsForService:serviceString];
if (!accounts) {
XKKeychainGenericPasswordItem *keychainItem = [XKKeychainGenericPasswordItem itemsForService:serviceString error:nil].firstObject;
if (!keychainItem) {
serviceString = @"plex://Account";
accounts = [SSKeychain accountsForService:serviceString];
keychainItem = [XKKeychainGenericPasswordItem itemsForService:serviceString error:nil].firstObject;
}
if (accounts) {
NSDictionary *account = [accounts firstObject];
NSString *username = [account objectForKey:@"acct"];
NSString *password = [SSKeychain passwordForService:serviceString account:username];
if (keychainItem) {
NSString *username = keychainItem.account;
NSString *password = keychainItem.secret.stringValue;
auth = [PlexWebAPI PlexAuthentification:username password:password];
url = [NSURL URLWithString:[PlexWebAPI urlAuth:mediaServerUrl authentification:auth]];
......
......@@ -13,7 +13,6 @@
#import "VLCLocalNetworkServiceBrowserDSM.h"
#import "VLCNetworkServerLoginInformation.h"
@implementation VLCLocalNetworkServiceBrowserDSM
- (instancetype)init {
......@@ -37,6 +36,8 @@
NSString *const VLCNetworkServerProtocolIdentifierSMB = @"smb";
static NSString *const VLCLocalNetworkServiceDSMWorkgroupIdentifier = @"VLCLocalNetworkServiceDSMWorkgroup";
@implementation VLCLocalNetworkServiceDSM
- (UIImage *)icon {
return [UIImage imageNamed:@"serverIcon"];
......@@ -50,7 +51,11 @@ NSString *const VLCNetworkServerProtocolIdentifierSMB = @"smb";
VLCNetworkServerLoginInformation *login = [[VLCNetworkServerLoginInformation alloc] init];
login.address = self.mediaItem.url.host;
login.protocolIdentifier = VLCNetworkServerProtocolIdentifierSMB;
VLCNetworkServerLoginInformationField *workgroupField = [[VLCNetworkServerLoginInformationField alloc] initWithType:VLCNetworkServerLoginInformationFieldTypeText
identifier:VLCLocalNetworkServiceDSMWorkgroupIdentifier
label:NSLocalizedString(@"DSM_WORKGROUP", nil)
textValue:@"WORKGROUP"];
login.additionalFields = @[workgroupField];
return login;
}
......@@ -66,13 +71,21 @@ NSString *const VLCNetworkServerProtocolIdentifierSMB = @"smb";
components.host = login.address;
components.port = login.port;
NSURL *url = components.URL;
__block NSString *workgroup = nil;
[login.additionalFields enumerateObjectsUsingBlock:^(VLCNetworkServerLoginInformationField * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj.identifier isEqualToString:VLCLocalNetworkServiceDSMWorkgroupIdentifier])
{
workgroup = obj.textValue;
}
}];
return [self SMBNetworkServerBrowserWithURL:url
username:login.username
password:login.password
workgroup:nil];
workgroup:workgroup];
}
+ (instancetype)SMBNetworkServerBrowserWithURL:(NSURL *)url username:(NSString *)username password:(NSString *)password workgroup:(NSString *)workgroup
{
VLCMedia *media = [VLCMedia mediaWithURL:url];
......
......@@ -14,12 +14,25 @@
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, VLCNetworkServerLoginInformationFieldType) {
VLCNetworkServerLoginInformationFieldTypeText,
VLCNetworkServerLoginInformationFieldTypeNumber
};
@protocol VLCNetworkServerLoginInformationField <NSObject>
@property (nonatomic, readonly) VLCNetworkServerLoginInformationFieldType type;
@property (nonatomic, readonly) NSString *identifier;
@property (nonatomic, readonly) NSString *localizedLabel;
@property (nonatomic, copy) NSString *textValue;
@end
@protocol VLCNetworkServerLoginInformation <NSObject>
@property (nonatomic) NSString *username;
@property (nonatomic) NSString *password;
@property (nonatomic) NSString *address;
@property (nonatomic) NSNumber *port;
@property (nonatomic) NSString *protocolIdentifier;
@property (nonatomic, copy, nullable) NSString *username;
@property (nonatomic, copy, nullable) NSString *password;
@property (nonatomic, copy) NSString *address;
@property (nonatomic, copy) NSNumber *port;
@property (nonatomic, copy) NSString *protocolIdentifier;
@property (nonatomic, copy) NSArray< id<VLCNetworkServerLoginInformationField>> *additionalFields;
@end
@protocol VLCLocalNetworkService <NSObject>
......
......@@ -13,7 +13,7 @@
#import "VLCNetworkLoginViewController.h"
#import "VLCPlexWebAPI.h"
#import "SSKeychain.h"
#import <XKKeychain/XKKeychainGenericPasswordItem.h>
@interface VLCNetworkLoginViewController () <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate>
{
......@@ -123,7 +123,11 @@
if (count > 0) {
for (NSUInteger i = 0; i < count; i++) {
[SSKeychain setPassword:ftpPasswordList[i] forService:ftpServerList[i] account:ftpLoginList[i]];
XKKeychainGenericPasswordItem *keychainItem = [[XKKeychainGenericPasswordItem alloc] init];
keychainItem.service = ftpServerList[i];
keychainItem.account = ftpLoginList[i];
keychainItem.secret.stringValue = ftpPasswordList[i];
[keychainItem saveWithError:nil];
[_serverList addObject:ftpServerList[i]];
}
}
......@@ -283,8 +287,13 @@
NSString *username = self.usernameField.text;
NSString *password = self.passwordField.text;
if (username || password)
[SSKeychain setPassword:password forService:service account:username];
if (username || password) {
XKKeychainGenericPasswordItem *keychainItem = [[XKKeychainGenericPasswordItem alloc] init];
keychainItem.service = service;
keychainItem.account = username;
keychainItem.secret.stringValue = password;
[keychainItem saveWithError:nil];
}
[self.storedServersTableView reloadData];
}
......@@ -363,10 +372,9 @@
NSString *serviceString = _serverList[row];
NSURL *service = [NSURL URLWithString:serviceString];
cell.textLabel.text = [NSString stringWithFormat:@"%@ [%@]", service.host, [service.scheme uppercaseString]];
NSArray *accounts = [SSKeychain accountsForService:serviceString];
if (accounts.count > 0) {
NSDictionary *account = [accounts firstObject];
cell.detailTextLabel.text = [account objectForKey:@"acct"];
XKKeychainGenericPasswordItem *keychainItem = [XKKeychainGenericPasswordItem itemsForService:serviceString error:nil].firstObject;
if (keychainItem) {
cell.detailTextLabel.text = keychainItem.account;
} else
cell.detailTextLabel.text = @"";
......@@ -391,12 +399,7 @@ forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSString *serviceString = _serverList[indexPath.row];
NSArray *accounts = [SSKeychain accountsForService:serviceString];
NSUInteger count = accounts.count;
for (NSUInteger i = 0; i < count; i++) {
NSString *username = [accounts[i] objectForKey:@"acct"];
[SSKeychain deletePasswordForService:serviceString account:username];
}
[XKKeychainGenericPasswordItem removeItemsForService:serviceString error:nil];
[_serverList removeObject:serviceString];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults removeObjectForKey:serviceString];
......@@ -428,17 +431,14 @@ forRowAtIndexPath:(NSIndexPath *)indexPath
self.serverField.text = service.host;
self.portField.text = [service.port stringValue];
NSArray *accounts = [SSKeychain accountsForService:serviceString];
if (!accounts) {
XKKeychainGenericPasswordItem *keychainItem = [XKKeychainGenericPasswordItem itemsForService:serviceString error:nil].firstObject;
if (!keychainItem)