]> git.saurik.com Git - apple/security.git/blobdiff - SharedWebCredentialViewService/SWCViewController.m
Security-57031.1.35.tar.gz
[apple/security.git] / SharedWebCredentialViewService / SWCViewController.m
diff --git a/SharedWebCredentialViewService/SWCViewController.m b/SharedWebCredentialViewService/SWCViewController.m
new file mode 100755 (executable)
index 0000000..87c85b4
--- /dev/null
@@ -0,0 +1,428 @@
+//
+//  SWCViewController.m
+//  SharedWebCredentialViewService
+//
+//  Copyright (c) 2014 Apple Inc. All Rights Reserved.
+//
+
+#import "SWCViewController.h"
+#import <UIKit/UIViewController_Private.h>
+#import <UIKit/UIFont_Private.h>
+
+#import <UIKit/UIAlertController_Private.h>
+#import <UIKit/UITableViewCell_Private.h>
+
+#include <bsm/libbsm.h>
+#include <ipc/securityd_client.h>
+#include "SharedWebCredential/swcagent_client.h"
+
+const NSString* SWC_PASSWORD_KEY = @"spwd";
+const NSString* SWC_ACCOUNT_KEY  = @"acct";
+const NSString* SWC_SERVER_KEY   = @"srvr";
+
+//
+// SWCDictionaryAdditions
+//
+
+@interface NSDictionary (SWCDictionaryAdditions)
+- (NSComparisonResult) compareCredentialDictionaryAscending:(NSDictionary *)other;
+@end
+
+@implementation NSDictionary (SWCDictionaryAdditions)
+- (NSComparisonResult)compareCredentialDictionaryAscending:(NSDictionary *)other
+{
+    NSComparisonResult result;
+    NSString *str1 = [self objectForKey:SWC_ACCOUNT_KEY], *str2 = [other objectForKey:SWC_ACCOUNT_KEY];
+    if (!str1) str1 = @"";
+    if (!str2) str2 = @"";
+    
+    // primary sort by account name
+    result = [str1 localizedCaseInsensitiveCompare:str2];
+    if (result == NSOrderedSame) {
+        // secondary sort by domain name
+        NSString *str3 = [self objectForKey:SWC_SERVER_KEY], *str4 = [other objectForKey:SWC_SERVER_KEY];
+        if (!str3) str3 = @"";
+        if (!str4) str4 = @"";
+        
+        result = [str3 localizedCaseInsensitiveCompare:str4];
+    }
+    
+    return result;
+}
+@end
+
+
+//
+// SWCItemCell
+//
+@interface SWCItemCell : UITableViewCell
+{
+    NSDictionary *_dict;
+    BOOL _isTicked;
+    UIView *_bottomLine;
+    UIView *_bottomLineSelected;
+    UIView *_topLine;
+    UIView *_topLineSelected;
+    BOOL _showSeparator;
+    BOOL _showTopSeparator;
+}
+
+- (id)initWithDictionary:(NSDictionary *)dict;
+@property (nonatomic, readonly) id userInfo;
+@property (nonatomic, assign) BOOL showSeparator;
+@end
+
+@implementation SWCItemCell
+
+@synthesize showSeparator = _showSeparator;
+
+- (id)initWithDictionary:(NSDictionary *)dict
+{
+    if ((self = [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil]))
+    {
+        _dict = dict;
+        
+        self.selectionStyle = UITableViewCellSelectionStyleNone;
+        
+        self.backgroundColor = [UIColor colorWithWhite:0.1 alpha:0.005];
+        
+        self.textLabel.textColor = [UIColor blackColor];
+        self.textLabel.textAlignment = NSTextAlignmentLeft;
+        self.textLabel.AdjustsFontSizeToFitWidth = YES;
+        self.textLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
+        
+        NSString *title = [dict objectForKey:SWC_ACCOUNT_KEY];
+        self.textLabel.text = title ? title : @"--";
+        
+        self.detailTextLabel.textColor = [UIColor darkGrayColor];
+        self.detailTextLabel.textAlignment = NSTextAlignmentLeft;
+        self.detailTextLabel.AdjustsFontSizeToFitWidth = YES;
+        self.detailTextLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
+        
+        NSString *subtitle = [dict objectForKey:SWC_SERVER_KEY];
+        self.detailTextLabel.text = subtitle ? subtitle : @"--";
+        
+        self.backgroundView = [[UIView alloc] init];
+        self.backgroundView.backgroundColor = self.backgroundColor;
+        
+        self.imageView.image = [self _checkmarkImage: NO];
+        self.imageView.hidden = YES;
+        
+    }
+    
+    return self;
+}
+
+- (void)setTicked: (BOOL) selected
+{
+    _isTicked = selected;
+}
+
+- (void)layoutSubviews
+{
+    
+    if (_bottomLine) {
+        CGFloat scale = [[UIScreen mainScreen] scale];
+        [_bottomLine setFrame:CGRectMake(0, self.frame.size.height - (1 / scale), self.frame.size.width, 1 / scale)];
+    }
+    
+    if (_bottomLineSelected) {
+        CGFloat scale = [[UIScreen mainScreen] scale];
+        [_bottomLineSelected setFrame:CGRectMake(0, self.frame.size.height - (1 / scale), self.frame.size.width, 1 / scale)];
+    }
+    
+    if (_topLine) {
+        CGFloat scale = [[UIScreen mainScreen] scale];
+        [_topLine setFrame:CGRectMake(0, 0, self.frame.size.width, 1 / scale)];
+    }
+    
+    if (_topLineSelected) {
+        CGFloat scale = [[UIScreen mainScreen] scale];
+        [_topLineSelected setFrame:CGRectMake(0, 0, self.frame.size.width, 1 / scale)];
+    }
+    
+    if (_isTicked)
+    {
+        self.imageView.hidden = NO;
+    } else {
+        self.imageView.hidden = YES;
+    }
+    
+    [super layoutSubviews];
+    
+}
+
+- (void)setShowSeparator:(BOOL)showSeparator {
+    if (_showSeparator != showSeparator) {
+        _showSeparator = showSeparator;
+        
+        if (_showSeparator) {
+            if (!_bottomLine) {
+                CGRect rectZero = CGRectMake(0, 0, 0, 0);
+                _bottomLine = [[UIView alloc] initWithFrame:rectZero];
+                _bottomLine.backgroundColor = [UIColor colorWithWhite:.5 alpha:.5];
+                [self.backgroundView addSubview:_bottomLine];
+            }
+            if (!_bottomLineSelected) {
+                CGRect rectZero = CGRectMake(0, 0, 0, 0);
+                _bottomLineSelected = [[UIView alloc] initWithFrame:rectZero];
+                _bottomLineSelected.backgroundColor = [UIColor colorWithWhite:.5 alpha:.5];
+                [self.selectedBackgroundView addSubview: _bottomLineSelected];
+            }
+            
+        } else {
+            if (_bottomLine) {
+                [_bottomLine removeFromSuperview];
+                _bottomLine = nil;
+            }
+            if (_bottomLineSelected) {
+                [_bottomLineSelected removeFromSuperview];
+                _bottomLineSelected = nil;
+            }
+        }
+    }
+}
+
+- (void)setShowTopSeparator:(BOOL)showTopSeparator {
+    if (_showTopSeparator != showTopSeparator) {
+        _showTopSeparator = showTopSeparator;
+        
+        if (_showTopSeparator) {
+            if (!_topLine) {
+                CGRect rectZero = CGRectMake(0, 0, 0, 0);
+                _topLine = [[UIView alloc] initWithFrame:rectZero];
+                _topLine.backgroundColor = [UIColor colorWithWhite:.5 alpha:.5];
+                [self.backgroundView addSubview:_topLine];
+            }
+            if (!_topLineSelected) {
+                CGRect rectZero = CGRectMake(0, 0, 0, 0);
+                _topLineSelected = [[UIView alloc] initWithFrame:rectZero];
+                _topLineSelected.backgroundColor = [UIColor colorWithWhite:.5 alpha:.5];
+                [self.selectedBackgroundView addSubview: _topLineSelected];
+            }
+            
+        } else {
+            if (_topLine) {
+                [_topLine removeFromSuperview];
+                _topLine = nil;
+            }
+            if (_topLineSelected) {
+                [_topLineSelected removeFromSuperview];
+                _topLineSelected = nil;
+            }
+        }
+    }
+}
+
+@end
+
+
+//
+// SWCViewController
+//
+
+@interface SWCViewController ()
+{
+    NSMutableArray       *_credentials; // array of NSDictionary
+    UILabel              *_topLabel;
+    UILabel              *_middleLabel;
+    UITableView          *_table;
+    NSDictionary         *_selectedDict;
+    NSIndexPath          *_selectedCell;
+}
+
+@end
+
+@implementation SWCViewController
+
+- (NSDictionary *)selectedItem
+{
+    return _selectedDict;
+}
+
+- (void)setCredentials:(NSArray *)inArray
+{
+    NSMutableArray *credentials = [[NSMutableArray alloc] initWithArray:inArray];
+    [credentials sortUsingSelector:@selector(compareCredentialDictionaryAscending:)];
+    _credentials = credentials;
+    if (_table)
+        [_table reloadData];
+}
+
+- (void)_enableTable
+{
+    [_table setUserInteractionEnabled:YES];
+}
+
+- (UITableView *)tableView
+{
+    if (_table == nil) {
+        _table = [[UITableView alloc] init];
+        [_table setTranslatesAutoresizingMaskIntoConstraints:NO];
+        [_table setAutoresizingMask:UIViewAutoresizingNone];
+        [_table setBackgroundColor:[UIColor clearColor]];
+        [_table setSeparatorStyle:UITableViewCellSeparatorStyleNone];
+    }
+    [_table sizeToFit];
+    
+    return (UITableView *)_table;
+}
+
+-(void)loadView
+{
+    
+    UIView* view = [[UIView alloc] init];
+    
+    UITableView* table = [self tableView];
+    [table setDelegate: self];
+    [table setDataSource: self];
+    
+    [view addSubview: table];
+    
+    CFErrorRef error = NULL;
+    audit_token_t auditToken = {};
+    memset(&auditToken, 0, sizeof(auditToken));
+    CFArrayRef credentialList = swca_copy_pairs(swca_copy_pairs_request_id, &auditToken, &error);
+    if (error) {
+        NSLog(@"Unable to get accounts: %@", [(__bridge NSError*)error localizedDescription]);
+    }
+    
+    [self setCredentials:(__bridge NSArray*)credentialList];
+    if (credentialList) {
+        CFRelease(credentialList);
+    }
+    
+    
+    NSDictionary* views = NSDictionaryOfVariableBindings(table);
+    
+    if ([_credentials count] > 2)
+    {
+        
+        NSDictionary *metrics = @{@"height":@120.0};
+        [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[table]-|"  options:0 metrics:metrics views:views]];
+        [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[table(height)]-|" options:0 metrics:metrics views:views]];
+        
+        CGFloat scale = [[UIScreen mainScreen] scale];
+        table.layer.borderWidth = 1.0 / scale;
+        table.layer.borderColor = [UIColor colorWithWhite:.5 alpha:.5].CGColor;
+        
+        [self setPreferredContentSize:CGSizeMake(0,140)];
+        
+    } else if ([_credentials count] == 2) {
+        
+        NSDictionary *metrics = @{@"height":@90.0};
+        [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[table]|"  options:0 metrics:metrics views:views]];
+        [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[table(height)]-|" options:0 metrics:metrics views:views]];
+        
+        [self setPreferredContentSize:CGSizeMake(0,90)];
+        [table setScrollEnabled: NO];
+        
+    } else {  // [_credentials count] == 1
+        
+        NSDictionary *metrics = @{@"height":@45.0};
+        [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[table]|"  options:0 metrics:metrics views:views]];
+        [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[table(height)]|" options:0 metrics:metrics views:views]];
+        
+        [self setPreferredContentSize:CGSizeMake(0,45)];
+        [table setScrollEnabled: NO];
+        
+    }
+    
+    [self setView:view];
+}
+
+-(void)viewWillAppear:(BOOL)animated
+{
+    
+    // Select the first cell by default
+    
+    NSDictionary *dict = [_credentials objectAtIndex: 0];
+    _selectedDict = dict;
+    _selectedCell = [NSIndexPath indexPathForItem:0 inSection: 0];
+    SWCItemCell *cell = (SWCItemCell *)[_table cellForRowAtIndexPath: _selectedCell];
+    [cell setTicked: YES];
+    [_table selectRowAtIndexPath: _selectedCell animated: NO scrollPosition: UITableViewScrollPositionTop];
+    
+    CFErrorRef error = NULL;
+    audit_token_t auditToken = {};
+    memset(&auditToken, 0, sizeof(auditToken));
+    bool result = swca_set_selection(swca_set_selection_request_id,
+                                     &auditToken, (__bridge CFDictionaryRef)dict, &error);
+    if (!result) {
+        NSLog(@"Unable to select item: %@", [(__bridge NSError*)error localizedDescription]);
+    }
+    
+    [super viewWillAppear:animated];
+}
+
+
+//
+// UITableView delegate methods
+//
+
+- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
+{
+    return [_credentials count];
+}
+
+- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    NSUInteger row = indexPath.row;
+    
+    NSDictionary *dict = [_credentials objectAtIndex:row];
+    _selectedDict = dict;
+    
+    CFErrorRef error = NULL;
+    audit_token_t auditToken = {};
+    memset(&auditToken, 0, sizeof(auditToken));
+    bool result = swca_set_selection(swca_set_selection_request_id,
+                                     &auditToken, (__bridge CFDictionaryRef)dict, &error);
+    if (!result) {
+        NSLog(@"Unable to select item: %@", [(__bridge NSError*)error localizedDescription]);
+    }
+    
+    _selectedCell = indexPath;
+    SWCItemCell *cell = (SWCItemCell *)[tableView cellForRowAtIndexPath: indexPath];
+    [cell setTicked: YES];
+    [cell layoutSubviews];
+}
+
+- (void) tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    SWCItemCell *cell = (SWCItemCell *)[tableView cellForRowAtIndexPath: indexPath];
+    [cell setTicked: NO];
+    [cell layoutSubviews];
+    
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    
+    NSDictionary *dict = [_credentials objectAtIndex:[indexPath row]];
+    SWCItemCell *cell = [[SWCItemCell alloc] initWithDictionary:dict];
+    
+    // show separator on top cell if there's only or or two items
+    if ([_credentials count] <= 2) {
+        cell.showTopSeparator = YES;
+    } else {
+        cell.showSeparator = YES;
+        
+        if (indexPath.row == 0)
+        {
+            cell.showTopSeparator = YES;
+        }
+        
+    }
+    
+    if (_selectedCell == indexPath)
+    {
+        [cell setTicked: YES];
+    } else {
+        [cell setTicked: NO];
+    }
+    
+    return cell;
+}
+
+
+@end