authenticate method
Future<bool>
authenticate(
- String atsign,
- AtClientPreference atClientPreference, {
- OnboardingStatus? status,
- String? jsonData,
- String? decryptKey,
Returns true
on successfully authenticating atsign
with cramSecret
/privateKey
.
if pkam is successful, encryption keys will be set for the user.
Implementation
Future<bool> authenticate(
String atsign, AtClientPreference atClientPreference,
{OnboardingStatus? status, String? jsonData, String? decryptKey}) async {
/**ToDo Use OnboardingStatus enum instead of using
atClientPreferences.cramSecret == null to know if atSign is new or existing
If status == OnboardingStatus.ACTIVATE, then atSign is new, so perform initial auth and
generate RSA key-pair
If status == OnboardingStatus.RESTORE then use use atKeys file to login into existing atSign
*/
/**
* The authentication is performed either by CRAM authentication or PKAM authentication
* 1. If AtClientPreference.cramSecret is populated, then atSign is considered as new atSign.
* So, perform CRAM auth and if successful, generate PKAM key-pair and encryption key-pair
* and store them into key-chain manager and return true, else false.
* 2. If AtClientPreference.privateKey is populated, then atSign is considered as existing atSign.
* So, first verify if .atKeys file provided have valid key-pair. Perform PKAM auth to validate the
* key-pair. If successful, store the keys into key-chain manager and return true, else false.
**/
// _formatAtSign method checks if atSign is prefixed with '@',
// If '@' is not prefixed, prefixes '@' and returns @sign.
// If atSign is null or empty, returns empty string.
atsign = _formatAtSign(atsign);
// atSign is mandatory to authenticate. So, if atSign is empty return
// false to indicate authentication is not successful
if (atsign.isEmpty) {
_logger.severe('Authentication failed. Null or empty atSign found.');
return false;
}
AtChops? atChops;
if (atClientPreference.cramSecret.isNull) {
// If JSON data (encrypted keys from .atKeys file) or decrypt key is null or empty,
// cannot process authentication. Hence return false.
//
// "isNull" is an extension on String class that checks if String is null or empty.
if ((jsonData.isNull) || (decryptKey.isNull)) {
_logger.severe(
'Authentication failed. Encrypted keys from atKeys file not found for the atSign $atsign.');
return false;
}
var decryptedAtKeysMap = _decodeAndDecryptKeys(jsonData!, decryptKey!);
atChops = createAtChops(decryptedAtKeysMap);
// Inside "_validateAtKeys", performs PKAM auth using atChops.
// If PKAM auth fails, UnAuthenticatedException is returned which is handled in the caller method.
var isValidAtKeysFile = await _validateAtKeys(atChops, atsign,
atClientPreference.rootDomain, atClientPreference.rootPort);
if (!isValidAtKeysFile) {
_logger.severe(
'Authentication failed. Invalid atKeys file found for the atSign $atsign.');
return false;
}
//If atKeys are valid, store keys to keychain manager
await _storeToKeyChainManager(atsign, decryptedAtKeysMap);
}
// Perform the initial auth using CRAM Secret and then
// Generate the PKAM and encryption key-pair and create the atChops instance.
else {
atClientAuthenticator ??= AtClientAuthenticator();
var isAuthenticated = await atClientAuthenticator!
.performInitialAuth(atsign, atClientPreference);
// If authentication is failed, return false.
if (!isAuthenticated) {
return isAuthenticated;
}
// The "getKeysFromKeyChainManager" fetches PKAM key-pair and encryption key-pair
// from the keychain. throws exception if any of the key is null or empty.
// The createAtChops method takes PKAM and encryption key-pair map and returns
// atChops instance with fields initialized.
atChops = createAtChops(await getKeysFromKeyChainManager(atsign));
}
await _init(atsign, atClientPreference, atChops);
await _sync();
// persist keys to the local-keystore
await persistKeys(atsign);
return true;
}