219 lines
7.9 KiB
Matlab
219 lines
7.9 KiB
Matlab
|
#import <Foundation/Foundation.h>
|
||
|
#import <Cordova/CDVPlugin.h>
|
||
|
#import <Cordova/CDVPluginResult.h>
|
||
|
#import "SecureStorage.h"
|
||
|
|
||
|
@implementation SecureStorage
|
||
|
|
||
|
- (void)get:(CDVInvokedUrlCommand*)command {
|
||
|
NSArray* names = [command argumentAtIndex:0];
|
||
|
NSString* collection = [command argumentAtIndex:1 withDefault:@""];
|
||
|
NSMutableDictionary* result = [NSMutableDictionary new];
|
||
|
|
||
|
NSLog(@"SecureStorage: Get values with names %@ in collection %@", names, collection);
|
||
|
|
||
|
for (NSString* name in names) {
|
||
|
NSString* value = [self getValue:name inCollection:collection];
|
||
|
if (value != nil) {
|
||
|
result[name] = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result];
|
||
|
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||
|
}
|
||
|
|
||
|
- (NSString *)getValue:(NSString*)name inCollection:(NSString*)collection {
|
||
|
if ([name length] == 0) {
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
NSDictionary* query = @{
|
||
|
(id)kSecClass: (id)kSecClassGenericPassword,
|
||
|
(id)kSecAttrAccount: name,
|
||
|
(id)kSecAttrService: collection,
|
||
|
(id)kSecReturnData: @YES,
|
||
|
(id)kSecMatchLimit: (id)kSecMatchLimitOne
|
||
|
};
|
||
|
NSData* storedData = NULL;
|
||
|
|
||
|
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (void *) &storedData);
|
||
|
|
||
|
if (status == errSecSuccess) {
|
||
|
return [[NSString alloc] initWithData:storedData encoding:NSUTF8StringEncoding];
|
||
|
} else if (status != errSecItemNotFound) {
|
||
|
NSLog(@"Error getting value for %@ in collection %@. Status: %d", name, collection, (int) status);
|
||
|
}
|
||
|
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
- (void)store:(CDVInvokedUrlCommand*)command {
|
||
|
|
||
|
NSDictionary* data = [command argumentAtIndex:0];
|
||
|
NSString* collection = [command argumentAtIndex:1 withDefault:@""];
|
||
|
NSArray* names = [data allKeys];
|
||
|
BOOL error = false;
|
||
|
|
||
|
// Variables to be able to rollback changes if something fails.
|
||
|
NSMutableArray* insertedNames = [NSMutableArray new];
|
||
|
NSMutableDictionary* previousValues = [NSMutableDictionary new];
|
||
|
|
||
|
NSLog(@"SecureStorage: Store values with names %@ in collection %@", names, collection);
|
||
|
|
||
|
for (NSString* name in data) {
|
||
|
OSStatus status;
|
||
|
NSString* storedValue = [self getValue:name inCollection:collection];
|
||
|
|
||
|
if (storedValue != nil) {
|
||
|
status = [self updateName:name withValue:data[name] inCollection: collection];
|
||
|
} else {
|
||
|
status = [self addName:name withValue:data[name] inCollection: collection];
|
||
|
}
|
||
|
|
||
|
if (status != errSecSuccess) {
|
||
|
NSLog(@"Error storing value for %@ in collection %@. Status: %d", name, collection, (int) status);
|
||
|
error = true;
|
||
|
|
||
|
// Rollback.
|
||
|
for (NSString *name in insertedNames) {
|
||
|
[self deleteName:name fromCollection:collection];
|
||
|
}
|
||
|
for(NSString *name in previousValues) {
|
||
|
[self updateName:name withValue:previousValues[name] inCollection: collection];
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
} else if (storedValue != nil) {
|
||
|
previousValues[name] = storedValue;
|
||
|
} else {
|
||
|
[insertedNames addObject:name];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CDVPluginResult* pluginResult;
|
||
|
if (error) {
|
||
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
|
||
|
messageAsString:@"Error storing one or more values in secure storage."];
|
||
|
} else {
|
||
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||
|
}
|
||
|
|
||
|
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||
|
}
|
||
|
|
||
|
- (OSStatus)addName:(NSString*)name withValue:(NSString*)value inCollection:(NSString*)collection {
|
||
|
NSData* newValue = [value dataUsingEncoding:NSUTF8StringEncoding];
|
||
|
NSMutableDictionary* query = [NSMutableDictionary new];
|
||
|
query[(id)kSecClass] = (id)kSecClassGenericPassword;
|
||
|
query[(id)kSecAttrAccount] = name;
|
||
|
query[(id)kSecAttrService] = collection;
|
||
|
query[(id)kSecAttrAccessible] = (id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
|
||
|
query[(id)kSecValueData] = newValue;
|
||
|
|
||
|
return SecItemAdd((CFDictionaryRef)query, nil);
|
||
|
}
|
||
|
|
||
|
- (OSStatus)updateName:(NSString*)name withValue:(NSString*)value inCollection:(NSString*)collection {
|
||
|
NSData* newValue = [value dataUsingEncoding:NSUTF8StringEncoding];
|
||
|
NSMutableDictionary* query = [NSMutableDictionary new];
|
||
|
query[(id)kSecClass] = (id)kSecClassGenericPassword;
|
||
|
query[(id)kSecAttrAccount] = name;
|
||
|
query[(id)kSecAttrService] = collection;
|
||
|
query[(id)kSecAttrAccessible] = (id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
|
||
|
|
||
|
return SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)@{
|
||
|
(id)kSecValueData: newValue
|
||
|
});
|
||
|
}
|
||
|
|
||
|
- (void)delete:(CDVInvokedUrlCommand*)command {
|
||
|
NSArray* names = [command argumentAtIndex:0];
|
||
|
NSString* collection = [command argumentAtIndex:1 withDefault:@""];
|
||
|
BOOL error = false;
|
||
|
|
||
|
// Variable to be able to rollback changes if something fails.
|
||
|
NSMutableDictionary* deletedValues = [NSMutableDictionary new];
|
||
|
|
||
|
NSLog(@"SecureStorage: Delete values with names %@ in collection %@", names, collection);
|
||
|
|
||
|
for (NSString* name in names) {
|
||
|
if ([name length] == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
NSString* storedValue = [self getValue:name inCollection:collection];
|
||
|
if (storedValue == nil) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
OSStatus status = [self deleteName:name fromCollection:collection];
|
||
|
|
||
|
if (status != errSecSuccess && status != errSecItemNotFound) {
|
||
|
NSLog(@"Error deleting entry with name %@ in collection %@. Status: %d", name, collection, (int) status);
|
||
|
error = true;
|
||
|
|
||
|
// Rollback.
|
||
|
for (NSString *name in deletedValues) {
|
||
|
[self addName:name withValue:deletedValues[name] inCollection:collection];
|
||
|
}
|
||
|
} else {
|
||
|
deletedValues[name] = storedValue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CDVPluginResult* pluginResult;
|
||
|
if (error) {
|
||
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
|
||
|
messageAsString:@"Error deleting one or more values from secure storage."];
|
||
|
} else {
|
||
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||
|
}
|
||
|
|
||
|
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||
|
}
|
||
|
|
||
|
- (OSStatus)deleteName:(NSString*)name fromCollection:(NSString*)collection {
|
||
|
NSDictionary* query = @{
|
||
|
(id)kSecClass: (id)kSecClassGenericPassword,
|
||
|
(id)kSecAttrAccount: name,
|
||
|
(id)kSecAttrService: collection,
|
||
|
};
|
||
|
|
||
|
return SecItemDelete((CFDictionaryRef)query);
|
||
|
}
|
||
|
|
||
|
- (void)deleteCollection:(CDVInvokedUrlCommand*)command {
|
||
|
NSString* collection = [command argumentAtIndex:0 withDefault:@""];
|
||
|
|
||
|
if ([collection length] == 0) {
|
||
|
NSLog(@"SecureStorage: Collection cannot be empty in deleteCollection");
|
||
|
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||
|
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
NSLog(@"SecureStorage: Delete all values in collection %@", collection);
|
||
|
|
||
|
NSDictionary* query = @{
|
||
|
(id)kSecClass: (id)kSecClassGenericPassword,
|
||
|
(id)kSecAttrService: collection,
|
||
|
};
|
||
|
|
||
|
OSStatus status = SecItemDelete((CFDictionaryRef)query);
|
||
|
|
||
|
CDVPluginResult* pluginResult;
|
||
|
if (status == errSecSuccess || status == errSecItemNotFound) {
|
||
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||
|
} else {
|
||
|
NSLog(@"Error deleting all values in collection %@. Status: %d", collection, (int) status);
|
||
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION
|
||
|
messageAsString:@"Error deleting values from secure storage."];
|
||
|
}
|
||
|
|
||
|
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||
|
}
|
||
|
|
||
|
@end
|