Add hasInternetCredentials (#150)

This checks if the username/password combination for server is available in the secure storage.
Resolves to `true` if an entry exists or `false` if it doesn't.
This commit is contained in:
Jürno Ader 2018-09-30 15:12:57 +03:00 committed by Joel Arvidsson
parent 1abc167b70
commit b2c07b9f77
5 changed files with 61 additions and 0 deletions

View File

@ -61,6 +61,10 @@ Will remove the username/password combination from the secure storage.
Will store the server/username/password combination in the secure storage.
### `hasInternetCredentials(server, [{ authenticationPrompt }])`
Will check if the username/password combination for server is available in the secure storage. Resolves to `true` if an entry exists or `false` if it doesn't.
### `getInternetCredentials(server, [{ authenticationPrompt }])`
Will retreive the server/username/password combination from the secure storage. Resolves to `{ username, password }` 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.

View File

@ -372,6 +372,35 @@ RCT_EXPORT_METHOD(setInternetCredentialsForServer:(NSString *)server withUsernam
[self insertKeychainEntry:attributes withOptions:options resolver:resolve rejecter:reject];
}
RCT_EXPORT_METHOD(hasInternetCredentialsForServer:(NSString *)server resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
NSMutableDictionary *queryParts = [[NSMutableDictionary alloc] init];
queryParts[(__bridge NSString *)kSecClass] = (__bridge id)(kSecClassInternetPassword);
queryParts[(__bridge NSString *)kSecAttrServer] = server;
queryParts[(__bridge NSString *)kSecMatchLimit] = (__bridge NSString *)kSecMatchLimitOne;
if (@available(iOS 9, *)) {
queryParts[(__bridge NSString *)kSecUseAuthenticationUI] = (__bridge NSString *)kSecUseAuthenticationUIFail;
}
NSDictionary *query = [queryParts copy];
// Look up server in the keychain
OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef) query, nil);
switch (osStatus) {
case noErr:
case errSecInteractionNotAllowed:
return resolve(@(YES));
case errSecItemNotFound:
return resolve(@(NO));
}
NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
return rejectWithError(reject, error);
}
RCT_EXPORT_METHOD(getInternetCredentialsForServer:(NSString *)server withOptions:(NSDictionary *)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
NSDictionary *query = @{

View File

@ -149,6 +149,19 @@ public class KeychainModule extends ReactContextBaseJavaModule {
}
}
public void hasInternetCredentialsForServer(@NonNull String server, Promise promise) {
final String defaultService = getDefaultServiceIfNull(server);
ResultSet resultSet = prefsStorage.getEncryptedEntry(defaultService);
if (resultSet == null) {
Log.e(KEYCHAIN_MODULE, "No entry found for service: " + defaultService);
promise.resolve(false);
return;
}
promise.resolve(true);
}
@ReactMethod
public void setInternetCredentialsForServer(@NonNull String server, String username, String password, ReadableMap unusedOptions, Promise promise) {
setGenericPasswordForOptions(server, username, password, promise);

View File

@ -108,6 +108,17 @@ export function setInternetCredentials(
);
}
/**
* Checks if we have a login combination for `server`.
* @param {string} server URL to server.
* @return {Promise} Resolves to `true` when successful
*/
export function hasInternetCredentials(
server: string,
): Promise {
return RNKeychainManager.hasInternetCredentialsForServer(server);
}
/**
* Fetches login combination for `server`.
* @param {string} server URL to server.

View File

@ -63,6 +63,10 @@ declare module 'react-native-keychain' {
server: string
): Promise<UserCredentials>;
function hasInternetCredentials(
server: string
): Promise<boolean>;
function resetInternetCredentials(
server: string
): Promise<void>;