| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 |
- //
- // SAiOSPaypalPlugin.m
- // Cordova Plugin for Cordova
- //
- // Created by shazron on 10-11-05.
- // Copyright 2010 Shazron Abdullah. All rights reserved.
- #import "SAiOSKeychainPlugin.h"
- @implementation SAiOSKeychainPlugin
- -(CDVPlugin*) initWithWebView:(UIWebView*)theWebView
- {
- self = (SAiOSKeychainPlugin*)[super initWithWebView:(UIWebView*)theWebView];
- if (self) {
- // initialization here
- }
- return self;
- }
- - (void) getForKey:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
- {
- int argc = [arguments count];
- if (argc < 2) {
- return;
- }
-
- NSString* key = [arguments objectAtIndex:0];
- NSString* serviceName = [arguments objectAtIndex:1];
- NSError* error = nil;
-
- NSString* value = [SFHFKeychainUtils getPasswordForUsername:key andServiceName:serviceName error:&error];
- if (error == nil && value != nil) {
- NSString* jsCallback = [NSString stringWithFormat:@"window.plugins.keychain._onGetCallbackSuccess(\"%@\", \"%@\");", key, value];
- [super writeJavascript:jsCallback];
- } else {
- NSString* jsCallback = [NSString stringWithFormat:@"window.plugins.keychain._onGetCallbackFail(\"%@\", \"%@\");", key, [error localizedDescription]];
- [super writeJavascript:jsCallback];
- }
- }
- - (void) setForKey:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
- {
- int argc = [arguments count];
- if (argc < 3) {
- return;
- }
-
- NSString* key = [arguments objectAtIndex:0];
- NSString* value = [arguments objectAtIndex:1];
- NSString* serviceName = [arguments objectAtIndex:2];
- NSError* error = nil;
-
- BOOL stored = [SFHFKeychainUtils storeUsername:key andPassword:value forServiceName:serviceName updateExisting:YES error:&error];
- if (stored) {
- NSString* jsCallback = [NSString stringWithFormat:@"window.plugins.keychain._onSetCallbackSuccess(\"%@\");", key];
- [super writeJavascript:jsCallback];
- } else {
- NSString* jsCallback = [NSString stringWithFormat:@"window.plugins.keychain._onSetCallbackFail(\"%@\", \"%@\");", key, [error localizedDescription]];
- [super writeJavascript:jsCallback];
- }
- }
- - (void) removeForKey:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
- {
- int argc = [arguments count];
- if (argc < 2) {
- return;
- }
-
- NSString* key = [arguments objectAtIndex:0];
- NSString* serviceName = [arguments objectAtIndex:1];
- NSError* error = nil;
-
- BOOL deleted = [SFHFKeychainUtils deleteItemForUsername:key andServiceName:serviceName error:&error];
- if (deleted) {
- NSString* jsCallback = [NSString stringWithFormat:@"window.plugins.keychain._onRemoveCallbackSuccess(\"%@\");", key];
- [super writeJavascript:jsCallback];
- } else {
- NSString* jsCallback = [NSString stringWithFormat:@"window.plugins.keychain._onRemoveCallbackFail(\"%@\", \"%@\");", key, [error localizedDescription]];
- [super writeJavascript:jsCallback];
- }
- }
- @end
- //
- // SFHFKeychainUtils.m
- //
- // Created by Buzz Andersen on 10/20/08.
- // Based partly on code by Jonathan Wight, Jon Crosby, and Mike Malone.
- // Copyright 2008 Sci-Fi Hi-Fi. All rights reserved.
- //
- // Permission is hereby granted, free of charge, to any person
- // obtaining a copy of this software and associated documentation
- // files (the "Software"), to deal in the Software without
- // restriction, including without limitation the rights to use,
- // copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the
- // Software is furnished to do so, subject to the following
- // conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- // OTHER DEALINGS IN THE SOFTWARE.
- //
- #import <Security/Security.h>
- static NSString *SFHFKeychainUtilsErrorDomain = @"SFHFKeychainUtilsErrorDomain";
- #if __IPHONE_OS_VERSION_MIN_REQUIRED < 30000 && TARGET_IPHONE_SIMULATOR
- @interface SFHFKeychainUtils (PrivateMethods)
- + (SecKeychainItemRef) getKeychainItemReferenceForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;
- @end
- #endif
- @implementation SFHFKeychainUtils
- #if __IPHONE_OS_VERSION_MIN_REQUIRED < 30000 && TARGET_IPHONE_SIMULATOR
- + (NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error {
- if (!username || !serviceName) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
- return nil;
- }
-
- SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServiceName: serviceName error: error];
-
- if (*error || !item) {
- return nil;
- }
-
- // from Advanced Mac OS X Programming, ch. 16
- UInt32 length;
- char *password;
- SecKeychainAttribute attributes[8];
- SecKeychainAttributeList list;
-
- attributes[0].tag = kSecAccountItemAttr;
- attributes[1].tag = kSecDescriptionItemAttr;
- attributes[2].tag = kSecLabelItemAttr;
- attributes[3].tag = kSecModDateItemAttr;
-
- list.count = 4;
- list.attr = attributes;
-
- OSStatus status = SecKeychainItemCopyContent(item, NULL, &list, &length, (void **)&password);
-
- if (status != noErr) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
- return nil;
- }
-
- NSString *passwordString = nil;
-
- if (password != NULL) {
- char passwordBuffer[1024];
-
- if (length > 1023) {
- length = 1023;
- }
- strncpy(passwordBuffer, password, length);
-
- passwordBuffer[length] = '\0';
- passwordString = [NSString stringWithCString:passwordBuffer];
- }
-
- SecKeychainItemFreeContent(&list, password);
-
- CFRelease(item);
-
- return passwordString;
- }
- + (void) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error {
- if (!username || !password || !serviceName) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
- return;
- }
-
- OSStatus status = noErr;
-
- SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServiceName: serviceName error: error];
-
- if (*error && [*error code] != noErr) {
- return;
- }
-
- *error = nil;
-
- if (item) {
- status = SecKeychainItemModifyAttributesAndData(item,
- NULL,
- strlen([password UTF8String]),
- [password UTF8String]);
-
- CFRelease(item);
- }
- else {
- status = SecKeychainAddGenericPassword(NULL,
- strlen([serviceName UTF8String]),
- [serviceName UTF8String],
- strlen([username UTF8String]),
- [username UTF8String],
- strlen([password UTF8String]),
- [password UTF8String],
- NULL);
- }
-
- if (status != noErr) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
- }
- }
- + (void) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error {
- if (!username || !serviceName) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: 2000 userInfo: nil];
- return;
- }
-
- *error = nil;
-
- SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServiceName: serviceName error: error];
-
- if (*error && [*error code] != noErr) {
- return;
- }
-
- OSStatus status;
-
- if (item) {
- status = SecKeychainItemDelete(item);
-
- CFRelease(item);
- }
-
- if (status != noErr) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
- }
- }
- + (SecKeychainItemRef) getKeychainItemReferenceForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error {
- if (!username || !serviceName) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
- return nil;
- }
-
- *error = nil;
-
- SecKeychainItemRef item;
-
- OSStatus status = SecKeychainFindGenericPassword(NULL,
- strlen([serviceName UTF8String]),
- [serviceName UTF8String],
- strlen([username UTF8String]),
- [username UTF8String],
- NULL,
- NULL,
- &item);
-
- if (status != noErr) {
- if (status != errSecItemNotFound) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
- }
-
- return nil;
- }
-
- return item;
- }
- #else
- + (NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error {
- if (!username || !serviceName) {
- if (error != nil) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
- }
- return nil;
- }
-
- if (error != nil) {
- *error = nil;
- }
-
- // Set up a query dictionary with the base query attributes: item type (generic), username, and service
-
- NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, kSecAttrService, nil] autorelease];
- NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, username, serviceName, nil] autorelease];
-
- NSMutableDictionary *query = [[[NSMutableDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
-
- // First do a query for attributes, in case we already have a Keychain item with no password data set.
- // One likely way such an incorrect item could have come about is due to the previous (incorrect)
- // version of this code (which set the password as a generic attribute instead of password data).
-
- NSDictionary *attributeResult = NULL;
- NSMutableDictionary *attributeQuery = [query mutableCopy];
- [attributeQuery setObject: (id) kCFBooleanTrue forKey:(id) kSecReturnAttributes];
- OSStatus status = SecItemCopyMatching((CFDictionaryRef) attributeQuery, (CFTypeRef *) &attributeResult);
-
- [attributeResult release];
- [attributeQuery release];
-
- if (status != noErr) {
- // No existing item found--simply return nil for the password
- if (error != nil && status != errSecItemNotFound) {
- //Only return an error if a real exception happened--not simply for "not found."
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
- }
-
- return nil;
- }
-
- // We have an existing item, now query for the password data associated with it.
-
- NSData *resultData = nil;
- NSMutableDictionary *passwordQuery = [query mutableCopy];
- [passwordQuery setObject: (id) kCFBooleanTrue forKey: (id) kSecReturnData];
-
- status = SecItemCopyMatching((CFDictionaryRef) passwordQuery, (CFTypeRef *) &resultData);
-
- [resultData autorelease];
- [passwordQuery release];
-
- if (status != noErr) {
- if (status == errSecItemNotFound) {
- // We found attributes for the item previously, but no password now, so return a special error.
- // Users of this API will probably want to detect this error and prompt the user to
- // re-enter their credentials. When you attempt to store the re-entered credentials
- // using storeUsername:andPassword:forServiceName:updateExisting:error
- // the old, incorrect entry will be deleted and a new one with a properly encrypted
- // password will be added.
- if (error != nil) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -1999 userInfo: nil];
- }
- }
- else {
- // Something else went wrong. Simply return the normal Keychain API error code.
- if (error != nil) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
- }
- }
-
- return nil;
- }
-
- NSString *password = nil;
-
- if (resultData) {
- password = [[NSString alloc] initWithData: resultData encoding: NSUTF8StringEncoding];
- }
- else {
- // There is an existing item, but we weren't able to get password data for it for some reason,
- // Possibly as a result of an item being incorrectly entered by the previous code.
- // Set the -1999 error so the code above us can prompt the user again.
- if (error != nil) {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -1999 userInfo: nil];
- }
- }
-
- return [password autorelease];
- }
- + (BOOL) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error
- {
- if (!username || !password || !serviceName)
- {
- if (error != nil)
- {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
- }
- return NO;
- }
-
- // See if we already have a password entered for these credentials.
- NSError *getError = nil;
- NSString *existingPassword = [SFHFKeychainUtils getPasswordForUsername: username andServiceName: serviceName error:&getError];
-
- if ([getError code] == -1999)
- {
- // There is an existing entry without a password properly stored (possibly as a result of the previous incorrect version of this code.
- // Delete the existing item before moving on entering a correct one.
-
- getError = nil;
-
- [self deleteItemForUsername: username andServiceName: serviceName error: &getError];
-
- if ([getError code] != noErr)
- {
- if (error != nil)
- {
- *error = getError;
- }
- return NO;
- }
- }
- else if ([getError code] != noErr)
- {
- if (error != nil)
- {
- *error = getError;
- }
- return NO;
- }
-
- if (error != nil)
- {
- *error = nil;
- }
-
- OSStatus status = noErr;
-
- if (existingPassword)
- {
- // We have an existing, properly entered item with a password.
- // Update the existing item.
-
- if (![existingPassword isEqualToString:password] && updateExisting)
- {
- //Only update if we're allowed to update existing. If not, simply do nothing.
-
- NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass,
- kSecAttrService,
- kSecAttrLabel,
- kSecAttrAccount,
- nil] autorelease];
-
- NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword,
- serviceName,
- serviceName,
- username,
- nil] autorelease];
-
- NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
-
- status = SecItemUpdate((CFDictionaryRef) query, (CFDictionaryRef) [NSDictionary dictionaryWithObject: [password dataUsingEncoding: NSUTF8StringEncoding] forKey: (NSString *) kSecValueData]);
- }
- }
- else
- {
- // No existing entry (or an existing, improperly entered, and therefore now
- // deleted, entry). Create a new entry.
-
- NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass,
- kSecAttrService,
- kSecAttrLabel,
- kSecAttrAccount,
- kSecValueData,
- nil] autorelease];
-
- NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword,
- serviceName,
- serviceName,
- username,
- [password dataUsingEncoding: NSUTF8StringEncoding],
- nil] autorelease];
-
- NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
-
- status = SecItemAdd((CFDictionaryRef) query, NULL);
- }
-
- if (error != nil && status != noErr)
- {
- // Something went wrong with adding the new item. Return the Keychain error code.
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
-
- return NO;
- }
-
- return YES;
- }
- + (BOOL) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error
- {
- if (!username || !serviceName)
- {
- if (error != nil)
- {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
- }
- return NO;
- }
-
- if (error != nil)
- {
- *error = nil;
- }
-
- NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, kSecAttrService, kSecReturnAttributes, nil] autorelease];
- NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, username, serviceName, kCFBooleanTrue, nil] autorelease];
-
- NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
-
- OSStatus status = SecItemDelete((CFDictionaryRef) query);
-
- if (error != nil && status != noErr)
- {
- *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
-
- return NO;
- }
-
- return YES;
- }
- #endif
- @end
|