Added first implementation.

This commit is contained in:
Joel Arvidsson 2015-05-20 20:39:52 +02:00
parent d5ecf4bdaa
commit fe4642c3e0
4 changed files with 197 additions and 2 deletions

13
.editorconfig Normal file
View File

@ -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

View File

@ -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

View File

@ -17,4 +17,69 @@
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

View File

@ -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;