Skip to content

Commit

Permalink
Added first implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
oblador committed May 20, 2015
1 parent d5ecf4b commit fe4642c
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 2 deletions.
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,42 @@
# react-native-keychain
Keychain Access for React Native

Currently functionality is limited to just storing internet passwords. More to come...

## Installation

* `$ npm install react-native-keychain`
* Right click on Libraries, select **Add files to "…"** and select `node_modules/react-native-keychain/RNKeychain.xcodeproj`
* Select your project and under **Build Phases** -> **Link Binary With Libraries**, press the + and select `libRNKeychain.a`.


## Usage

```js
var Keychain = require('Keychain');

var server = 'http://facebook.com';
var username = 'zuck';
var password = 'poniesRgr8';
Keychain
.setInternetCredentials(server, username, password)
.then(function() {
console.log('Credentials saved successfully!')
});

Keychain
.getInternetCredentials(server)
.then(function(credentials) {
console.log('Credentials successfully loaded', credentials)
});

Keychain
.resetInternetCredentials(server)
.then(function(credentials) {
console.log('Credentials successfully deleted')
});

```

## License
MIT © Joel Arvidsson 2015
65 changes: 65 additions & 0 deletions RNKeychainManager/RNKeychainManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,69 @@ @implementation RNKeychainManager
RCT_EXPORT_MODULE();


RCT_EXPORT_METHOD(setInternetCredentialsForServer:(NSString*)server withUsername:(NSString*)username withPassword:(NSString*)password callback:(RCTResponseSenderBlock)callback){
// Create dictionary of search parameters
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassInternetPassword), kSecClass, server, kSecAttrServer, kCFBooleanTrue, kSecReturnAttributes, nil];

// Remove any old values from the keychain
OSStatus osStatus = SecItemDelete((__bridge CFDictionaryRef) dict);

// Create dictionary of parameters to add
NSData* passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
dict = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassInternetPassword), kSecClass, server, kSecAttrServer, passwordData, kSecValueData, username, kSecAttrAccount, nil];

// Try to save to keychain
osStatus = SecItemAdd((__bridge CFDictionaryRef) dict, NULL);

if (osStatus) {
NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
callback(@[error]);
}

callback(@[[NSNull null]]);

}

RCT_EXPORT_METHOD(getInternetCredentialsForServer:(NSString*)server callback:(RCTResponseSenderBlock)callback){

// Create dictionary of search parameters
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassInternetPassword), kSecClass, server, kSecAttrServer, kCFBooleanTrue, kSecReturnAttributes, kCFBooleanTrue, kSecReturnData, nil];

// Look up server in the keychain
NSDictionary* found = nil;
CFDictionaryRef foundCF;
OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef) dict, (CFTypeRef*)&foundCF);

found = (__bridge NSDictionary*)(foundCF);
if (!found) return callback(@[[NSNull null]]);

// Found
NSString* username = (NSString*) [found objectForKey:(__bridge id)(kSecAttrAccount)];
NSString* password = [[NSString alloc] initWithData:[found objectForKey:(__bridge id)(kSecValueData)] encoding:NSUTF8StringEncoding];

if (osStatus) {
NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
callback(@[error]);
}

callback(@[[NSNull null], username, password]);

}

RCT_EXPORT_METHOD(resetInternetCredentialsForServer:(NSString*)server callback:(RCTResponseSenderBlock)callback){

// Create dictionary of search parameters
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassInternetPassword), kSecClass, server, kSecAttrServer, kCFBooleanTrue, kSecReturnAttributes, kCFBooleanTrue, kSecReturnData, nil];

// Remove any old values from the keychain
OSStatus osStatus = SecItemDelete((__bridge CFDictionaryRef) dict);
if (osStatus) {
NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
callback(@[error]);
}

callback(@[[NSNull null]]);

}

@end
81 changes: 79 additions & 2 deletions index.ios.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,89 @@
/**
* @providesModule KeychainIOS
* @providesModule Keychain
*/
'use strict';

var RNKeychainManager = require('NativeModules').RNKeychainManager;
var NativeModules = require('NativeModules');
var RNKeychainManager = NativeModules.RNKeychainManager;

var Keychain = {
/**
* Saves the `username` and `password` combination for `server`
* and calls `callback` with an `Error` if there is any.
* Returns a `Promise` object.
*/
setInternetCredentials: function(
server: string,
username: string,
password: string,
callback?: ?(error: ?Error) => void
): Promise {
return new Promise((resolve, reject) => {
RNKeychainManager.setInternetCredentialsForServer(server, username, password, function(err) {
callback && callback((err && convertError(err)) || null);
if (err) {
reject(convertError(err));
} else {
resolve();
}
});
});
},

/**
* Fetches login combination for `server` as an object with the format `{ username, password }`
* and passes the result to `callback`, along with an `Error` if there is any.
* Returns a `Promise` object.
*/
getInternetCredentials: function(
server: string,
callback?: ?(error: ?Error, result: ?string) => void
): Promise {
return new Promise((resolve, reject) => {
RNKeychainManager.getInternetCredentialsForServer(server, function(err, username, password) {
err = convertError(err);
if(!err && arguments.length === 1) {
err = new Error('No keychain entry found for server "' + server + '"');
}
callback && callback((err && convertError(err)) || null, username, password);
if (err) {
reject(convertError(err));
} else {
resolve({ username, password });
}
});
});
},

/**
* Deletes all keychain entries for `server` and calls `callback` with an `Error` if there is any.
* Returns a `Promise` object.
*/
resetInternetCredentials: function(
server: string,
callback?: ?(error: ?Error) => void
): Promise {
return new Promise((resolve, reject) => {
RNKeychainManager.resetInternetCredentialsForServer(server, function(err) {
callback && callback((err && convertError(err)) || null);
if (err) {
reject(convertError(err));
} else {
resolve();
}
});
});
},

};

function convertError(err) {
if (!err) {
return null;
}
var out = new Error(err.message);
out.key = err.key;
return out;
}

module.exports = Keychain;

0 comments on commit fe4642c

Please sign in to comment.