mirror of
https://github.com/SoPat712/YTLitePlus.git
synced 2025-11-01 13:23:37 -04:00
255 lines
8.6 KiB
Objective-C
255 lines
8.6 KiB
Objective-C
//
|
|
// FLEXKeychainViewController.m
|
|
// FLEX
|
|
//
|
|
// Created by ray on 2019/8/17.
|
|
// Copyright © 2020 FLEX Team. All rights reserved.
|
|
//
|
|
|
|
#import "FLEXKeychain.h"
|
|
#import "FLEXKeychainQuery.h"
|
|
#import "FLEXKeychainViewController.h"
|
|
#import "FLEXTableViewCell.h"
|
|
#import "FLEXMutableListSection.h"
|
|
#import "FLEXUtility.h"
|
|
#import "UIPasteboard+FLEX.h"
|
|
#import "UIBarButtonItem+FLEX.h"
|
|
|
|
@interface FLEXKeychainViewController ()
|
|
@property (nonatomic, readonly) FLEXMutableListSection<NSDictionary *> *section;
|
|
@end
|
|
|
|
@implementation FLEXKeychainViewController
|
|
|
|
- (id)init {
|
|
return [self initWithStyle:UITableViewStyleGrouped];
|
|
}
|
|
|
|
#pragma mark - Overrides
|
|
|
|
- (void)viewDidLoad {
|
|
[super viewDidLoad];
|
|
|
|
[self addToolbarItems:@[
|
|
FLEXBarButtonItemSystem(Add, self, @selector(addPressed)),
|
|
[FLEXBarButtonItemSystem(Trash, self, @selector(trashPressed:)) flex_withTintColor:UIColor.redColor],
|
|
]];
|
|
|
|
[self reloadData];
|
|
}
|
|
|
|
- (NSArray<FLEXTableViewSection *> *)makeSections {
|
|
_section = [FLEXMutableListSection list:FLEXKeychain.allAccounts.mutableCopy
|
|
cellConfiguration:^(__kindof FLEXTableViewCell *cell, NSDictionary *item, NSInteger row) {
|
|
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
|
|
|
id service = item[kFLEXKeychainWhereKey];
|
|
if ([service isKindOfClass:[NSString class]]) {
|
|
cell.textLabel.text = service;
|
|
cell.detailTextLabel.text = [item[kFLEXKeychainAccountKey] description];
|
|
} else {
|
|
cell.textLabel.text = [NSString stringWithFormat:
|
|
@"[%@]\n\n%@",
|
|
NSStringFromClass([service class]),
|
|
[service description]
|
|
];
|
|
}
|
|
} filterMatcher:^BOOL(NSString *filterText, NSDictionary *item) {
|
|
// Loop over contents of the keychain item looking for a match
|
|
for (NSString *field in item.allValues) {
|
|
if ([field isKindOfClass:[NSString class]]) {
|
|
if ([field localizedCaseInsensitiveContainsString:filterText]) {
|
|
return YES;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
];
|
|
|
|
return @[self.section];
|
|
}
|
|
|
|
/// We always want to show this section
|
|
- (NSArray<FLEXTableViewSection *> *)nonemptySections {
|
|
return @[self.section];
|
|
}
|
|
|
|
- (void)reloadSections {
|
|
self.section.list = FLEXKeychain.allAccounts.mutableCopy;
|
|
}
|
|
|
|
- (void)refreshSectionTitle {
|
|
self.section.customTitle = FLEXPluralString(
|
|
self.section.filteredList.count, @"items", @"item"
|
|
);
|
|
}
|
|
|
|
- (void)reloadData {
|
|
[self reloadSections];
|
|
[self refreshSectionTitle];
|
|
[super reloadData];
|
|
}
|
|
|
|
|
|
#pragma mark - Private
|
|
|
|
- (FLEXKeychainQuery *)queryForItemAtIndex:(NSInteger)idx {
|
|
NSDictionary *item = self.section.filteredList[idx];
|
|
|
|
FLEXKeychainQuery *query = [FLEXKeychainQuery new];
|
|
query.service = [item[kFLEXKeychainWhereKey] description];
|
|
query.account = [item[kFLEXKeychainAccountKey] description];
|
|
query.accessGroup = [item[kFLEXKeychainGroupKey] description];
|
|
[query fetch:nil];
|
|
|
|
return query;
|
|
}
|
|
|
|
- (void)deleteItem:(NSDictionary *)item {
|
|
NSError *error = nil;
|
|
BOOL success = [FLEXKeychain
|
|
deletePasswordForService:item[kFLEXKeychainWhereKey]
|
|
account:item[kFLEXKeychainAccountKey]
|
|
error:&error
|
|
];
|
|
|
|
if (!success) {
|
|
[FLEXAlert makeAlert:^(FLEXAlert *make) {
|
|
make.title(@"Error Deleting Item");
|
|
make.message(error.localizedDescription);
|
|
} showFrom:self];
|
|
}
|
|
}
|
|
|
|
|
|
#pragma mark Buttons
|
|
|
|
- (void)trashPressed:(UIBarButtonItem *)sender {
|
|
[FLEXAlert makeSheet:^(FLEXAlert *make) {
|
|
make.title(@"Clear Keychain");
|
|
make.message(@"This will remove all keychain items for this app.\n");
|
|
make.message(@"This action cannot be undone. Are you sure?");
|
|
make.button(@"Yes, clear the keychain").destructiveStyle().handler(^(NSArray *strings) {
|
|
[self confirmClearKeychain];
|
|
});
|
|
make.button(@"Cancel").cancelStyle();
|
|
} showFrom:self source:sender];
|
|
}
|
|
|
|
- (void)confirmClearKeychain {
|
|
[FLEXAlert makeAlert:^(FLEXAlert *make) {
|
|
make.title(@"ARE YOU SURE?");
|
|
make.message(@"This action CANNOT BE UNDONE.\nAre you sure you want to continue?\n");
|
|
make.message(@"If you're sure, scroll to confirm.");
|
|
make.button(@"Yes, clear the keychain").destructiveStyle().handler(^(NSArray *strings) {
|
|
for (id account in self.section.list) {
|
|
[self deleteItem:account];
|
|
}
|
|
|
|
[self reloadData];
|
|
});
|
|
make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel");
|
|
make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel");
|
|
make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel");
|
|
make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel"); make.button(@"Cancel");
|
|
make.button(@"Cancel").cancelStyle();
|
|
} showFrom:self];
|
|
}
|
|
|
|
- (void)addPressed {
|
|
[FLEXAlert makeAlert:^(FLEXAlert *make) {
|
|
make.title(@"Add Keychain Item");
|
|
make.textField(@"Service name, i.e. Instagram");
|
|
make.textField(@"Account");
|
|
make.textField(@"Password");
|
|
make.button(@"Cancel").cancelStyle();
|
|
make.button(@"Save").handler(^(NSArray<NSString *> *strings) {
|
|
// Display errors
|
|
NSError *error = nil;
|
|
if (![FLEXKeychain setPassword:strings[2] forService:strings[0] account:strings[1] error:&error]) {
|
|
[FLEXAlert showAlert:@"Error" message:error.localizedDescription from:self];
|
|
}
|
|
|
|
[self reloadData];
|
|
});
|
|
} showFrom:self];
|
|
}
|
|
|
|
|
|
#pragma mark - FLEXGlobalsEntry
|
|
|
|
+ (NSString *)globalsEntryTitle:(FLEXGlobalsRow)row {
|
|
return @"🔑 Keychain";
|
|
}
|
|
|
|
+ (UIViewController *)globalsEntryViewController:(FLEXGlobalsRow)row {
|
|
FLEXKeychainViewController *viewController = [self new];
|
|
viewController.title = [self globalsEntryTitle:row];
|
|
|
|
return viewController;
|
|
}
|
|
|
|
|
|
#pragma mark - Table View Data Source
|
|
|
|
- (void)tableView:(UITableView *)tv commitEditingStyle:(UITableViewCellEditingStyle)style forRowAtIndexPath:(NSIndexPath *)ip {
|
|
if (style == UITableViewCellEditingStyleDelete) {
|
|
// Update the model
|
|
NSDictionary *toRemove = self.section.filteredList[ip.row];
|
|
[self deleteItem:toRemove];
|
|
[self.section mutate:^(NSMutableArray *list) {
|
|
[list removeObject:toRemove];
|
|
}];
|
|
|
|
// Delete the row
|
|
[tv deleteRowsAtIndexPaths:@[ip] withRowAnimation:UITableViewRowAnimationAutomatic];
|
|
|
|
// Update the title by refreshing the section without disturbing the delete animation
|
|
//
|
|
// This is an ugly hack, but literally nothing else works, save for manually getting
|
|
// the header and setting its title, which I personally think is worse since it
|
|
// would need to make assumptions about the default style of the header (CAPS)
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
[self refreshSectionTitle];
|
|
[tv reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
#pragma mark - Table View Delegate
|
|
|
|
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
return YES;
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
FLEXKeychainQuery *query = [self queryForItemAtIndex:indexPath.row];
|
|
|
|
[FLEXAlert makeAlert:^(FLEXAlert *make) {
|
|
make.title(query.service);
|
|
make.message(@"Service: ").message(query.service);
|
|
make.message(@"\nAccount: ").message(query.account);
|
|
make.message(@"\nPassword: ").message(query.password);
|
|
make.message(@"\nGroup: ").message(query.accessGroup);
|
|
|
|
make.button(@"Copy Service").handler(^(NSArray<NSString *> *strings) {
|
|
[UIPasteboard.generalPasteboard flex_copy:query.service];
|
|
});
|
|
make.button(@"Copy Account").handler(^(NSArray<NSString *> *strings) {
|
|
[UIPasteboard.generalPasteboard flex_copy:query.account];
|
|
});
|
|
make.button(@"Copy Password").handler(^(NSArray<NSString *> *strings) {
|
|
[UIPasteboard.generalPasteboard flex_copy:query.password];
|
|
});
|
|
make.button(@"Dismiss").cancelStyle();
|
|
|
|
} showFrom:self];
|
|
|
|
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
|
}
|
|
|
|
@end
|