Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add account to Options structure (#112) #643

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ Both `setGenericPassword` and `setInternetCredentials` are limited to strings on

Will store the username/password combination in the secure storage. Resolves to `{service, storage}` or rejects in case of an error. `storage` - is a name of used internal cipher for saving secret; `service` - name used for storing secret in internal storage (empty string resolved to valid default name).

### `getGenericPassword([{ authenticationPrompt, service, accessControl }])`
### `getGenericPassword([{ accessControl, account, authenticationPrompt, service }])`

Will retrieve the username/password combination from the secure storage. Resolves to `{ username, password, service, storage }` if an entry exists or `false` if it doesn't. It will reject only if an unexpected error is encountered like lacking entitlements or permission.

Expand Down Expand Up @@ -171,7 +171,8 @@ Get security level that is supported on the current device with the current OS.
| -------------------------- |---------------| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
| **`accessControl`** | All | This dictates how a keychain item may be used, see possible values in `Keychain.ACCESS_CONTROL`. | _None_ |
| **`accessible`** | iOS, visionOS | This dictates when a keychain item is accessible, see possible values in `Keychain.ACCESSIBLE`. | _`Keychain.ACCESSIBLE.WHEN_UNLOCKED`_ |
| **`accessGroup`** | iOS, visionOS | In which App Group to share the keychain. Requires additional setup with entitlements. | _None_ |
| **`accessGroup`** | iOS, visionOS | In which App Group to share the keychain. Requires additional setup with entitlements. | _None_
| **`account`** | iOS, visionOS | Account / username of keychain accounts. Maps to kSecAttrAccount on iOS. | _None_ |
| **`authenticationPrompt`** | All | What to prompt the user when unlocking the keychain with biometry or device password. | See [`authenticationPrompt` Properties](#authenticationprompt-properties) |
| **`authenticationType`** | iOS, visionOS | Policies specifying which forms of authentication are acceptable. | `Keychain.AUTHENTICATION_TYPE.DEVICE_PASSCODE_OR_BIOMETRICS` |
| **`service`** | All | Reverse domain name qualifier for the service associated with password. | _App bundle ID_ |
Expand Down
40 changes: 31 additions & 9 deletions RNKeychainManager/RNKeychainManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ CFStringRef accessibleValue(NSDictionary *options)
return kSecAttrAccessibleAfterFirstUnlock;
}

id accountValue(NSDictionary *options)
{
if (options && options[@"account"] != nil) {
return options[@"account"];
}
return nil;
}

NSString *serviceValue(NSDictionary *options)
{
if (options && options[@"service"] != nil) {
Expand Down Expand Up @@ -375,18 +383,32 @@ - (OSStatus)deleteCredentialsForServer:(NSString *)server
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSString *account = accountValue(options);
NSString *service = serviceValue(options);
NSString *authenticationPrompt = authenticationPromptValue(options);

NSDictionary *query = @{
(__bridge NSString *)kSecClass: (__bridge id)(kSecClassGenericPassword),
(__bridge NSString *)kSecAttrService: service,
(__bridge NSString *)kSecReturnAttributes: (__bridge id)kCFBooleanTrue,
(__bridge NSString *)kSecReturnData: (__bridge id)kCFBooleanTrue,
(__bridge NSString *)kSecMatchLimit: (__bridge NSString *)kSecMatchLimitOne,
(__bridge NSString *)kSecUseOperationPrompt: authenticationPrompt
};

NSDictionary *query;
if (account) {
query = @{
(__bridge NSString *)kSecClass: (__bridge id)(kSecClassGenericPassword),
(__bridge NSString *)kSecAttrAccount: account,
(__bridge NSString *)kSecAttrService: service,
(__bridge NSString *)kSecReturnAttributes: (__bridge id)kCFBooleanTrue,
(__bridge NSString *)kSecReturnData: (__bridge id)kCFBooleanTrue,
(__bridge NSString *)kSecMatchLimit: (__bridge NSString *)kSecMatchLimitOne,
(__bridge NSString *)kSecUseOperationPrompt: authenticationPrompt
};
} else {
query = @{
(__bridge NSString *)kSecClass: (__bridge id)(kSecClassGenericPassword),
(__bridge NSString *)kSecAttrService: service,
(__bridge NSString *)kSecReturnAttributes: (__bridge id)kCFBooleanTrue,
(__bridge NSString *)kSecReturnData: (__bridge id)kCFBooleanTrue,
(__bridge NSString *)kSecMatchLimit: (__bridge NSString *)kSecMatchLimitOne,
(__bridge NSString *)kSecUseOperationPrompt: authenticationPrompt
};
}

// Look up service in the keychain
NSDictionary *found = nil;
CFTypeRef foundTypeRef = NULL;
Expand Down
1 change: 1 addition & 0 deletions typings/react-native-keychain.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ declare module 'react-native-keychain' {
accessControl?: ACCESS_CONTROL;
accessGroup?: string;
accessible?: ACCESSIBLE;
account?: string;
authenticationPrompt?: string | AuthenticationPrompt;
authenticationType?: AUTHENTICATION_TYPE;
service?: string;
Expand Down
Loading